fix: User should not be shown ID Verification prompt on progress page if disabled (#29662)
Co-authored-by: Simon Chen <schen@edx-c02fw0guml85.lan>
This commit is contained in:
@@ -8,11 +8,13 @@ import itertools
|
|||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from uuid import uuid4
|
|
||||||
|
|
||||||
from unittest.mock import MagicMock, PropertyMock, call, create_autospec, patch
|
from unittest.mock import MagicMock, PropertyMock, call, create_autospec, patch
|
||||||
from urllib.parse import quote, urlencode
|
from urllib.parse import quote, urlencode
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
|
from capa.tests.response_xml_factory import \
|
||||||
|
MultipleChoiceResponseXMLFactory
|
||||||
from completion.test_utils import CompletionWaffleTestMixin
|
from completion.test_utils import CompletionWaffleTestMixin
|
||||||
from crum import set_current_request
|
from crum import set_current_request
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -24,6 +26,7 @@ from django.test.client import Client
|
|||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from edx_toggles.toggles.testutils import override_waffle_flag, override_waffle_switch
|
from edx_toggles.toggles.testutils import override_waffle_flag, override_waffle_switch
|
||||||
|
from freezegun import freeze_time
|
||||||
from markupsafe import escape
|
from markupsafe import escape
|
||||||
from milestones.tests.utils import MilestonesTestCaseMixin
|
from milestones.tests.utils import MilestonesTestCaseMixin
|
||||||
from opaque_keys.edx.keys import CourseKey, UsageKey
|
from opaque_keys.edx.keys import CourseKey, UsageKey
|
||||||
@@ -31,17 +34,47 @@ from pytz import UTC, utc
|
|||||||
from web_fragments.fragment import Fragment
|
from web_fragments.fragment import Fragment
|
||||||
from xblock.core import XBlock
|
from xblock.core import XBlock
|
||||||
from xblock.fields import Scope, String
|
from xblock.fields import Scope, String
|
||||||
|
from xmodule.course_module import (
|
||||||
|
COURSE_VISIBILITY_PRIVATE,
|
||||||
|
COURSE_VISIBILITY_PUBLIC,
|
||||||
|
COURSE_VISIBILITY_PUBLIC_OUTLINE
|
||||||
|
)
|
||||||
|
from xmodule.data import CertificatesDisplayBehaviors
|
||||||
|
from xmodule.graders import ShowCorrectness
|
||||||
|
from xmodule.modulestore import ModuleStoreEnum
|
||||||
|
from xmodule.modulestore.django import modulestore
|
||||||
|
from xmodule.modulestore.tests.django_utils import (
|
||||||
|
TEST_DATA_SPLIT_MODULESTORE,
|
||||||
|
CourseUserType,
|
||||||
|
ModuleStoreTestCase,
|
||||||
|
SharedModuleStoreTestCase
|
||||||
|
)
|
||||||
|
from xmodule.modulestore.tests.factories import (
|
||||||
|
CourseFactory,
|
||||||
|
ItemFactory,
|
||||||
|
check_mongo_calls
|
||||||
|
)
|
||||||
|
|
||||||
import lms.djangoapps.courseware.views.views as views
|
import lms.djangoapps.courseware.views.views as views
|
||||||
from capa.tests.response_xml_factory import MultipleChoiceResponseXMLFactory # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from common.djangoapps.course_modes.models import CourseMode
|
from common.djangoapps.course_modes.models import CourseMode
|
||||||
from common.djangoapps.course_modes.tests.factories import CourseModeFactory
|
from common.djangoapps.course_modes.tests.factories import CourseModeFactory
|
||||||
from freezegun import freeze_time # lint-amnesty, pylint: disable=wrong-import-order
|
from common.djangoapps.student.models import CourseEnrollment
|
||||||
from common.djangoapps.student.tests.factories import GlobalStaffFactory
|
from common.djangoapps.student.roles import CourseStaffRole
|
||||||
from common.djangoapps.student.tests.factories import RequestFactoryNoCsrf
|
from common.djangoapps.student.tests.factories import (
|
||||||
|
TEST_PASSWORD,
|
||||||
|
AdminFactory,
|
||||||
|
CourseEnrollmentFactory,
|
||||||
|
GlobalStaffFactory,
|
||||||
|
RequestFactoryNoCsrf,
|
||||||
|
UserFactory
|
||||||
|
)
|
||||||
|
from common.djangoapps.util.tests.test_date_utils import fake_pgettext, fake_ugettext
|
||||||
|
from common.djangoapps.util.url import reload_django_url_config
|
||||||
|
from common.djangoapps.util.views import ensure_valid_course_key
|
||||||
from lms.djangoapps.certificates import api as certs_api
|
from lms.djangoapps.certificates import api as certs_api
|
||||||
from lms.djangoapps.certificates.models import (
|
from lms.djangoapps.certificates.models import (
|
||||||
CertificateGenerationConfiguration,
|
CertificateGenerationConfiguration,
|
||||||
|
CertificateGenerationCourseSetting,
|
||||||
CertificateStatuses
|
CertificateStatuses
|
||||||
)
|
)
|
||||||
from lms.djangoapps.certificates.tests.factories import (
|
from lms.djangoapps.certificates.tests.factories import (
|
||||||
@@ -63,7 +96,7 @@ from lms.djangoapps.courseware.toggles import (
|
|||||||
COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW,
|
COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW,
|
||||||
COURSEWARE_OPTIMIZED_RENDER_XBLOCK,
|
COURSEWARE_OPTIMIZED_RENDER_XBLOCK,
|
||||||
COURSEWARE_USE_LEGACY_FRONTEND,
|
COURSEWARE_USE_LEGACY_FRONTEND,
|
||||||
courseware_mfe_is_advertised,
|
courseware_mfe_is_advertised
|
||||||
)
|
)
|
||||||
from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient
|
from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient
|
||||||
from lms.djangoapps.grades.config.waffle import ASSUME_ZERO_GRADE_IF_ABSENT
|
from lms.djangoapps.grades.config.waffle import ASSUME_ZERO_GRADE_IF_ABSENT
|
||||||
@@ -71,6 +104,7 @@ from lms.djangoapps.grades.config.waffle import waffle_switch as grades_waffle_s
|
|||||||
from lms.djangoapps.instructor.access import allow_access
|
from lms.djangoapps.instructor.access import allow_access
|
||||||
from lms.djangoapps.verify_student.models import VerificationDeadline
|
from lms.djangoapps.verify_student.models import VerificationDeadline
|
||||||
from lms.djangoapps.verify_student.services import IDVerificationService
|
from lms.djangoapps.verify_student.services import IDVerificationService
|
||||||
|
from openedx.core.djangoapps.agreements.toggles import ENABLE_INTEGRITY_SIGNATURE
|
||||||
from openedx.core.djangoapps.catalog.tests.factories import CourseFactory as CatalogCourseFactory
|
from openedx.core.djangoapps.catalog.tests.factories import CourseFactory as CatalogCourseFactory
|
||||||
from openedx.core.djangoapps.catalog.tests.factories import CourseRunFactory, ProgramFactory
|
from openedx.core.djangoapps.catalog.tests.factories import CourseRunFactory, ProgramFactory
|
||||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||||
@@ -91,30 +125,12 @@ from openedx.features.course_experience import (
|
|||||||
)
|
)
|
||||||
from openedx.features.course_experience.tests.views.helpers import add_course_mode
|
from openedx.features.course_experience.tests.views.helpers import add_course_mode
|
||||||
from openedx.features.course_experience.url_helpers import (
|
from openedx.features.course_experience.url_helpers import (
|
||||||
|
ExperienceOption,
|
||||||
get_courseware_url,
|
get_courseware_url,
|
||||||
get_learning_mfe_home_url,
|
get_learning_mfe_home_url,
|
||||||
make_learning_mfe_courseware_url,
|
make_learning_mfe_courseware_url
|
||||||
ExperienceOption,
|
|
||||||
)
|
)
|
||||||
from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired
|
from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired
|
||||||
from common.djangoapps.student.models import CourseEnrollment
|
|
||||||
from common.djangoapps.student.roles import CourseStaffRole
|
|
||||||
from common.djangoapps.student.tests.factories import TEST_PASSWORD, AdminFactory, CourseEnrollmentFactory, UserFactory
|
|
||||||
from common.djangoapps.util.tests.test_date_utils import fake_pgettext, fake_ugettext
|
|
||||||
from common.djangoapps.util.url import reload_django_url_config
|
|
||||||
from common.djangoapps.util.views import ensure_valid_course_key
|
|
||||||
from xmodule.course_module import COURSE_VISIBILITY_PRIVATE, COURSE_VISIBILITY_PUBLIC, COURSE_VISIBILITY_PUBLIC_OUTLINE # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from xmodule.data import CertificatesDisplayBehaviors # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from xmodule.graders import ShowCorrectness # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from xmodule.modulestore import ModuleStoreEnum # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from xmodule.modulestore.tests.django_utils import ( # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
TEST_DATA_SPLIT_MODULESTORE,
|
|
||||||
CourseUserType,
|
|
||||||
ModuleStoreTestCase,
|
|
||||||
SharedModuleStoreTestCase
|
|
||||||
)
|
|
||||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
|
|
||||||
QUERY_COUNT_TABLE_BLACKLIST = WAFFLE_TABLES
|
QUERY_COUNT_TABLE_BLACKLIST = WAFFLE_TABLES
|
||||||
|
|
||||||
@@ -1928,6 +1944,30 @@ class ProgressPageTests(ProgressPageBaseTests):
|
|||||||
assert response.cert_status == 'earned_but_not_available'
|
assert response.cert_status == 'earned_but_not_available'
|
||||||
assert response.title == 'Your certificate will be available soon!'
|
assert response.title == 'Your certificate will be available soon!'
|
||||||
|
|
||||||
|
@ddt.data(True, False)
|
||||||
|
def test_no_certs_generated_and_not_verified(self, waffle_override):
|
||||||
|
"""
|
||||||
|
Verify if the learner is not ID Verified, and the certs are not yet generated,
|
||||||
|
but the learner is eligible, the get_cert_data would return cert status Unverified
|
||||||
|
"""
|
||||||
|
CertificateGenerationConfiguration(enabled=True).save()
|
||||||
|
CertificateGenerationCourseSetting(
|
||||||
|
course_key=self.course.id, self_generation_enabled=True
|
||||||
|
).save()
|
||||||
|
with override_waffle_flag(ENABLE_INTEGRITY_SIGNATURE, active=waffle_override):
|
||||||
|
with patch(
|
||||||
|
'lms.djangoapps.certificates.api.certificate_downloadable_status',
|
||||||
|
return_value=self.mock_certificate_downloadable_status()
|
||||||
|
):
|
||||||
|
response = views.get_cert_data(self.user, self.course, CourseMode.VERIFIED, MagicMock(passed=True))
|
||||||
|
|
||||||
|
if waffle_override:
|
||||||
|
assert response.cert_status == 'requesting'
|
||||||
|
assert response.title == 'Congratulations, you qualified for a certificate!'
|
||||||
|
else:
|
||||||
|
assert response.cert_status == 'unverified'
|
||||||
|
assert response.title == 'Certificate unavailable'
|
||||||
|
|
||||||
def assert_invalidate_certificate(self, certificate):
|
def assert_invalidate_certificate(self, certificate):
|
||||||
""" Dry method to mark certificate as invalid. And assert the response. """
|
""" Dry method to mark certificate as invalid. And assert the response. """
|
||||||
CertificateInvalidationFactory.create(
|
CertificateInvalidationFactory.create(
|
||||||
@@ -3477,47 +3517,40 @@ class DatesTabTestCase(ModuleStoreTestCase):
|
|||||||
vertical = ItemFactory.create(category='vertical', parent_location=subsection.location)
|
vertical = ItemFactory.create(category='vertical', parent_location=subsection.location)
|
||||||
ItemFactory.create(category='problem', parent_location=vertical.location, has_score=True)
|
ItemFactory.create(category='problem', parent_location=vertical.location, has_score=True)
|
||||||
|
|
||||||
with patch('lms.djangoapps.courseware.views.views.get_enrollment') as mock_get_enrollment:
|
response = self._get_response(self.course)
|
||||||
mock_get_enrollment.return_value = {
|
self.assertContains(response, subsection.display_name)
|
||||||
'mode': enrollment.mode
|
# Show the Verification Deadline for verified only
|
||||||
}
|
self.assertContains(response, 'Verification Deadline')
|
||||||
response = self._get_response(self.course)
|
# Make sure pill exists for today's date
|
||||||
self.assertContains(response, subsection.display_name)
|
self.assertContains(response, '<div class="pill today">')
|
||||||
# Show the Verification Deadline for verified only
|
# Make sure pill exists for next due assignment
|
||||||
self.assertContains(response, 'Verification Deadline')
|
self.assertContains(response, '<div class="pill due-next">')
|
||||||
# Make sure pill exists for today's date
|
# No pills for verified enrollments
|
||||||
self.assertContains(response, '<div class="pill today">')
|
self.assertNotContains(response, '<div class="pill verified">')
|
||||||
# Make sure pill exists for next due assignment
|
# Make sure the assignment type is rendered
|
||||||
self.assertContains(response, '<div class="pill due-next">')
|
self.assertContains(response, 'Homework:')
|
||||||
# No pills for verified enrollments
|
|
||||||
self.assertNotContains(response, '<div class="pill verified">')
|
|
||||||
# Make sure the assignment type is rendered
|
|
||||||
self.assertContains(response, 'Homework:')
|
|
||||||
|
|
||||||
enrollment.delete()
|
enrollment.delete()
|
||||||
enrollment = CourseEnrollmentFactory(course_id=self.course.id, user=self.user, mode=CourseMode.AUDIT)
|
enrollment = CourseEnrollmentFactory(course_id=self.course.id, user=self.user, mode=CourseMode.AUDIT)
|
||||||
mock_get_enrollment.return_value = {
|
|
||||||
'mode': enrollment.mode
|
|
||||||
}
|
|
||||||
|
|
||||||
expected_calls = [
|
expected_calls = [
|
||||||
call('course_id', str(self.course.id)),
|
call('course_id', str(self.course.id)),
|
||||||
call('user_id', self.user.id),
|
call('user_id', self.user.id),
|
||||||
call('is_staff', self.user.is_staff),
|
call('is_staff', self.user.is_staff),
|
||||||
]
|
]
|
||||||
|
|
||||||
response = self._get_response(self.course)
|
response = self._get_response(self.course)
|
||||||
|
|
||||||
mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=True)
|
mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=True)
|
||||||
self.assertContains(response, subsection.display_name)
|
self.assertContains(response, subsection.display_name)
|
||||||
# Don't show the Verification Deadline for audit
|
# Don't show the Verification Deadline for audit
|
||||||
self.assertNotContains(response, 'Verification Deadline')
|
self.assertNotContains(response, 'Verification Deadline')
|
||||||
# Pill doesn't exist for assignment due tomorrow
|
# Pill doesn't exist for assignment due tomorrow
|
||||||
self.assertNotContains(response, '<div class="pill due-next">')
|
self.assertNotContains(response, '<div class="pill due-next">')
|
||||||
# Should have verified pills for audit enrollments
|
# Should have verified pills for audit enrollments
|
||||||
self.assertContains(response, '<div class="pill verified">')
|
self.assertContains(response, '<div class="pill verified">')
|
||||||
# Make sure the assignment type is rendered
|
# Make sure the assignment type is rendered
|
||||||
self.assertContains(response, 'Homework:')
|
self.assertContains(response, 'Homework:')
|
||||||
|
|
||||||
@override_waffle_flag(RELATIVE_DATES_FLAG, active=True)
|
@override_waffle_flag(RELATIVE_DATES_FLAG, active=True)
|
||||||
def test_reset_deadlines_banner_displays(self):
|
def test_reset_deadlines_banner_displays(self):
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ Courseware views functions
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import urllib
|
||||||
from collections import OrderedDict, namedtuple
|
from collections import OrderedDict, namedtuple
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
import urllib
|
|
||||||
import bleach
|
import bleach
|
||||||
import requests
|
import requests
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -22,7 +23,6 @@ from django.shortcuts import redirect
|
|||||||
from django.template.context_processors import csrf
|
from django.template.context_processors import csrf
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from urllib.parse import quote_plus # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from django.utils.translation import gettext
|
from django.utils.translation import gettext
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@@ -45,21 +45,32 @@ from rest_framework.decorators import api_view, throttle_classes
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.throttling import UserRateThrottle
|
from rest_framework.throttling import UserRateThrottle
|
||||||
from web_fragments.fragment import Fragment
|
from web_fragments.fragment import Fragment
|
||||||
|
from xmodule.course_module import (
|
||||||
|
COURSE_VISIBILITY_PUBLIC,
|
||||||
|
COURSE_VISIBILITY_PUBLIC_OUTLINE
|
||||||
|
)
|
||||||
|
from xmodule.modulestore.django import modulestore
|
||||||
|
from xmodule.modulestore.exceptions import (
|
||||||
|
ItemNotFoundError,
|
||||||
|
NoPathToItem
|
||||||
|
)
|
||||||
|
from xmodule.tabs import CourseTabList
|
||||||
|
from xmodule.x_module import STUDENT_VIEW
|
||||||
|
|
||||||
from lms.djangoapps.survey import views as survey_views
|
|
||||||
from common.djangoapps.course_modes.models import CourseMode, get_course_prices
|
from common.djangoapps.course_modes.models import CourseMode, get_course_prices
|
||||||
from common.djangoapps.edxmako.shortcuts import marketing_link, render_to_response, render_to_string
|
from common.djangoapps.edxmako.shortcuts import marketing_link, render_to_response, render_to_string
|
||||||
from lms.djangoapps.edxnotes.helpers import is_feature_enabled
|
from common.djangoapps.student.models import CourseEnrollment, UserTestGroup
|
||||||
|
from common.djangoapps.util.cache import cache, cache_if_anonymous
|
||||||
|
from common.djangoapps.util.course import course_location_from_key
|
||||||
|
from common.djangoapps.util.db import outer_atomic
|
||||||
|
from common.djangoapps.util.milestones_helpers import get_prerequisite_courses_display
|
||||||
|
from common.djangoapps.util.views import ensure_valid_course_key, ensure_valid_usage_key
|
||||||
from lms.djangoapps.ccx.custom_exception import CCXLocatorValidationException
|
from lms.djangoapps.ccx.custom_exception import CCXLocatorValidationException
|
||||||
from lms.djangoapps.certificates import api as certs_api
|
from lms.djangoapps.certificates import api as certs_api
|
||||||
from lms.djangoapps.certificates.data import CertificateStatuses
|
from lms.djangoapps.certificates.data import CertificateStatuses
|
||||||
from lms.djangoapps.commerce.utils import EcommerceService
|
from lms.djangoapps.commerce.utils import EcommerceService
|
||||||
from lms.djangoapps.course_goals.models import UserActivity
|
from lms.djangoapps.course_goals.models import UserActivity
|
||||||
from lms.djangoapps.course_home_api.toggles import (
|
from lms.djangoapps.course_home_api.toggles import course_home_legacy_is_active, course_home_mfe_progress_tab_is_active
|
||||||
course_home_legacy_is_active,
|
|
||||||
course_home_mfe_progress_tab_is_active
|
|
||||||
)
|
|
||||||
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url, is_request_from_learning_mfe
|
|
||||||
from lms.djangoapps.courseware.access import has_access, has_ccx_coach_role
|
from lms.djangoapps.courseware.access import has_access, has_ccx_coach_role
|
||||||
from lms.djangoapps.courseware.access_utils import check_course_open_for_learner, check_public_access
|
from lms.djangoapps.courseware.access_utils import check_course_open_for_learner, check_public_access
|
||||||
from lms.djangoapps.courseware.courses import (
|
from lms.djangoapps.courseware.courses import (
|
||||||
@@ -78,23 +89,24 @@ from lms.djangoapps.courseware.courses import (
|
|||||||
)
|
)
|
||||||
from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link
|
from lms.djangoapps.courseware.date_summary import verified_upgrade_deadline_link
|
||||||
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect, Redirect
|
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect, Redirect
|
||||||
from lms.djangoapps.courseware.masquerade import setup_masquerade, is_masquerading_as_specific_student
|
from lms.djangoapps.courseware.masquerade import is_masquerading_as_specific_student, setup_masquerade
|
||||||
from lms.djangoapps.courseware.model_data import FieldDataCache
|
from lms.djangoapps.courseware.model_data import FieldDataCache
|
||||||
from lms.djangoapps.courseware.models import BaseStudentModuleHistory, StudentModule
|
from lms.djangoapps.courseware.models import BaseStudentModuleHistory, StudentModule
|
||||||
from lms.djangoapps.courseware.permissions import ( # lint-amnesty, pylint: disable=unused-import
|
from lms.djangoapps.courseware.permissions import (
|
||||||
MASQUERADE_AS_STUDENT,
|
MASQUERADE_AS_STUDENT,
|
||||||
VIEW_COURSE_HOME,
|
VIEW_COURSE_HOME,
|
||||||
VIEW_COURSEWARE,
|
VIEW_COURSEWARE,
|
||||||
VIEW_XQA_INTERFACE
|
|
||||||
)
|
)
|
||||||
|
|
||||||
from lms.djangoapps.courseware.toggles import is_courses_default_invite_only_enabled
|
from lms.djangoapps.courseware.toggles import is_courses_default_invite_only_enabled
|
||||||
from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient
|
from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient
|
||||||
|
from lms.djangoapps.edxnotes.helpers import is_feature_enabled
|
||||||
from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context
|
from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context
|
||||||
from lms.djangoapps.grades.api import CourseGradeFactory
|
from lms.djangoapps.grades.api import CourseGradeFactory
|
||||||
from lms.djangoapps.instructor.enrollment import uses_shib
|
from lms.djangoapps.instructor.enrollment import uses_shib
|
||||||
from lms.djangoapps.instructor.views.api import require_global_staff
|
from lms.djangoapps.instructor.views.api import require_global_staff
|
||||||
|
from lms.djangoapps.survey import views as survey_views
|
||||||
from lms.djangoapps.verify_student.services import IDVerificationService
|
from lms.djangoapps.verify_student.services import IDVerificationService
|
||||||
|
from openedx.core.djangoapps.agreements.toggles import is_integrity_signature_enabled
|
||||||
from openedx.core.djangoapps.catalog.utils import get_programs, get_programs_with_type
|
from openedx.core.djangoapps.catalog.utils import get_programs, get_programs_with_type
|
||||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||||
from openedx.core.djangoapps.credit.api import (
|
from openedx.core.djangoapps.credit.api import (
|
||||||
@@ -102,7 +114,7 @@ from openedx.core.djangoapps.credit.api import (
|
|||||||
is_credit_course,
|
is_credit_course,
|
||||||
is_user_eligible_for_credit
|
is_user_eligible_for_credit
|
||||||
)
|
)
|
||||||
from openedx.core.djangoapps.enrollments.api import add_enrollment, get_enrollment # lint-amnesty, pylint: disable=unused-import
|
from openedx.core.djangoapps.enrollments.api import add_enrollment
|
||||||
from openedx.core.djangoapps.enrollments.permissions import ENROLL_IN_COURSE
|
from openedx.core.djangoapps.enrollments.permissions import ENROLL_IN_COURSE
|
||||||
from openedx.core.djangoapps.models.course_details import CourseDetails
|
from openedx.core.djangoapps.models.course_details import CourseDetails
|
||||||
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
|
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
|
||||||
@@ -117,23 +129,17 @@ from openedx.features.content_type_gating.models import ContentTypeGatingConfig
|
|||||||
from openedx.features.course_duration_limits.access import generate_course_expired_fragment
|
from openedx.features.course_duration_limits.access import generate_course_expired_fragment
|
||||||
from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG, course_home_url_name
|
from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG, course_home_url_name
|
||||||
from openedx.features.course_experience.course_tools import CourseToolsPluginManager
|
from openedx.features.course_experience.course_tools import CourseToolsPluginManager
|
||||||
from openedx.features.course_experience.url_helpers import get_courseware_url, ExperienceOption
|
from openedx.features.course_experience.url_helpers import (
|
||||||
|
ExperienceOption,
|
||||||
|
get_courseware_url,
|
||||||
|
get_learning_mfe_home_url,
|
||||||
|
is_request_from_learning_mfe
|
||||||
|
)
|
||||||
from openedx.features.course_experience.utils import dates_banner_should_display
|
from openedx.features.course_experience.utils import dates_banner_should_display
|
||||||
from openedx.features.course_experience.views.course_dates import CourseDatesFragmentView
|
from openedx.features.course_experience.views.course_dates import CourseDatesFragmentView
|
||||||
from openedx.features.course_experience.waffle import ENABLE_COURSE_ABOUT_SIDEBAR_HTML
|
from openedx.features.course_experience.waffle import ENABLE_COURSE_ABOUT_SIDEBAR_HTML
|
||||||
from openedx.features.course_experience.waffle import waffle as course_experience_waffle
|
from openedx.features.course_experience.waffle import waffle as course_experience_waffle
|
||||||
from openedx.features.enterprise_support.api import data_sharing_consent_required
|
from openedx.features.enterprise_support.api import data_sharing_consent_required
|
||||||
from common.djangoapps.student.models import CourseEnrollment, UserTestGroup
|
|
||||||
from common.djangoapps.util.cache import cache, cache_if_anonymous
|
|
||||||
from common.djangoapps.util.course import course_location_from_key
|
|
||||||
from common.djangoapps.util.db import outer_atomic
|
|
||||||
from common.djangoapps.util.milestones_helpers import get_prerequisite_courses_display
|
|
||||||
from common.djangoapps.util.views import ensure_valid_course_key, ensure_valid_usage_key
|
|
||||||
from xmodule.course_module import COURSE_VISIBILITY_PUBLIC, COURSE_VISIBILITY_PUBLIC_OUTLINE # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from xmodule.modulestore.exceptions import ItemNotFoundError, NoPathToItem # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from xmodule.tabs import CourseTabList # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
from xmodule.x_module import STUDENT_VIEW # lint-amnesty, pylint: disable=wrong-import-order
|
|
||||||
|
|
||||||
from ..context_processor import user_timezone_locale_prefs
|
from ..context_processor import user_timezone_locale_prefs
|
||||||
from ..entrance_exams import user_can_skip_entrance_exam
|
from ..entrance_exams import user_can_skip_entrance_exam
|
||||||
@@ -1248,8 +1254,8 @@ def _downloadable_certificate_message(course, cert_downloadable_status): # lint
|
|||||||
return _downloadable_cert_data(download_url=cert_downloadable_status['download_url'])
|
return _downloadable_cert_data(download_url=cert_downloadable_status['download_url'])
|
||||||
|
|
||||||
|
|
||||||
def _missing_required_verification(student, enrollment_mode):
|
def _missing_required_verification(student, enrollment_mode, course_key):
|
||||||
return (
|
return not is_integrity_signature_enabled(course_key) and (
|
||||||
enrollment_mode in CourseMode.VERIFIED_MODES and not IDVerificationService.user_is_verified(student)
|
enrollment_mode in CourseMode.VERIFIED_MODES and not IDVerificationService.user_is_verified(student)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1272,7 +1278,7 @@ def _certificate_message(student, course, enrollment_mode): # lint-amnesty, pyl
|
|||||||
if cert_downloadable_status['is_downloadable']:
|
if cert_downloadable_status['is_downloadable']:
|
||||||
return _downloadable_certificate_message(course, cert_downloadable_status)
|
return _downloadable_certificate_message(course, cert_downloadable_status)
|
||||||
|
|
||||||
if _missing_required_verification(student, enrollment_mode):
|
if _missing_required_verification(student, enrollment_mode, course.id):
|
||||||
return UNVERIFIED_CERT_DATA
|
return UNVERIFIED_CERT_DATA
|
||||||
|
|
||||||
return REQUESTING_CERT_DATA
|
return REQUESTING_CERT_DATA
|
||||||
|
|||||||
Reference in New Issue
Block a user