def launch(request):
    config = get_tool_conf()
    if not check_if_success_getting_tool_config(config):
        return LTIError(config).response_json()
    CacheConfig = get_cache_config()
    message_launch = DjangoMessageLaunch(
        request, config, launch_data_storage=CacheConfig.launch_data_storage)
    if not CacheConfig.is_dummy_cache:
        # fetch platform's public key from cache instead of calling the API will speed up the launch process
        message_launch.set_public_key_caching(
            CacheConfig.launch_data_storage,
            cache_lifetime=CacheConfig.cache_lifetime)
    else:
        logger.info(
            'DummyCache is set up, recommended atleast to us Mysql DB cache for LTI advantage services'
        )

    try:
        course_id = extract_launch_variables_for_tool_use(
            request, message_launch)
    except Exception as e:
        return LTIError(e).response_json()

    url = reverse('courses', kwargs={'course_id': course_id})
    return redirect(url)
Esempio n. 2
0
 def get_launch_message(self):
     """
     Return the LTI 1.3 launch message object for the current request.
     """
     launch_message = DjangoMessageLaunch(
         self.request,
         self.lti_tool_config,
         launch_data_storage=self.lti_tool_storage)
     # This will force the LTI launch validation steps.
     launch_message.get_launch_data()
     return launch_message
Esempio n. 3
0
    def test_get_members(self):
        from pylti1p3.contrib.django import DjangoMessageLaunch
        tool_conf = get_test_tool_conf()

        with patch.object(DjangoMessageLaunch, "_get_jwt_body", autospec=True) as get_jwt_body:
            message_launch = DjangoMessageLaunch(FakeRequest(), tool_conf)
            get_jwt_body.side_effect = lambda x: self._get_jwt_body()
            with patch('socket.gethostbyname', return_value="127.0.0.1"):
                with requests_mock.Mocker() as m:
                    m.post(self._get_auth_token_url(), text=json.dumps(self._get_auth_token_response()))
                    m.get(self._get_jwt_body()['https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice']
                          ['context_memberships_url'],
                          text=json.dumps({
                              'members': [{
                                  'status': 'Active',
                                  'user_id': '20eb59f5-26e8-46bc-87b0-57ed54820aeb',
                                  'roles': ['http://purl.imsglobal.org/vocab/lis/v2/membership#Learner']
                              }],
                              'id': 'http://canvas.docker/api/lti/courses/1/names_and_roles',
                              'context': {
                                  'title': 'Test',
                                  'id': '4dde05e8ca1973bcca9bffc13e1548820eee93a3',
                                  'label': 'Test'}
                              }),
                          headers={
                              'Status': '200 OK',
                              'X-Request-Context-Id': 'fb3662e8-527c-4c83-b4d5-b32d247a896c',
                              'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff',
                              'Transfer-Encoding': 'chunked',
                              'X-Rate-Limit-Remaining': '600.0',
                              'X-Runtime': '0.235817',
                              'Server': 'nginx/1.13.5',
                              'X-Canvas-Meta': 'o=lti/ims/names_and_roles;n=course_index;t=Course;i=1;b=892132;'
                                               'm=892132;u=0.08;y=0.00;d=0.01;',
                              'Connection': 'keep-alive', 'ETag': 'W/"a198e0b4e31245287ba175ddf5a9223c"',
                              'X-Request-Cost': '0.09043669500000007', 'X-UA-Compatible': 'IE=Edge,chrome=1',
                              'Cache-Control': 'max-age=0, private, must-revalidate',
                              'Date': 'Mon, 12 Aug 2019 09:50:45 GMT',
                              'Link': '<http://canvas.docker/api/lti/courses/1/names_and_roles?page=1'
                                      '&per_page=10>; rel="current",<http://canvas.docker/api/lti/cou'
                                      'rses/1/names_and_roles?page=1&per_page=10>; rel="first",'
                                      '<http://canvas.docker/api/lti/courses/1/names_and_roles'
                                      '?page=1&per_page=10>; rel="last"',
                              'X-Frame-Options': 'SAMEORIGIN',
                              'Content-Type': 'application/vnd.ims.lti-nrps.v2.membershipcontainer+json; charset=utf-8'
                          })
                    members = message_launch.validate_registration().get_nrps().get_members()
                    self.assertEqual(len(members), 1)
                    self.assertDictEqual(members[0], {
                        'status': 'Active',
                        'user_id': '20eb59f5-26e8-46bc-87b0-57ed54820aeb',
                        'roles': ['http://purl.imsglobal.org/vocab/lis/v2/membership#Learner']
                    })
