class LtiUserDataTest(TestCase):
    minimal_valid_lti_parameters = {
        'lis_result_sourcedid': 'result-sourced-id',
        'lis_outcome_service_url': 'lis-outcome-service-url'
    }

    def setUp(self):
        self.model = LtiUserData(
            edx_lti_parameters=self.minimal_valid_lti_parameters)

    def test_send_lti_grade_empty_lti_parameters_raises_value_error(self, _):
        self.model.edx_lti_parameters = None
        with self.assertRaises(ValueError) as exc:
            self.model.send_lti_grade(0)
            self.assertEqual("LTI grade parameters is not set", exc.message)

    @ddt.data(
        {'lis_result_sourcedid': '111'},
        {'lis_outcome_service_url': '111'},
        {
            'lis_result_sourcedid': '',
            'lis_outcome_service_url': '111'
        },
        {
            'lis_result_sourcedid': '111',
            'lis_outcome_service_url': ''
        },
    )
    def test_send_lti_grade_missing_lti_parameters_raises_value_error(
            self, lti_parameters, _):
        self.model.edx_lti_parameters = lti_parameters
        with self.assertRaises(ValueError) as exc:
            self.model.send_lti_grade(0)
            self.assertIn("Following required LTI parameters are not set",
                          exc.message)

    @ddt.data(-1, 2, 1 + 10**-10, -10**-10, 7, 5, 42, -14)
    def test_send_lti_grade_incorrect_grade_raises_value_error(
            self, incorrect_grade, _):
        with self.assertRaises(ValueError) as exc:
            self.model.send_lti_grade(incorrect_grade)
            self.assertIn("Grade should be in range [0..1]", exc.message)

    @override_settings(LTI_CLIENT_KEY='client_key',
                       LTI_CLIENT_SECRET='lti_client_secret')
    def test_send_lti_grade_creates_tool_provider(
            self, tool_provider_constructor_mock):
        self.model.send_lti_grade(0)
        tool_provider_constructor_mock.assert_called_with(
            'client_key', 'lti_client_secret', self.model.edx_lti_parameters)

    @ddt.data(*[1.0 - i * 0.1 for i in xrange(10, -1, -1)])
    def test_send_lti_grade_sends_replace_result_request(
            self, grade, tool_provider_constructor_mock):
        tool_provider_mock = tool_provider_constructor_mock.return_value
        self.model.send_lti_grade(grade)

        tool_provider_mock.post_replace_result.assert_called_with(grade)
Example #2
0
 def log_in_with_lti(self, user=None, password=None, lti_params=None):
     """Log a user in with fake LTI data."""
     if user is None:
         user = self.user
     if lti_params is None:
         lti_params = self.LTI_PARAMS.copy()
     lti_params['lis_person_sourcedid'] = user.username
     lti_params['lis_person_contact_email_primary'] = user.email
     lti_params['custom_assignment_id'] = unicode(self.assignment.pk)
     lti_params['custom_question_id'] = unicode(self.question.pk)
     LtiUserData.store_lti_parameters(user, LTIView.authentication_manager, lti_params)
     self.client.login(username=user.username, password=password or 'test')
Example #3
0
 def log_in_with_lti(self, user=None, password=None, lti_params=None):
     """Log a user in with fake LTI data."""
     if user is None:
         user = self.user
     if lti_params is None:
         lti_params = self.LTI_PARAMS.copy()
     lti_params['lis_person_sourcedid'] = user.username
     lti_params['lis_person_contact_email_primary'] = user.email
     lti_params['custom_assignment_id'] = unicode(self.assignment.pk)
     lti_params['custom_question_id'] = unicode(self.question.pk)
     LtiUserData.store_lti_parameters(user, LTIView.authentication_manager,
                                      lti_params)
     self.client.login(username=user.username, password=password or 'test')
