def get_object(self, event): """ Get object for the statement. """ try: display_name = event['context']['module']['display_name'] except KeyError: display_name = "Problem" try: event_data = self.get_event_data(event) submission = event_data['submission'][event_data['submission'].keys()[0]] question = submission['question'].replace('\"', '').replace('\\', '') question = re.sub(r'\(\$(\w+)\)', r'<\1>', question) except KeyError: question = event['context']['question'] return Activity( id=self._get_activity_id(event), definition=ActivityDefinition( type=constants.XAPI_ACTIVITY_INTERACTION, # could be _QUESTION if not CAPA name=LanguageMap({'ru-RU': question}), description=LanguageMap({'ru-RU': display_name}), # TODO: interactionType, correctResponsesPattern, choices, if possible ), )
def sendstatement_tally_shared(self, conn, tally_obj): # self._SC._active_presentation_name and tally_obj['id'] give me the id. # self._presentation_activity_id = 'https://iltserver.com/presentations/' + presentation_slug tally_activity_id = 'https://iltserver.com/presentations/' + self._SC._active_presentation_name + '/interaction_stats/' + tally_obj[ 'id'] verb = Verb( id='http://adlnet.gov/expapi/verbs/shared', display=LanguageMap({'en-US': 'shared'}), ) obj = Activity( id=tally_activity_id, definition=ActivityDefinition( name=LanguageMap({'en-US': 'Interaction statistics'}), description=LanguageMap({ 'en-US': 'Statistics about the responses to an interaction in the Reveal JS presentation.' }), type= 'https://xapi.xapicohort.org/iltxapiteam/activity-types/interaction-stats' ), ) result_obj = Result(extensions=Extensions({ 'https://iltserver.com/extensions/interaction-response-info': tally_obj })) statement = Statement(actor=conn._actor, verb=verb, object=obj, result=result_obj) self._send_to_LRS(statement)
def __init__(self, event, *args, **kwargs): try: display_name = event['display_name'] except KeyError: # not all events will have in the context display_name = "Course Block" if event['usage_key'].find('vertical+block') > 0: block_type = 'vertical block' elif event['usage_key'].find('sequential+block') > 0: block_type = 'sequential block' elif event['usage_key'].find('chapter+block') > 0: block_type = 'chapter block' else: block_type = 'undefined' kwargs.update({ 'type': constants.XAPI_ASSESSMENT_MODULE, 'name': LanguageMap({'ru-RU': display_name}), 'description': LanguageMap({'en-US': block_type}) }) try: ext_url = u'{}/question_amount'.format(settings.UNTI_XAPI_EXT_URL) kwargs.update({'extensions': {ext_url: event['childrens']}}) except: pass super(BlockAssessmentDefinition, self).__init__(*args, **kwargs)
def setUp(self): self.activity = Activity( id="http://tincanapi.com/TinCanPython/Test/Unit/0", definition=ActivityDefinition()) self.activity.definition.type = "http://id.tincanapi.com/activitytype/unit-test" self.activity.definition.name = LanguageMap({"en-US": "Python Tests"}) self.activity.definition.description = LanguageMap( {"en-US": "Unit test in the test suite for the Python library"})
def test_InitLanguageMap(self): arg = LanguageMap({ "en-US": "US-test", "fr-CA": "CA-test", "fr-FR": "FR-test" }) lmap = LanguageMap(arg) self.mapVerificationHelper(lmap)
def __init__(self, event, *args, **kwargs): kwargs.update({ 'type': constants.XAPI_CONTEXT_REFERRER, 'name': LanguageMap({'en-US': 'Referrer'}), 'description': LanguageMap({'en-US': 'A referring course activity'}) }) super(ReferringActivityDefinition, self).__init__(*args, **kwargs)
def test_ToJSON(self): lmap = LanguageMap({ "en-US": "US-test", "fr-CA": "CA-test", "fr-FR": "FR-test" }) # since the map is unordered, it is ok that to_json() changes ordering self.assertEqual( lmap.to_json(), '{"fr-CA": "CA-test", "en-US": "US-test", "fr-FR": "FR-test"}')
def criterion(cls, criterion): activity = Activity( id=XAPIResourceIRI.criterion(criterion.uuid), definition=ActivityDefinition( type=XAPIActivity.activity_types.get('question'), name=LanguageMap({'en-US': criterion.name}))) if criterion.description: activity.definition.description = LanguageMap( {'en-US': criterion.description}) return activity
def assignment(cls, assignment): activity = Activity( id=XAPIResourceIRI.assignment(assignment.uuid), definition=ActivityDefinition( type=XAPIActivity.activity_types.get('assessment'), name=LanguageMap({'en-US': assignment.name}))) if assignment.description: activity.definition.description = LanguageMap( {'en-US': assignment.description}) return activity
def get_object(self, name, description): """ Get object for the statement. """ return Activity( id=X_API_ACTIVITY_COURSE, definition=ActivityDefinition( name=LanguageMap({'en-US': name}), description=LanguageMap({'en-US': description}), ), )
def test_build_statement(self): """ The build_statement function should return a valid tincan Statement. """ user = UserFactory() verb = Verb( id="https://activitystrea.ms/schema/1.0/create", display=LanguageMap({"en-US": "created"}), ) activity = Activity( id=f"id://ashley/topic/{uuid.uuid4()}", definition=ActivityDefinition( name=LanguageMap({"en-US": "test topic"}), type="http://id.tincanapi.com/activitytype/discussion", ), ) context = Context(context_activities=ContextActivities(parent=[ Activity( id=f"uuid://{uuid.uuid4()}", definition=ActivityDefinition( name=LanguageMap({"en-US": "test forum"}), type="http://id.tincanapi.com/activitytype/community-site", ), ) ])) statement1 = build_statement(user, verb, activity, context) statement2 = build_statement(user, verb, activity, context) # The function should generate a random, non empty uuid as a # statement ID self.assertIsInstance(statement1.id, uuid.UUID) self.assertIsInstance(statement2.id, uuid.UUID) self.assertNotEqual(statement1.id, statement2.id) # The statement id can also be specified statement3_id = uuid.uuid4() statement3 = build_statement(user, verb, activity, context, statement3_id) self.assertEqual(statement3_id, statement3.id) # The verb, object and context should correspond to the given arguments self.assertEqual(statement1.verb, verb) self.assertEqual(statement1.object, activity) self.assertEqual(statement1.context, context) # The Actor part of the statement should reflect the user passed as an # argument self.assertEqual(statement1.actor.account.name, user.lti_remote_user_id) self.assertEqual(statement1.actor.account.home_page, user.lti_consumer.url)
def listVerificationHelper(self, iclist): self.assertIsInstance(iclist, InteractionComponentList) self.assertEqual(len(iclist), 2) self.assertIsInstance(iclist[0], InteractionComponent) self.assertIsInstance(iclist[1], InteractionComponent) self.assertEqual(iclist[0].id, 'test1') self.assertEqual(iclist[1].id, 'test2') self.assertEqual(iclist[0].description, LanguageMap({"en-US": "test1"})) self.assertEqual(iclist[1].description, LanguageMap({"en-US": "test2"}))
def setUp(self): self.endpoint = lrs_properties.endpoint self.version = lrs_properties.version self.username = lrs_properties.username self.password = lrs_properties.password self.lrs = RemoteLRS( version=self.version, endpoint=self.endpoint, username=self.username, password=self.password, ) self.agent = Agent(mbox="mailto:[email protected]") self.agent2 = Agent(mbox="mailto:[email protected]") self.verb = Verb(id="http://adlnet.gov/expapi/verbs/experienced", display=LanguageMap({"en-US": "experienced"})) self.group = Group(member=[self.agent, self.agent2]) self.activity = Activity( id="http://tincanapi.com/TinCanPython/Test/Unit/0", definition=ActivityDefinition()) self.activity.definition.type = "http://id.tincanapi.com/activitytype/unit-test" self.activity.definition.name = LanguageMap({"en-US": "Python Tests"}) self.activity.definition.description = LanguageMap( {"en-US": "Unit test in the test suite for the Python library"}) self.activity.object_type = 'Activity' self.parent = Activity(id="http://tincanapi.com/TinCanPython/Test", definition=ActivityDefinition()) self.parent.definition.type = "http://id.tincanapi.com/activitytype/unit-test-suite" self.parent.definition.name = LanguageMap({"en-US": "Python Tests"}) self.parent.definition.description = LanguageMap( {"en-US": "Unit test in the test suite for the Python library"}) self.parent.object_type = 'Activity' self.statement_ref = StatementRef(id=uuid.uuid4()) self.context = Context(registration=uuid.uuid4(), statement=self.statement_ref) # self.context.context_activities = ContextActivities(parent=[self.parent]) self.score = Score(raw=97, scaled=0.97, max=100, min=0) self.result = Result(score=self.score, success=True, completion=True, duration="PT120S") self.substatement = SubStatement( actor=self.agent, verb=self.verb, object=self.activity, )
def test_AsVersionNotEmpty(self): lmap = LanguageMap({ "en-US": "US-test", "fr-CA": "CA-test", "fr-FR": "FR-test" }) check = lmap.as_version() self.assertEqual(check, { "en-US": "US-test", "fr-CA": "CA-test", "fr-FR": "FR-test" })
def __init__(self, event, *args, **kwargs): try: display_name = event['context']['module']['display_name'] except KeyError: # not all events will have in the context display_name = "Course Block" kwargs.update({ 'type': constants.XAPI_ACTIVITY_MODULE, 'name': LanguageMap({'en': display_name}), 'description': LanguageMap({'en': 'A course block in a course delivered through Open edX'}) }) super(BlockActivityDefinition, self).__init__(*args, **kwargs)
def __init__(self, event, *args, **kwargs): # TODO get course name, probably from enrollment API # in course_details['course_name'] kwargs.update({ 'type': constants.XAPI_ACTIVITY_COURSE, 'name': LanguageMap({'en': 'Course'}), 'description': LanguageMap({'en': 'A course delivered through Open edX'}) }) super(CourseActivityDefinition, self).__init__(*args, **kwargs)
def track_forum_view(sender, forum, user, request, response, **kwargs): """Log a XAPI statement when a user views a forum.""" parent_activities = None consumer = getattr(user, "lti_consumer", None) if consumer is None: logger.warning("Unable to get LTI consumer of user %s", user) return xapi_logger = logging.getLogger(f"xapi.{user.lti_consumer.slug}") verb = Verb( id="http://id.tincanapi.com/verb/viewed", display=LanguageMap({"en-US": "viewed"}), ) obj = Activity( id=f"id://ashley/forum/{forum.pk}", definition=ActivityDefinition( name=LanguageMap( {to_locale(settings.LANGUAGE_CODE).replace("_", "-"): forum.name} ), type="http://id.tincanapi.com/activitytype/community-site", ), ) if request.forum_permission_handler.current_lti_context_id is not None: try: lti_context = LTIContext.objects.get( pk=request.forum_permission_handler.current_lti_context_id ) parent_activities = [ Activity( id=lti_context.lti_id, definition=ActivityDefinition( type="http://adlnet.gov/expapi/activities/course" ), ) ] except LTIContext.DoesNotExist: pass if parent_activities is not None: context = Context( context_activities=ContextActivities(parent=parent_activities), ) else: context = None statement = build_statement(user, verb, obj, context) if statement: xapi_logger.info(statement.to_json())
def set_presentation_object(self, presentation_slug): self._presentation_activity_id = 'https://iltserver.com/presentations/' + presentation_slug object = Activity( id=self._presentation_activity_id, definition=ActivityDefinition( name=LanguageMap( {'en-US': 'A team-ilt-xapi RevealJS presentation'}), description=LanguageMap({'en-US': 'A RevealJS presentation'}), type= 'https://xapi.xapicohort.org/revealjs/activity-type/presentation' ), ) self._presentation_object = object
def _set_session_object(self): self._session_activity_id = 'https://iltserver.com/sessions/' + self._SC._session_id object = Activity( id=self._session_activity_id, definition=ActivityDefinition( name=LanguageMap({'en-US': 'A team-ilt-xapi session'}), description=LanguageMap({ 'en-US': 'A synchronous multiuser session on our wonderful system' }), type= 'https://xapi.xapicohort.org/iltxapiteam/activity-types/session' ), ) self._session_object = object
def get_object(self, event): """ Get object for the statement. """ return Activity( id=self._get_activity_id(event), definition=ActivityDefinition( type=constants.XAPI_ACTIVITY_VIDEO, name=LanguageMap( {'en': 'Video'} ), # TODO: get video name if possible, but not in tracking logs description=LanguageMap( {'en': 'A video in an Open edX course'}), ), )
def comparison_criterion(cls, comparison, comparison_criterion): return Activity( id=XAPIResourceIRI.comparison_criterion(comparison_criterion.uuid), definition=ActivityDefinition( type=XAPIActivity.activity_types.get('solution'), name=LanguageMap({'en-US': "Assignment criterion comparison"})))
def sendstatement_interaction_completed(self, conn, interaction_info): # HERE TO-DO: I want to change 'completion' ... if the submission was forced, say completion = NO # although it's probably not nessary... verb = Verb( id='http://adlnet.gov/expapi/verbs/completed', display=LanguageMap({'en-US': 'completed'}), ) if (interaction_info['interaction_type'] == 'choice'): result_obj = Result( completion=interaction_info['interaction_type'], response=','.join(interaction_info['options_checked']), success=interaction_info['correct']) else: result_obj = Result( completion=interaction_info['interaction_type'], response=interaction_info['response'], success=interaction_info['correct']) statement = Statement( actor=conn._actor, verb=verb, object=self._make_interaction_object(interaction_info), result=result_obj) #app_log.info('SENDING INTERACTION Statement: '+ statement.actor.mbox + ' ' + statement.verb.id + ' ' + statement.object.id) self._send_to_LRS(statement)
def assignment(cls, assignment): activity = Activity( id=ResourceIRI.assignment(assignment.course_uuid, assignment.uuid), definition=ActivityDefinition( type=XAPIActivity.activity_types.get('assessment'), name=LanguageMap({ 'en-US': LearningRecord.trim_text_to_size_limit(assignment.name) }))) if assignment.description: activity.definition.description = LanguageMap({ 'en-US': LearningRecord.trim_text_to_size_limit(assignment.description) }) return activity
def getStatements(self, name): # connect LRS lrs = self.LRS # specify user as agent actor = Agent( name=name, mbox='mailto:' + name + '@id.lrs', ) # optional specify verb verb = Verb( id=self.verbs.get("experienced"), display=LanguageMap({'en-US': 'experienced'}), ) query = { "agent": actor, #"verb": verb, "limit": 1000 #change limit if needed } # query LRS for statements response = lrs.query_statements(query) # check response if not response: raise ValueError("statements could not be queried") # return queried statements return response
def course(cls, course): activity = Activity(id=XAPIResourceIRI.course(course.uuid), definition=ActivityDefinition( type=XAPIActivity.activity_types.get('course'), name=LanguageMap({'en-US': course.name}))) return activity
def criterion(cls, criterion): activity = Activity( id=ResourceIRI.criterion(criterion.uuid), definition=ActivityDefinition( type=XAPIActivity.activity_types.get('question'), name=LanguageMap({ 'en-US': LearningRecord.trim_text_to_size_limit(criterion.name) }))) if criterion.description: activity.definition.description = LanguageMap({ 'en-US': LearningRecord.trim_text_to_size_limit(criterion.description) }) return activity
def self_evaluation_question(cls, answer_comment): return Activity(id=XAPIResourceIRI.self_evaluation_question( answer_comment.assignment_uuid), definition=ActivityDefinition( type=XAPIActivity.activity_types.get('question'), name=LanguageMap( {'en-US': "Assignment self-evaluation"})))
def get_context_activities(self): """ Get context activities for xAPI transformed event. Returns: `ContextActivities` """ if self.get_data('context.course_id') is not None: course = get_course_from_id(self.get_data('context.course_id')) course_name = LanguageMap({constants.EN_US: course["display_name"]}) parent_activities = [ Activity( id=self.get_object_iri('course', self.get_data('context.course_id')), object_type=constants.XAPI_ACTIVITY_COURSE, definition=ActivityDefinition( type=constants.XAPI_ACTIVITY_COURSE, name=course_name ) ), ] return ContextActivities( parent=ActivityList(parent_activities), ) else: return None
def get_verb(self): """ Get verb for course enrollment statement. """ return Verb( id=X_API_VERB_REGISTERED, display=LanguageMap({'en-US': 'registered'}), )
def get_verb(self): """ Get verb for the statement. """ return Verb( id=X_API_VERB_COMPLETED, display=LanguageMap({'en-US': 'completed'}), )
def test_FromJSON(self): lmap = LanguageMap.from_json('{"en-US": "US-test", "fr-CA": "CA-test", "fr-FR": "FR-test"}') self.mapVerificationHelper(lmap)
def test_FromJSONExceptionBadJSON(self): with self.assertRaises(ValueError): LanguageMap.from_json('{"bad JSON"}')
def test_FromJSONExceptionNestedObject(self): with self.assertRaises(TypeError): LanguageMap.from_json('{"fr-CA": "test", "en-US": {"nested": "object"}}')
def test_FromJSONEmptyObject(self): lmap = LanguageMap.from_json('{}') self.assertIsInstance(lmap, LanguageMap) self.assertEqual(lmap, {})
def test_AsVersionEmpty(self): lmap = LanguageMap() check = lmap.as_version() self.assertEqual(check, {})
def test_AsVersionNotEmpty(self): lmap = LanguageMap({"en-US": "US-test", "fr-CA": "CA-test", "fr-FR": "FR-test"}) check = lmap.as_version() self.assertEqual(check, {"en-US": "US-test", "fr-CA": "CA-test", "fr-FR": "FR-test"})
def test_ToJSONFromJSON(self): json_str = '{"fr-CA": "CA-test", "en-US": "US-test", "fr-FR": "FR-test"}' lmap = LanguageMap.from_json(json_str) self.mapVerificationHelper(lmap) self.assertEqual(lmap.to_json(), json_str)
def test_ToJSON(self): lmap = LanguageMap({"en-US": "US-test", "fr-CA": "CA-test", "fr-FR": "FR-test"}) # since the map is unordered, it is ok that to_json() changes ordering self.assertEqual(lmap.to_json(), '{"fr-CA": "CA-test", "en-US": "US-test", "fr-FR": "FR-test"}')