Skip to content

Commit

Permalink
Show a message for instructors in VS course launches
Browse files Browse the repository at this point in the history
While VitalSource course launches is something only students should do
to adquire a license we'll show a message for instructors pointing them
to create assignments instead.
  • Loading branch information
marcospri committed May 6, 2024
1 parent b0d4e6d commit abdef38
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 22 deletions.
3 changes: 3 additions & 0 deletions lms/error_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ class ErrorCode(str, Enum):
CANVAS_INVALID_SCOPE = "canvas_invalid_scope"
VITALSOURCE_STUDENT_PAY_NO_LICENSE = "vitalsource_student_pay_no_license"
VITALSOURCE_STUDENT_PAY_LICENSE_LAUNCH = "vitalsource_student_pay_license_launch"
VITALSOURCE_STUDENT_PAY_LICENSE_LAUNCH_INSTRUCTOR = (
"vitalsource_student_pay_license_launch_instructor"
)
REUSED_CONSUMER_KEY = "reused_consumer_key"
25 changes: 15 additions & 10 deletions lms/services/vitalsource/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,22 +188,27 @@ def check_h_license(
self, lti_user: LTIUser, lti_params: LTIParams
) -> ErrorCode | None:
"""Check if the user of the current launch has a license for the H LTI app."""
if not self._student_pay_enabled or lti_user.is_instructor:
# Not a school using student pay or the current user it's an instructor.
if not self._student_pay_enabled:
# Not a school using student pay
return None

if lti_params["resource_link_id"] == lti_params["context_id"]:
# This looks like a "course launch" from a student
# This means that the student launch our tool from the course
# This looks like a "course launch"
# This means that the user launched our tool from the course
# "course materials" placement to acquire a license for our SKU.
# We can't do anything else from here other than display a message
return (
ErrorCode.VITALSOURCE_STUDENT_PAY_LICENSE_LAUNCH_INSTRUCTOR
if lti_user.is_instructor
else ErrorCode.VITALSOURCE_STUDENT_PAY_LICENSE_LAUNCH
)

return ErrorCode.VITALSOURCE_STUDENT_PAY_LICENSE_LAUNCH

user_reference = self.get_user_reference(lti_params)
assert self._sso_client
if not self._sso_client.get_user_book_license(user_reference, self.H_SKU):
return ErrorCode.VITALSOURCE_STUDENT_PAY_NO_LICENSE
if lti_user.is_learner:
# Do the actual license check, only for students
user_reference = self.get_user_reference(lti_params)
assert self._sso_client
if not self._sso_client.get_user_book_license(user_reference, self.H_SKU):
return ErrorCode.VITALSOURCE_STUDENT_PAY_NO_LICENSE

return None

Expand Down
22 changes: 22 additions & 0 deletions lms/static/scripts/frontend_apps/components/ErrorDialogApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export default function ErrorDialogApp() {
title = 'Hypothesis license activated';
displaySupportLink = false;
break;
case 'vitalsource_student_pay_license_launch_instructor':
title = 'This button allows students to acquire licenses';
displaySupportLink = false;
break;
default:
description =
'An error occurred when launching the Hypothesis application';
Expand Down Expand Up @@ -105,6 +109,24 @@ export default function ErrorDialogApp() {
</p>
</>
)}
{error.errorCode ===
'vitalsource_student_pay_license_launch_instructor' && (
<>
<p>
To create a Hypothesis-enabled reading in Canvas, create a new
Assignment or Module item.
</p>
<p>
See:{' '}
<Link
target="_blank"
href="https://web.hypothes.is/help/using-the-hypothesis-app-through-vitalsource/"
>
https://web.hypothes.is/help/using-the-hypothesis-app-through-vitalsource/
</Link>
</p>
</>
)}
</ErrorModal>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,13 @@ describe('ErrorDialogApp', () => {
'You have now activated your license to use the Hypothesis tool in your LMS.',
);
});
it('shows dialog for vital_source_student_pay_license_launch for instructors', () => {
fakeConfig.errorCode = 'vitalsource_student_pay_license_launch_instructor';

const wrapper = renderApp();
assert.include(
wrapper.text(),
'To create a Hypothesis-enabled reading in Canvas, create a new Assignment or Module item.',
);
});
});
3 changes: 2 additions & 1 deletion lms/static/scripts/frontend_apps/errors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export type AppLaunchServerErrorCode =
| 'reused_consumer_key'
| 'vitalsource_student_pay_no_license'
| 'vitalsource_student_pay_license_launch';
| 'vitalsource_student_pay_license_launch'
| 'vitalsource_student_pay_license_launch_instructor';

