diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fcce77bf4c5e..efa70ee8b37a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,8 @@ These are notable changes in edx-platform. This is a rolling list of changes, in roughly chronological order, most recent first. Add your entries at or near the top. Include a label indicating the component affected. +Blades: Allow user with BetaTester role correctly use LTI. BLD-641. + Blades: Video player persist speed preferences between videos. BLD-237. Blades: Change the download video field to a dropdown that will allow students diff --git a/lms/djangoapps/courseware/features/lti.feature b/lms/djangoapps/courseware/features/lti.feature index b9f03e7f02f0..e004f4bd5be8 100644 --- a/lms/djangoapps/courseware/features/lti.feature +++ b/lms/djangoapps/courseware/features/lti.feature @@ -4,7 +4,7 @@ Feature: LMS.LTI component #1 Scenario: LTI component in LMS with no launch_url is not rendered - Given the course has correct LTI credentials + Given the course has correct LTI credentials with registered Instructor And the course has an LTI component with no_launch_url fields: | open_in_a_new_page | | False | @@ -12,7 +12,7 @@ Feature: LMS.LTI component #2 Scenario: LTI component in LMS with incorrect lti_id is rendered incorrectly - Given the course has correct LTI credentials + Given the course has correct LTI credentials with registered Instructor And the course has an LTI component with incorrect_lti_id fields: | open_in_a_new_page | | False | @@ -28,13 +28,13 @@ Feature: LMS.LTI component #4 Scenario: LTI component in LMS is correctly rendered in new page - Given the course has correct LTI credentials + Given the course has correct LTI credentials with registered Instructor And the course has an LTI component with correct fields Then I view the LTI and it is rendered in new page #5 Scenario: LTI component in LMS is correctly rendered in iframe - Given the course has correct LTI credentials + Given the course has correct LTI credentials with registered Instructor And the course has an LTI component with correct fields: | open_in_a_new_page | | False | @@ -42,7 +42,7 @@ Feature: LMS.LTI component #6 Scenario: Graded LTI component in LMS is correctly works - Given the course has correct LTI credentials + Given the course has correct LTI credentials with registered Instructor And the course has an LTI component with correct fields: | open_in_a_new_page | weight | is_graded | has_score | | False | 10 | True | True | @@ -55,4 +55,15 @@ Feature: LMS.LTI component And I see in the gradebook table that "HW" is "50" And I see in the gradebook table that "Total" is "5" + #7 + Scenario: Graded LTI component in LMS is correctly works with beta testers + Given the course has correct LTI credentials with registered BetaTester + And the course has an LTI component with correct fields: + | open_in_a_new_page | weight | is_graded | has_score | + | False | 10 | True | True | + And I submit answer to LTI question + And I click on the "Progress" tab + Then I see text "Problem Scores: 5/10" + And I see graph with total progress "5%" + diff --git a/lms/djangoapps/courseware/features/lti.py b/lms/djangoapps/courseware/features/lti.py index 2959ffee85d0..d463eaace2cc 100644 --- a/lms/djangoapps/courseware/features/lti.py +++ b/lms/djangoapps/courseware/features/lti.py @@ -1,14 +1,19 @@ #pylint: disable=C0111 +import datetime import os +import pytz +from mock import patch from django.contrib.auth.models import User from django.core.urlresolvers import reverse from lettuce import world, step from lettuce.django import django_url -from common import course_id, visit_scenario_item -from courseware.tests.factories import InstructorFactory +from common import course_id, visit_scenario_item +from courseware.tests.factories import InstructorFactory, BetaTesterFactory +from courseware.access import has_access +from student.tests.factories import UserFactory @step('I view the LTI and error is shown$') @@ -65,8 +70,8 @@ def incorrect_lti_is_rendered(_step): check_lti_iframe_content("Wrong LTI signature") -@step('the course has correct LTI credentials$') -def set_correct_lti_passport(_step): +@step('the course has correct LTI credentials with registered (.*)$') +def set_correct_lti_passport(_step, user='Instructor'): coursenum = 'test_course' metadata = { 'lti_passports': ["correct_lti_id:{}:{}".format( @@ -74,7 +79,7 @@ def set_correct_lti_passport(_step): world.lti_server.oauth_settings['client_secret'] )] } - i_am_registered_for_the_course(coursenum, metadata) + i_am_registered_for_the_course(coursenum, metadata, user) @step('the course has incorrect LTI credentials$') @@ -126,7 +131,7 @@ def add_correct_lti_to_course(_step, fields): visit_scenario_item('LTI') -def create_course(course, metadata): +def create_course_for_lti(course, metadata): # First clear the modulestore so we don't try to recreate # the same course twice @@ -181,16 +186,35 @@ def create_course(course, metadata): metadata={'graded': True, 'format': 'Homework'}) -def i_am_registered_for_the_course(course, metadata): - # Create the course - create_course(course, metadata) - - # Create an instructor - instructor = InstructorFactory(course=world.scenario_dict['COURSE'].location) +@patch.dict('courseware.access.settings.FEATURES', {'DISABLE_START_DATES': False}) +def i_am_registered_for_the_course(coursenum, metadata, user='Instructor'): + # Create user + if user == 'BetaTester': + # Create the course + now = datetime.datetime.now(pytz.UTC) + tomorrow = now + datetime.timedelta(days=5) + metadata.update({'days_early_for_beta': 5, 'start': tomorrow}) + create_course_for_lti(coursenum, metadata) + course_descriptor = world.scenario_dict['COURSE'] + course_location = world.scenario_dict['COURSE'].location + + # create beta tester + user = BetaTesterFactory(course=course_location) + normal_student = UserFactory() + instructor = InstructorFactory(course=course_location) + assert not has_access(normal_student, course_descriptor, 'load') + assert has_access(user, course_descriptor, 'load') + assert has_access(instructor, course_descriptor, 'load') + else: + create_course_for_lti(coursenum, metadata) + course_descriptor = world.scenario_dict['COURSE'] + course_location = world.scenario_dict['COURSE'].location + user = InstructorFactory(course=course_location) # Enroll the user in the course and log them in - world.enroll_user(instructor, course_id(course)) - world.log_in(username=instructor.username, password='test') + if has_access(user, course_descriptor, 'load'): + world.enroll_user(user, course_id(coursenum)) + world.log_in(username=user.username, password='test') def check_lti_popup(): diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index e717743ba00b..f68c6cc31635 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -218,9 +218,11 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours See get_module() docstring for further details. """ - # Short circuit--if the user shouldn't have access, bail without doing any work - if not has_access(user, descriptor, 'load', course_id): - return None + # Do not check access when it's a noauth request. + if getattr(user, 'known', True): + # Short circuit--if the user shouldn't have access, bail without doing any work + if not has_access(user, descriptor, 'load', course_id): + return None student_data = KvsFieldData(DjangoKeyValueStore(field_data_cache)) descriptor._field_data = LmsFieldData(descriptor._field_data, student_data) @@ -516,6 +518,8 @@ def handle_xblock_callback_noauth(request, course_id, usage_id, handler, suffix= """ Entry point for unauthenticated XBlock handlers. """ + request.user.known = False + return _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, request.user)