class LtiUserDataTest(TestCase):
    minimal_valid_lti_parameters = {
        'lis_result_sourcedid': 'result-sourced-id',
        'lis_outcome_service_url': 'lis-outcome-service-url'
    }

    def setUp(self):
        self.model = LtiUserData(edx_lti_parameters=self.minimal_valid_lti_parameters)

    def test_send_lti_grade_empty_lti_parameters_raises_value_error(self, _):
        self.model.edx_lti_parameters = None
        with self.assertRaises(ValueError) as exc:
            self.model.send_lti_grade(0)
            self.assertEqual("LTI grade parameters is not set", exc.message)

    @ddt.data(
        {'lis_result_sourcedid': '111'},
        {'lis_outcome_service_url': '111'},
        {'lis_result_sourcedid': '', 'lis_outcome_service_url': '111'},
        {'lis_result_sourcedid': '111', 'lis_outcome_service_url': ''},
    )
    def test_send_lti_grade_missing_lti_parameters_raises_value_error(self, lti_parameters, _):
        self.model.edx_lti_parameters = lti_parameters
        with self.assertRaises(ValueError) as exc:
            self.model.send_lti_grade(0)
            self.assertIn("Following required LTI parameters are not set", exc.message)

    @ddt.data(
        -1, 2, 1 + 10 ** -10, -10 ** -10, 7, 5, 42, -14
    )
    def test_send_lti_grade_incorrect_grade_raises_value_error(self, incorrect_grade, _):
        with self.assertRaises(ValueError) as exc:
            self.model.send_lti_grade(incorrect_grade)
            self.assertIn("Grade should be in range [0..1]", exc.message)

    @override_settings(LTI_CLIENT_KEY='client_key', LTI_CLIENT_SECRET='lti_client_secret')
    def test_send_lti_grade_creates_tool_provider(self, tool_provider_constructor_mock):
        self.model.send_lti_grade(0)
        tool_provider_constructor_mock.assert_called_with('client_key', 'lti_client_secret', self.model.edx_lti_parameters)

    @ddt.data(*[1.0 - i * 0.1 for i in xrange(10, -1, -1)])
    def test_send_lti_grade_sends_replace_result_request(self, grade, tool_provider_constructor_mock):
        tool_provider_mock = tool_provider_constructor_mock.return_value
        self.model.send_lti_grade(grade)

        tool_provider_mock.post_replace_result.assert_called_with(grade)
 def test_send_grade_loose_suppresses_and_logs_does_not_exist(
         self, get_user_data):
     get_user_data.side_effect = LtiUserData.DoesNotExist()
     with self.assertRaises(LtiUserData.DoesNotExist), \
             patch("django_lti_tool_provider.signals._logger.info") as patched_log_info:
         _send_grade(Mock(), 0, None)
         patched_log_info.assert_called_once()
         call_args = patched_log_info.call_args[0]
         self.assertIn("No LTI parameters", call_args[0])
 def _right_user(cls, user, lti_parameters):
     try:
         info, created = LtiUserData.get_or_create_by_parameters(
             user, cls.authentication_manager, cls.lti_param_filter(lti_parameters), create=False
         )
         if created:
             # If this is the first time the user's data is being created, that means
             # that the user predated the LTI request.
             info.delete()
             return False
         return True
     except (WrongUserError, LtiUserData.DoesNotExist):
         return False
Example #7
0
 def _right_user(cls, user, lti_parameters):
     try:
         info, created = LtiUserData.get_or_create_by_parameters(
             user,
             cls.authentication_manager,
             cls.lti_param_filter(lti_parameters),
             create=False)
         if created:
             # If this is the first time the user's data is being created, that means
             # that the user predated the LTI request.
             info.delete()
             return False
         return True
     except (WrongUserError, LtiUserData.DoesNotExist):
         return False
Example #8
0
        2. This is OpenID redirect from edx if actual LTI request was send anonymously - already validated
           LTI parameters and stored them in session - take them from session

        When lti parameters are ready (either taken from session or parsed and validated from request) store them
        in DB for later
        """
        if cls.SESSION_KEY in request.session and not cls._is_new_lti_request(
                request):
            lti_parameters = request.session[cls.SESSION_KEY]
            del request.session[cls.SESSION_KEY]
        else:
            try:
                lti_parameters = cls._get_lti_parameters_from_request(request)
            except oauth2.Error, e:
                _logger.exception(u"Invalid LTI Request")
                return HttpResponseBadRequest(u"Invalid LTI Request: " +
                                              e.message)

        lti_data = LtiUserData.store_lti_parameters(
            request.user, cls.authentication_manager,
            cls.lti_param_filter(lti_parameters))
        Signals.LTI.received.send(cls, user=request.user, lti_data=lti_data)

        return HttpResponseRedirect(
            cls.authentication_manager.authenticated_redirect_to(
                request, lti_parameters))

    @classmethod
    def _is_new_lti_request(cls, request):
        return 'lis_result_sourcedid' in request.POST
    def process_authenticated_lti(cls, request):
        """
        There are two options:
        1. This is actual LTI request made with cookies already set - need parsing and validating LTI parameters
        2. This is OpenID redirect from edx if actual LTI request was send anonymously - already validated
           LTI parameters and stored them in session - take them from session

        When lti parameters are ready (either taken from session or parsed and validated from request) store them
        in DB for later
        """
        if cls.SESSION_KEY in request.session and not cls._is_new_lti_request(request):
            lti_parameters = request.session[cls.SESSION_KEY]
            del request.session[cls.SESSION_KEY]
        else:
            try:
                lti_parameters = cls._get_lti_parameters_from_request(request)
            except oauth2.Error, e:
                _logger.exception(u"Invalid LTI Request")
                return HttpResponseBadRequest(u"Invalid LTI Request: " + e.message)

        lti_data = LtiUserData.store_lti_parameters(
            request.user, cls.authentication_manager, cls.lti_param_filter(lti_parameters)
        )
        Signals.LTI.received.send(cls, user=request.user, lti_data=lti_data)

        return HttpResponseRedirect(cls.authentication_manager.authenticated_redirect_to(request, lti_parameters))

    @classmethod
    def _is_new_lti_request(cls, request):
        return 'lis_result_sourcedid' in request.POST
 def setUp(self):
     self.model = LtiUserData(edx_lti_parameters=self.minimal_valid_lti_parameters)
 def setUp(self):
     self.model = LtiUserData(
         edx_lti_parameters=self.minimal_valid_lti_parameters)
 def test_send_grade_no_lti_user_data_raises_does_not_exist(
         self, get_user_data):
     get_user_data.side_effect = LtiUserData.DoesNotExist()
     with self.assertRaises(LtiUserData.DoesNotExist):
         _send_grade(Mock(), 0, None)