export type OAuthServerErrorCode =
| 'blackboard_missing_integration'
Expand Down
49 changes: 38 additions & 11 deletions tests/unit/lms/services/vitalsource/service_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,32 +100,39 @@ def test_get_user_reference(self, value, pattern, user_reference):

assert result == user_reference

@pytest.mark.parametrize("enabled", [True, False])
@pytest.mark.parametrize("instructor", [True, False])
def test_check_h_license_success(
self, request, svc, enabled, pyramid_request, instructor
):
svc._student_pay_enabled = enabled # pylint:disable=protected-access
if instructor:
request.getfixturevalue("user_is_instructor")
def test_check_h_license_disabled(self, svc, pyramid_request):
svc._student_pay_enabled = False # pylint:disable=protected-access

assert not svc.check_h_license(
pyramid_request.lti_user, pyramid_request.lti_params
)

def test_check_h_license_student_course_launch(self, svc, pyramid_request):
@pytest.mark.parametrize(
"user_fixture,code",
[
(
"user_is_instructor",
ErrorCode.VITALSOURCE_STUDENT_PAY_LICENSE_LAUNCH_INSTRUCTOR,
),
("user_is_learner", ErrorCode.VITALSOURCE_STUDENT_PAY_LICENSE_LAUNCH),
],
)
def test_check_h_license_course_launch(
self, request, svc, pyramid_request, user_fixture, code
):
svc._student_pay_enabled = True # pylint:disable=protected-access
pyramid_request.lti_params["context_id"] = "COURSE_ID"
pyramid_request.lti_params["resource_link_id"] = "COURSE_ID"
_ = request.getfixturevalue(user_fixture)

assert (
svc.check_h_license(pyramid_request.lti_user, pyramid_request.lti_params)
== ErrorCode.VITALSOURCE_STUDENT_PAY_LICENSE_LAUNCH
== code
)

@pytest.mark.usefixtures("user_is_learner")
def test_check_h_license_failure(self, svc, pyramid_request, customer_client):
svc._student_pay_enabled = True # pylint:disable=protected-access

customer_client.get_user_book_license.return_value = None

assert (
Expand All @@ -137,6 +144,26 @@ def test_check_h_license_failure(self, svc, pyramid_request, customer_client):
svc.get_user_reference(pyramid_request.lti_params), svc.H_SKU
)

@pytest.mark.usefixtures("user_is_learner")
def test_check_h_license_success(self, svc, pyramid_request, customer_client):
svc._student_pay_enabled = True # pylint:disable=protected-access
customer_client.get_user_book_license.return_value = sentinel.license

assert not (
svc.check_h_license(pyramid_request.lti_user, pyramid_request.lti_params)
)

@pytest.mark.usefixtures("user_is_instructor")
def test_check_h_license_no_license_check_for_instructors(
self, svc, pyramid_request, customer_client
):
svc._student_pay_enabled = True # pylint:disable=protected-access

assert not (
svc.check_h_license(pyramid_request.lti_user, pyramid_request.lti_params)
)
customer_client.get_user_book_license.assert_not_called()

@pytest.mark.parametrize(
"proxy_method,args",
(
Expand Down

0 comments on commit abdef38

Please sign in to comment.