MST-108 Add masquerading fix to the upgrade message display

This commit is contained in:
Simon Chen
2020-04-29 09:18:17 -04:00
parent f47fc73f98
commit 34d4d162f7
6 changed files with 166 additions and 8 deletions

View File

@@ -273,7 +273,7 @@ class IndexQueryTestCase(ModuleStoreTestCase):
NUM_PROBLEMS = 20
@ddt.data(
(ModuleStoreEnum.Type.mongo, 10, 170),
(ModuleStoreEnum.Type.mongo, 11, 170),
(ModuleStoreEnum.Type.split, 4, 168),
)
@ddt.unpack

View File

@@ -155,9 +155,9 @@ class RenderXBlockTestMixin(six.with_metaclass(ABCMeta, object)):
return response
@ddt.data(
('vertical_block', ModuleStoreEnum.Type.mongo, 13),
('vertical_block', ModuleStoreEnum.Type.mongo, 14),
('vertical_block', ModuleStoreEnum.Type.split, 6),
('html_block', ModuleStoreEnum.Type.mongo, 14),
('html_block', ModuleStoreEnum.Type.mongo, 15),
('html_block', ModuleStoreEnum.Type.split, 6),
)
@ddt.unpack

View File

@@ -0,0 +1,127 @@
"""
Tests for masquerading functionality on course_experience
"""
import json
import six
from django.urls import reverse
from lms.djangoapps.commerce.models import CommerceConfiguration
from openedx.core.djangoapps.waffle_utils.testutils import override_waffle_flag
from openedx.features.course_experience import DISPLAY_COURSE_SOCK_FLAG, SHOW_UPGRADE_MSG_ON_COURSE_HOME
from student.roles import CourseStaffRole
from student.tests.factories import CourseEnrollmentFactory, UserFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID
from xmodule.partitions.partitions_service import PartitionService
from .helpers import add_course_mode
from .test_course_home import TEST_UPDATE_MESSAGE, course_home_url
from .test_course_sock import TEST_VERIFICATION_SOCK_LOCATOR
TEST_PASSWORD = 'test'
UPGRADE_MESSAGE_CONTAINER = 'section-upgrade'
class MasqueradeTestBase(SharedModuleStoreTestCase):
"""
Base test class for masquerading functionality on course_experience
"""
@classmethod
def setUpClass(cls):
super(MasqueradeTestBase, cls).setUpClass()
# Create two courses
cls.verified_course = CourseFactory.create()
cls.masters_course = CourseFactory.create()
# Create a verifiable course mode with an upgrade deadline in each course
add_course_mode(cls.verified_course, upgrade_deadline_expired=False)
add_course_mode(cls.masters_course, upgrade_deadline_expired=False)
add_course_mode(cls.masters_course, mode_slug='masters', mode_display_name='Masters')
def setUp(self):
super(MasqueradeTestBase, self).setUp()
self.course_staff = UserFactory.create()
CourseStaffRole(self.verified_course.id).add_users(self.course_staff)
CourseStaffRole(self.masters_course.id).add_users(self.course_staff)
# Enroll the user in the two courses
CourseEnrollmentFactory.create(user=self.course_staff, course_id=self.verified_course.id)
CourseEnrollmentFactory.create(user=self.course_staff, course_id=self.masters_course.id)
# Log the staff user in
self.client.login(username=self.course_staff.username, password=TEST_PASSWORD)
def get_group_id_by_course_mode_name(self, course_id, mode_name):
"""
Get the needed group_id from the Enrollment_Track partition for the specific masquerading track.
"""
partition_service = PartitionService(course_id)
enrollment_track_user_partition = partition_service.get_user_partition(ENROLLMENT_TRACK_PARTITION_ID)
for group in enrollment_track_user_partition.groups:
if group.name == mode_name:
return group.id
return None
def update_masquerade(self, role, course, username=None, group_id=None):
"""
Toggle masquerade state.
"""
masquerade_url = reverse(
'masquerade_update',
kwargs={
'course_key_string': six.text_type(course.id),
}
)
response = self.client.post(
masquerade_url,
json.dumps({
"role": role,
"group_id": group_id,
"user_name": username,
"user_partition_id": ENROLLMENT_TRACK_PARTITION_ID
}),
"application/json"
)
self.assertEqual(response.status_code, 200)
return response
class TestVerifiedUpgradesWithMasquerade(MasqueradeTestBase):
"""
Tests for the course verification upgrade messages while the user is being masqueraded.
"""
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
@override_waffle_flag(SHOW_UPGRADE_MSG_ON_COURSE_HOME, active=True)
def test_masquerade_as_student(self):
# Elevate the staff user to be student
self.update_masquerade(role='student', course=self.verified_course)
response = self.client.get(course_home_url(self.verified_course))
self.assertContains(response, TEST_VERIFICATION_SOCK_LOCATOR, html=False)
self.assertContains(response, UPGRADE_MESSAGE_CONTAINER, html=False)
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
def test_masquerade_as_verified_student(self):
user_group_id = self.get_group_id_by_course_mode_name(
self.verified_course.id,
'Verified Certificate'
)
self.update_masquerade(role='student', course=self.verified_course, group_id=user_group_id)
response = self.client.get(course_home_url(self.verified_course))
self.assertNotContains(response, TEST_VERIFICATION_SOCK_LOCATOR, html=False)
self.assertNotContains(response, UPGRADE_MESSAGE_CONTAINER, html=False)
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
def test_masquerade_as_masters_student(self):
user_group_id = self.get_group_id_by_course_mode_name(
self.masters_course.id,
'Masters'
)
self.update_masquerade(role='student', course=self.masters_course, group_id=user_group_id)
response = self.client.get(course_home_url(self.masters_course))
self.assertNotContains(response, TEST_VERIFICATION_SOCK_LOCATOR, html=False)
self.assertNotContains(response, UPGRADE_MESSAGE_CONTAINER, html=False)

