def test_generate_xml(self): """ Generated post XML is valid """ xml = generate_request_xml('message_identifier_id', 'operation', 'lis_result_sourcedid', 'score') self.assertEqual( xml, """<?xml version='1.0' encoding='utf-8'?> <imsx_POXEnvelopeRequest xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/\ imsoms_v1p0"><imsx_POXHeader><imsx_POXRequestHeaderInfo><imsx_version>V1.0\ </imsx_version><imsx_messageIdentifier>message_identifier_id\ </imsx_messageIdentifier></imsx_POXRequestHeaderInfo></imsx_POXHeader>\ <imsx_POXBody><operationRequest><resultRecord><sourcedGUID><sourcedId>\ lis_result_sourcedid</sourcedId></sourcedGUID><result><resultScore>\ <language>en</language><textString>score</textString></resultScore>\ </result></resultRecord></operationRequest></imsx_POXBody>\ </imsx_POXEnvelopeRequest>""") xml = generate_request_xml('message_identifier_id', 'operation', 'lis_result_sourcedid', None) self.assertEqual( xml, """<?xml version='1.0' encoding='utf-8'?> <imsx_POXEnvelopeRequest xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/\ imsoms_v1p0"><imsx_POXHeader><imsx_POXRequestHeaderInfo><imsx_version>V1.0\ </imsx_version><imsx_messageIdentifier>message_identifier_id\ </imsx_messageIdentifier></imsx_POXRequestHeaderInfo></imsx_POXHeader>\ <imsx_POXBody><operationRequest><resultRecord><sourcedGUID><sourcedId>\ lis_result_sourcedid</sourcedId></sourcedGUID></resultRecord></operationRequest>\ </imsx_POXBody></imsx_POXEnvelopeRequest>""")
def test_generate_xml(self): """ Generated post XML is valid """ xml = generate_request_xml('message_identifier_id', 'operation', 'lis_result_sourcedid', 'score') self.assertEqual(xml, """<?xml version='1.0' encoding='utf-8'?> <imsx_POXEnvelopeRequest xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/\ imsoms_v1p0"><imsx_POXHeader><imsx_POXRequestHeaderInfo><imsx_version>V1.0\ </imsx_version><imsx_messageIdentifier>message_identifier_id\ </imsx_messageIdentifier></imsx_POXRequestHeaderInfo></imsx_POXHeader>\ <imsx_POXBody><operationRequest><resultRecord><sourcedGUID><sourcedId>\ lis_result_sourcedid</sourcedId></sourcedGUID><result><resultScore>\ <language>en</language><textString>score</textString></resultScore>\ </result></resultRecord></operationRequest></imsx_POXBody>\ </imsx_POXEnvelopeRequest>""") xml = generate_request_xml('message_identifier_id', 'operation', 'lis_result_sourcedid', None) self.assertEqual(xml, """<?xml version='1.0' encoding='utf-8'?> <imsx_POXEnvelopeRequest xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/\ imsoms_v1p0"><imsx_POXHeader><imsx_POXRequestHeaderInfo><imsx_version>V1.0\ </imsx_version><imsx_messageIdentifier>message_identifier_id\ </imsx_messageIdentifier></imsx_POXRequestHeaderInfo></imsx_POXHeader>\ <imsx_POXBody><operationRequest><resultRecord><sourcedGUID><sourcedId>\ lis_result_sourcedid</sourcedId></sourcedGUID></resultRecord></operationRequest>\ </imsx_POXBody></imsx_POXEnvelopeRequest>""")
def test_post_response_valid_xml(self): """ Test post grade with valid XML response """ uri = 'https://localhost:8000/dev_stack' def request_callback(request, cburi, headers): # pylint: disable=unused-argument, """ Mock expected response. """ return 200, headers, self.expected_response httpretty.register_uri(httpretty.POST, uri, body=request_callback) consumers = { "__consumer_key__": { "secret": "__lti_secret__", "cert": TEST_CLIENT_CERT, }, } body = generate_request_xml('message_identifier_id', 'operation', 'lis_result_sourcedid', '1.0') ret = post_message(consumers, "__consumer_key__", uri, body) self.assertTrue(ret) ret = post_message2(consumers, "__consumer_key__", uri, body) self.assertTrue(ret)
def post(self, request): """ Post grade to LTI consumer using XML :param: score: 0 <= score <= 1. (Score MUST be between 0 and 1) :return: True if post successful and score valid :exception: LTIPostMessageException if call failed """ try: lti_session = ltiSession.objects.get( id=request.data["ltisession"]["id"]) except ltiSession.DoesNotExist: return Response(data={ "error": "No LTI session exists for this ID" }, status=status.HTTP_400_BAD_REQUEST) consumer = lticonsumer.objects.get(id=lti_session.lti_consumer.id) schematic = StateSave.objects.get(save_id=request.data["schematic"]) schematic.shared = True schematic.save() submission_data = { "project": consumer, "student": schematic.owner, "score": consumer.score, "ltisession": lti_session, "schematic": schematic } submission = Submission.objects.create(**submission_data) xml = generate_request_xml( message_identifier(), 'replaceResult', lti_session.lis_result_sourcedid, submission.score) msg = "" try: post = post_message( consumers(), lti_session.oauth_consumer_key, lti_session.lis_outcome_service_url, xml) if not post: msg = 'An error occurred while saving your score.\ Please try again.' raise LTIPostMessageException('Post grade failed') else: submission.lms_success = True submission.save() msg = 'Your score was submitted. Great job!' return Response(data={"message": msg}, status=status.HTTP_200_OK) except LTIException: submission.lms_success = False submission.save() return Response(data={"message": msg}, status=status.HTTP_400_BAD_REQUEST)
def send_grade_to_lms(request, attempt): """ Sends the grade to lms using xml. :param request: django request object :param attempt: the Response object whose data is to be sent :return: None if quiz is not graded. """ quiz = db.get_quiz(request) quiz_settings = db.get_quiz_settings(quiz) student = db.get_user(request) if not quiz_settings.graded: return None outcome_service_url = lti.get_outcome_service_url(request) result_sourcedid = lti.get_result_sourced_id(request) # if outcome_service_url or result_sourcedid is not available in this request, search the database # It is very unlikely (or maybe impossible) that outcome_service_url will not be in the request itself, # but there is no harm in searching database if we can't find it in the current request ( or is there? ) if not (outcome_service_url or result_sourcedid): try: outcome_service_data = OutcomeServiceData.objects.get(user=student, quiz=quiz) outcome_service_url = outcome_service_data.lis_outcome_service_url result_sourcedid = outcome_service_data.lis_result_sourcedid except OutcomeServiceData.DoesNotExists: return # cannot send the grade as outcome_service_url is not available consumer_key = lti.get_oauth_consumer_key(request) message_identifier_id = "iquiz_grade" # TODO: Is this correct? operation = "replaceResult" score = get_grade(attempt, quiz) xml = generate_request_xml(message_identifier_id=message_identifier_id, operation=operation, lis_result_sourcedid=result_sourcedid, score=score) if not post_message(CONSUMERS, consumer_key, outcome_service_url, xml): raise Exception("Some error occurred while sending grade to the lms.") # add the last successfully sent response id and time to the outcome_service_data outcome_service_data = OutcomeServiceData.objects.get_or_create( user=student, quiz=quiz) outcome_service_data.response = attempt outcome_service_data.outcome_send_time = datetime.datetime.utcnow()
def get(self, request, submissionid, grade): user = request.user submitted_assignment = SubmittedAssignments.objects.get( id=submissionid) lis_result_sourcedid = submitted_assignment.lis_result_sourcedid if lis_result_sourcedid: xml = generate_request_xml('{:.0f}'.format(time.time()), 'replaceResult', lis_result_sourcedid, grade) config = getattr(settings, 'PYLTI_CONFIG', dict()) consumers = config.get('consumers', dict()) print(consumers) print(submitted_assignment.consumer_key) if not post_message(consumers, submitted_assignment.consumer_key, submitted_assignment.lis_outcome_service_url, xml): # Something went wrong, display an error. # Is 500 the right thing to do here? print("Scoring not successful") else: print('Your score was submitted. Great job!') submitted_assignment_serializer = SubmittedAssignmentsSerializer( submitted_assignment, data={ 'grade': grade, 'graded': True }, partial=True) if submitted_assignment_serializer.is_valid(): submitted_assignment_serializer.save() else: return Response({'error': submitted_assignment_serializer.errors}, status=500) return Response( {'submitted_assignment': submitted_assignment_serializer.data}, status=200)