Merge pull request #32931 from openedx/MichaelRoytman/MST-2038-courseware-api-xpert-la

Replace learning_assistant_launch_url with learning_assistant_enabled in courseware API.
This commit is contained in:
Michael Roytman
2023-08-09 11:54:05 -04:00
committed by GitHub
4 changed files with 12 additions and 160 deletions

View File

@@ -114,7 +114,7 @@ class CourseInfoSerializer(serializers.Serializer): # pylint: disable=abstract-
linkedin_add_to_profile_url = serializers.URLField()
is_integrity_signature_enabled = serializers.BooleanField()
user_needs_integrity_signature = serializers.BooleanField()
learning_assistant_launch_url = serializers.CharField()
learning_assistant_enabled = serializers.BooleanField()
def __init__(self, *args, **kwargs):
"""

View File

@@ -11,13 +11,10 @@ import ddt
from completion.test_utils import CompletionWaffleTestMixin, submit_completions_for_testing
from django.conf import settings
from django.contrib.auth import get_user_model
from django.test import override_settings
from django.test.client import RequestFactory
from edx_django_utils.cache import TieredCache
from edx_toggles.toggles.testutils import override_waffle_flag
from lti_consumer.data import Lti1p3LaunchData
from lti_consumer.models import LtiConfiguration
from xmodule.data import CertificatesDisplayBehaviors
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
@@ -434,109 +431,16 @@ class CourseApiTestViews(BaseCoursewareTests, MasqueradeMixin):
assert courseware_data['can_access_proctored_exams'] == result
@override_waffle_flag(COURSEWARE_LEARNING_ASSISTANT, active=False)
def test_learning_assistant_launch_url_disabled_waffle_flag(self):
def test_learning_assistant_enabled_disabled_waffle_flag(self):
response = self.client.get(self.url)
launch_url = response.json()['learning_assistant_launch_url']
assert launch_url is None
learning_assistant_enabled = response.json()['learning_assistant_enabled']
self.assertFalse(learning_assistant_enabled)
@override_waffle_flag(COURSEWARE_LEARNING_ASSISTANT, active=True)
@override_settings(LEARNING_ASSISTANT_CONFIG_ID=None)
def test_learning_assistant_launch_no_config(self):
def test_learning_assistant_enabled_enabled_waffle_flag(self):
response = self.client.get(self.url)
launch_url = response.json()['learning_assistant_launch_url']
assert launch_url is None
@override_waffle_flag(COURSEWARE_LEARNING_ASSISTANT, active=True)
def test_learning_assistant_launch_1p1(self):
test_config = LtiConfiguration.objects.create(
config_id=1,
version='lti_1p1'
)
with override_settings(LEARNING_ASSISTANT_CONFIG_ID=test_config.id):
response = self.client.get(self.url)
launch_url = response.json()['learning_assistant_launch_url']
assert launch_url is None
@override_waffle_flag(COURSEWARE_LEARNING_ASSISTANT, active=True)
def test_learning_assistant_launch_not_staff_unverified(self):
test_config = LtiConfiguration.objects.create(
config_id=1,
version='lti_1p3'
)
with override_settings(LEARNING_ASSISTANT_CONFIG_ID=test_config.id):
self.user.is_staff = False
self.user.save()
CourseEnrollment.enroll(self.user, self.course.id, 'audit')
response = self.client.get(self.url)
launch_url = response.json()['learning_assistant_launch_url']
assert launch_url is None
@ddt.data(
'verified',
'professional',
'masters',
'executive-education',
'paid-executive-education',
'paid-bootcamp'
)
@mock.patch('openedx.core.djangoapps.courseware_api.utils.get_lti_1p3_launch_start_url')
@override_waffle_flag(COURSEWARE_LEARNING_ASSISTANT, active=True)
def test_learning_assistant_launch_url(self, enrollment_mode, mock_lti_launch):
test_config = LtiConfiguration.objects.create(
config_id=1,
version='lti_1p3'
)
with override_settings(LEARNING_ASSISTANT_CONFIG_ID=test_config.id):
self.user.is_staff = False
self.user.save()
CourseEnrollment.enroll(self.user, self.course.id, enrollment_mode)
expected_url = 'https://testlaunch.org'
mock_lti_launch.return_value = expected_url
response = self.client.get(self.url)
launch_url = response.json()['learning_assistant_launch_url']
assert launch_url == expected_url
expected_launch_data = Lti1p3LaunchData(
user_id=self.user.id,
user_role='student',
email=self.user.email,
config_id=1,
resource_link_id='-'.join(['1', str(self.course.id)]),
context_id=str(self.course.id),
context_type=['course_offering'],
context_title=self.course.display_name
)
mock_lti_launch.assert_called_with(expected_launch_data)
@mock.patch('openedx.core.djangoapps.courseware_api.utils.get_lti_1p3_launch_start_url')
@override_waffle_flag(COURSEWARE_LEARNING_ASSISTANT, active=True)
def test_learning_assistant_launch_url_instructor(self, mock_lti_launch):
self.client.login(username='instructor', password='foo')
test_config = LtiConfiguration.objects.create(
config_id=1,
version='lti_1p3'
)
with override_settings(LEARNING_ASSISTANT_CONFIG_ID=test_config.id):
expected_url = 'https://testlaunch.org'
mock_lti_launch.return_value = expected_url
response = self.client.get(self.url)
launch_url = response.json()['learning_assistant_launch_url']
assert launch_url == expected_url
expected_launch_data = Lti1p3LaunchData(
user_id=self.instructor.id,
user_role='instructor',
email=self.instructor.email,
config_id=1,
resource_link_id='-'.join(['1', str(self.course.id)]),
context_id=str(self.course.id),
context_type=['course_offering'],
context_title=self.course.display_name
)
mock_lti_launch.assert_called_with(expected_launch_data)
learning_assistant_enabled = response.json()['learning_assistant_enabled']
self.assertTrue(learning_assistant_enabled)
@ddt.ddt

View File

@@ -3,15 +3,9 @@ Courseware API Mixins.
"""
from babel.numbers import get_currency_symbol
from django.conf import settings
from lti_consumer.api import get_lti_1p3_launch_start_url
from lti_consumer.data import Lti1p3LaunchData
from lti_consumer.models import LtiConfiguration
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollmentCelebration, UserCelebration
from lms.djangoapps.courseware.access import get_user_role
from lms.djangoapps.courseware.utils import can_show_verified_upgrade, verified_upgrade_deadline_link
from openedx.features.course_duration_limits.access import get_user_course_expiration_date
from openedx.features.discounts.applicability import can_show_streak_discount_coupon
@@ -72,41 +66,3 @@ def serialize_upgrade_info(user, course_overview, enrollment):
'sku': mode.sku,
'upgrade_url': verified_upgrade_deadline_link(user, course_overview),
}
def get_learning_assistant_launch_url(user, course_key, enrollment_object, overview):
"""
Return the launch URL for an LTI based learning assistant
"""
config_id = getattr(settings, 'LEARNING_ASSISTANT_CONFIG_ID', None)
if not config_id:
return None
try:
lti_config = LtiConfiguration.objects.get(config_id=config_id)
except LtiConfiguration.DoesNotExist:
return None
if lti_config.version != 'lti_1p3':
return None
user_role = get_user_role(user, course_key)
if (
(enrollment_object and enrollment_object.mode not in CourseMode.VERIFIED_MODES)
and (user_role != 'staff' or user_role != 'instructor')
):
return None
launch_data = Lti1p3LaunchData(
user_id=user.id,
user_role=user_role,
email=user.email,
config_id=config_id,
resource_link_id='-'.join([str(config_id), str(course_key)]),
context_id=str(course_key),
context_type=['course_offering'],
context_title=overview.display_name
)
lti_url = get_lti_1p3_launch_start_url(launch_data)
return lti_url