Esempio n. 4
0
    def test_send_scores(self):
        from pylti1p3.contrib.django import DjangoMessageLaunch
        tool_conf = get_test_tool_conf()

        with patch.object(DjangoMessageLaunch, "_get_jwt_body",
                          autospec=True) as get_jwt_body:
            message_launch = DjangoMessageLaunch(DjangoFakeRequest(),
                                                 tool_conf)
            get_jwt_body.side_effect = lambda x: self._get_jwt_body()
            with patch('socket.gethostbyname', return_value="127.0.0.1"):
                with requests_mock.Mocker() as m:
                    m.post(self._get_auth_token_url(),
                           text=json.dumps(self._get_auth_token_response()))
                    m.get(
                        'http://canvas.docker/api/lti/courses/1/line_items',
                        text=json.dumps([{
                            'scoreMaximum': 100.0,
                            'tag': 'score',
                            'id':
                            'http://canvas.docker/api/lti/courses/1/line_items/1',
                            'label': 'Score'
                        }]))
                    expected_result = {
                        'resultUrl':
                        'http://canvas.docker/api/lti/courses/1/line_items/1/results/4'
                    }
                    m.post(
                        'http://canvas.docker/api/lti/courses/1/line_items/1/scores',
                        text=json.dumps(expected_result))

                    ags = message_launch.validate_registration().get_ags()
                    sub = message_launch.get_launch_data().get('sub')

                    timestamp = datetime.datetime.utcnow().strftime(
                        '%Y-%m-%dT%H:%M:%S+0000')
                    sc = Grade()
                    sc.set_score_given(5) \
                        .set_score_maximum(100) \
                        .set_timestamp(timestamp) \
                        .set_activity_progress('Completed') \
                        .set_grading_progress('FullyGraded') \
                        .set_user_id(sub)

                    sc_line_item = LineItem()
                    sc_line_item.set_tag('score') \
                        .set_score_maximum(100) \
                        .set_label('Score')

                    resp = ags.put_grade(sc, sc_line_item)
                    self.assertEqual(expected_result, resp['body'])
Esempio n. 5
0
    def _launch(self, request, tool_conf, key_set_url_response=None, force_validation=False):
        from pylti1p3.contrib.django import DjangoMessageLaunch
        obj = DjangoMessageLaunch(request, tool_conf)
        obj.set_jwt_verify_options({
            'verify_aud': False,
            'verify_exp': False
        })

        with patch('socket.gethostbyname', return_value="127.0.0.1"):
            with requests_mock.Mocker() as m:
                key_set_url_text = key_set_url_response if key_set_url_response else json.dumps(self.jwt_canvas_keys)
                m.get(TOOL_CONFIG[self.iss]['key_set_url'], text=key_set_url_text)
                if force_validation:
                    return obj.validate()
                else:
                    return obj.get_launch_data()