View File

@@ -7,6 +7,7 @@ import logging
from datetime import timedelta
from completion.models import BlockCompletion
from django.conf import settings
from django.utils import timezone
from opaque_keys.edx.keys import CourseKey
from six.moves import range
@@ -15,10 +16,13 @@ from course_modes.models import CourseMode
from lms.djangoapps.course_api.blocks.api import get_blocks
from lms.djangoapps.course_blocks.utils import get_student_module_as_dict
from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.courseware.utils import verified_upgrade_link_is_valid
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.core.lib.cache_utils import request_cached
from student.models import CourseEnrollment
from xmodule.modulestore.django import modulestore
from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID
from xmodule.partitions.partitions_service import PartitionService
log = logging.getLogger(__name__)
@@ -291,3 +295,25 @@ def reset_deadlines_banner_should_display(course_key, request):
display_reset_dates_banner = True
break
return display_reset_dates_banner
def can_show_verified_upgrade(user, course_id, enrollment):
"""
Check if we are able to show verified upgrade message based
on the enrollment and current user partition
"""
if not enrollment:
return False
partition_service = PartitionService(course_id)
enrollment_track_partition = partition_service.get_user_partition(ENROLLMENT_TRACK_PARTITION_ID)
group = partition_service.get_group(user, enrollment_track_partition)
current_mode = None
if group:
try:
current_mode = [
mode.get('slug') for mode in settings.COURSE_ENROLLMENT_MODES.values() if mode['id'] == group.id
].pop()
except IndexError:
pass
upgradable_mode = not current_mode or current_mode in CourseMode.UPSELL_TO_VERIFIED_MODES
return upgradable_mode and verified_upgrade_link_is_valid(enrollment)

View File

@@ -42,7 +42,7 @@ from .. import (
SHOW_UPGRADE_MSG_ON_COURSE_HOME,
USE_BOOTSTRAP_FLAG
)
from ..utils import get_course_outline_block_tree, get_resume_block
from ..utils import can_show_verified_upgrade, get_course_outline_block_tree, get_resume_block
from .course_dates import CourseDatesFragmentView
from .course_home_messages import CourseHomeMessageFragmentView
from .course_outline import CourseOutlineFragmentView
@@ -222,7 +222,11 @@ class CourseHomeFragmentView(EdxFragmentView):
has_discount = False
# TODO Add switch to control deployment
if SHOW_UPGRADE_MSG_ON_COURSE_HOME.is_enabled(course_key) and enrollment and enrollment.upgrade_deadline:
if SHOW_UPGRADE_MSG_ON_COURSE_HOME.is_enabled(course_key) and can_show_verified_upgrade(
request.user,
course.id,
enrollment
):
upgrade_url = EcommerceService().upgrade_url(request.user, course_key)
upgrade_price, has_discount = format_strikeout_price(request.user, course_overview)

View File

@@ -2,15 +2,16 @@
Fragment for rendering the course's sock and associated toggle button.
"""
from django.template.loader import render_to_string
from web_fragments.fragment import Fragment
from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link, verified_upgrade_link_is_valid
from lms.djangoapps.courseware.utils import verified_upgrade_deadline_link
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
from openedx.features.discounts.utils import format_strikeout_price
from student.models import CourseEnrollment
from ..utils import can_show_verified_upgrade
class CourseSockFragmentView(EdxFragmentView):
"""
@@ -27,7 +28,7 @@ class CourseSockFragmentView(EdxFragmentView):
@staticmethod
def get_verification_context(request, course):
enrollment = CourseEnrollment.get_enrollment(request.user, course.id)
show_course_sock = verified_upgrade_link_is_valid(enrollment)
show_course_sock = can_show_verified_upgrade(request.user, course.id, enrollment)
if show_course_sock:
upgrade_url = verified_upgrade_deadline_link(request.user, course=course)
course_price, _ = format_strikeout_price(request.user, course)