View File

@@ -47,7 +47,7 @@ from lms.djangoapps.gating.api import get_entrance_exam_score, get_entrance_exam
from lms.djangoapps.grades.api import CourseGradeFactory
from lms.djangoapps.verify_student.services import IDVerificationService
from openedx.core.djangoapps.agreements.api import get_integrity_signature
from openedx.core.djangoapps.courseware_api.utils import get_celebrations_dict, get_learning_assistant_launch_url
from openedx.core.djangoapps.courseware_api.utils import get_celebrations_dict
from openedx.core.djangoapps.programs.utils import ProgramProgressMeter
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin
@@ -360,19 +360,11 @@ class CoursewareMeta:
return enrollment_active and CourseMode.is_eligible_for_certificate(enrollment_mode)
@property
def learning_assistant_launch_url(self):
def learning_assistant_enabled(self):
"""
Returns a URL for the learning assistant LTI launch if applicable, otherwise None
Returns a boolean representing whether the requesting user should have access to the Xpert Learning Assistant.
"""
if learning_assistant_is_active(self.course_key):
lti_url = get_learning_assistant_launch_url(
self.effective_user,
self.course_key,
self.enrollment_object,
self.overview,
)
return lti_url
return None
return learning_assistant_is_active(self.course_key)
class CoursewareInformation(RetrieveAPIView):
@@ -463,7 +455,7 @@ class CoursewareInformation(RetrieveAPIView):
verified mode. Will update to reverify URL if necessary.
* linkedin_add_to_profile_url: URL to add the effective user's certificate to a LinkedIn Profile.
* user_needs_integrity_signature: Whether the user needs to sign the integrity agreement for the course
* learning_assistant_launch_url: URL for the LTI launch of a learning assistant
* learning_assistant_enabled: Whether the Xpert Learning Assistant is enabled for the requesting user
**Parameters:**