Esempio n. 6
0
    def update_score(self, weighted_earned, weighted_possible, timestamp):
        """
        Use LTI's score service to update the LTI platform's gradebook.

        This method synchronously send a request to the LTI platform to update
        the assignment score.
        """

        launch_data = {
            'iss': self.profile.platform_id,
            'aud': self.profile.client_id,
            'https://purl.imsglobal.org/spec/lti-ags/claim/endpoint': {
                'lineitem': self.ags_lineitem,
                'scope': {
                    'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem',
                    'https://purl.imsglobal.org/spec/lti-ags/scope/score',
                }
            }
        }

        tool_config = DjangoDbToolConf()

        ags = (DjangoMessageLaunch(
            request=None,
            tool_config=tool_config).set_auto_validation(enable=False).set_jwt(
                {
                    'body': launch_data
                }).set_restored().validate_registration().get_ags())

        if weighted_possible == 0:
            weighted_score = 0
        else:
            weighted_score = float(weighted_earned) / float(weighted_possible)

        ags.put_grade(Grade().set_score_given(
            weighted_score).set_score_maximum(1).set_timestamp(
                timestamp.isoformat()).set_activity_progress('Submitted').
                      set_grading_progress('FullyGraded').set_user_id(
                          self.profile.subject_id))
Esempio n. 7
0
    def test_get_grades(self, name, line_items_exist):  # pylint: disable=unused-argument
        from pylti1p3.contrib.django import DjangoMessageLaunch
        tool_conf = get_test_tool_conf()

        with patch.object(DjangoMessageLaunch, "_get_jwt_body",
                          autospec=True) as get_jwt_body:
            message_launch = DjangoMessageLaunch(FakeRequest(), tool_conf)
            line_items_url = 'http://canvas.docker/api/lti/courses/1/line_items'
            get_jwt_body.side_effect = lambda x: self._get_jwt_body()
            with patch('socket.gethostbyname', return_value="127.0.0.1"):
                with requests_mock.Mocker() as m:
                    m.post(self._get_auth_token_url(),
                           text=json.dumps(self._get_auth_token_response()))

                    line_items_response = []
                    if line_items_exist:
                        line_items_response = [{
                            'scoreMaximum': 100.0,
                            'tag': 'score',
                            'id':
                            'http://canvas.docker/api/lti/courses/1/line_items/1',
                            'label': 'Score'
                        }, {
                            'scoreMaximum': 999.0,
                            'tag': 'time',
                            'id':
                            'http://canvas.docker/api/lti/courses/1/line_items/2',
                            'label': 'Time Taken'
                        }]
                    else:
                        m.post(
                            line_items_url,
                            text=json.dumps({
                                'scoreMaximum': 100.0,
                                'tag': 'score',
                                'id':
                                'http://canvas.docker/api/lti/courses/1/line_items/1',
                                'label': 'Score'
                            }))

                    m.get(line_items_url, text=json.dumps(line_items_response))
                    m.get(
                        'http://canvas.docker/api/lti/courses/1/line_items/1/results',
                        text=json.dumps([{
                            'resultScore':
                            13.0,
                            'resultMaximum':
                            100.0,
                            'userId':
                            '20eb59f5-26e8-46bc-87b0-57ed54820aeb',
                            'id':
                            'http://canvas.docker/api/lti/courses/1/line_items/1/results/1',
                            'scoreOf':
                            'http://canvas.docker/api/lti/courses/1/line_items/1'
                        }]))

                    score_line_item = LineItem()
                    score_line_item.set_tag('score') \
                        .set_score_maximum(100) \
                        .set_label('Score')

                    scores = message_launch.validate_registration().get_ags(
                    ).get_grades(score_line_item)
                    self.assertEqual(len(scores), 1)
                    self.assertDictEqual(
                        scores[0], {
                            'resultScore':
                            13.0,
                            'resultMaximum':
                            100.0,
                            'userId':
                            '20eb59f5-26e8-46bc-87b0-57ed54820aeb',
                            'id':
                            'http://canvas.docker/api/lti/courses/1/line_items/1/results/1',
                            'scoreOf':
                            'http://canvas.docker/api/lti/courses/1/line_items/1'
                        })
Esempio n. 8
0
 def _get_launch_obj(self, request, tool_conf, cache=False):
     from pylti1p3.contrib.django import DjangoMessageLaunch
     message_launch = DjangoMessageLaunch(request, tool_conf)
     if cache:
         message_launch.set_launch_data_storage(cache)
     return message_launch