def basic(cls, **kwargs): context = Context() if kwargs and kwargs.get('registration') != None: context.registration = kwargs.get('registration') return context
def test_InitLanguages(self): language_ids = ['en', 'ast', 'zh-yue', 'ar-afb', 'zh-Hans', 'az-Latn', 'en-GB', 'es-005', 'zh-Hant-HK', 'sl-nedis', 'sl-IT-nedis', 'de-CH-1901', 'de-DE-u-co-phonebk', 'en-US-x-twain'] for tag in language_ids: ctx = Context(language=tag) self.assertEqual(ctx.language, tag) self.assertIsInstance(ctx, Context)
def test_AsVersion(self): obj = { "registration": "016699c6-d600-48a7-96ab-86187498f16f", "instructor": {"member": [{"name": "instructorGroupMember"}]}, "team": {"member": [{"name": "teamGroupMember"}]}, "context_activities": {"category": {"id": "contextActivityCategory"}}, "revision": "revision", "platform": "platform", "language": "en-US", "extensions": {"extensions": "extend!"} } """ Keys are corrected, and ContextActivities is properly listified """ check_obj = { "registration": "016699c6-d600-48a7-96ab-86187498f16f", "instructor": {"member": [{"name": "instructorGroupMember", "objectType": "Agent"}], "objectType": "Group"}, "team": {"member": [{"name": "teamGroupMember", "objectType": "Agent"}], "objectType": "Group"}, "contextActivities": {"category": [{"id": "contextActivityCategory", "objectType": "Activity"}]}, "revision": "revision", "platform": "platform", "language": "en-US", "extensions": {"extensions": "extend!"} } ctx = Context(**obj) ctx2 = ctx.as_version() self.assertEqual(ctx2, check_obj)
def _add_default(cls, user, statement): if not statement.timestamp: statement.timestamp = LearningRecord.generate_timestamp() if impersonation.is_impersonating() and user.id == current_user.id: statement.actor = XAPIActor.generate_actor( impersonation.get_impersonation_original_user()) else: statement.actor = XAPIActor.generate_actor(user) # add default context info if not statement.context: statement.context = Context() if not statement.context.context_activities: statement.context.context_activities = ContextActivities() if not statement.context.context_activities.category: statement.context.context_activities.category = ActivityList() statement.context.context_activities.category.append( XAPIActivity.compair_source()) statement.context.platform = ResourceIRI.compair() if not statement.context.extensions: statement.context.extensions = Extensions() statement.context.extensions[ 'http://id.tincanapi.com/extension/session-info'] = { 'id': ResourceIRI.user_session(sess.get('session_id', '')), 'start_at': sess.get('start_at'), 'login_method': sess.get('login_method'), } if sess.get('end_at'): statement.context.extensions[ 'http://id.tincanapi.com/extension/session-info'][ 'end_at'] = sess.get('end_at') if impersonation.is_impersonating() and user.id == current_user.id: statement.context.extensions[ 'http://id.tincanapi.com/extension/session-info'][ 'impersonating-as'] = XAPIActor.generate_actor( user).as_version() statement.context.extensions[ 'http://id.tincanapi.com/extension/browser-info'] = {} if request and request.environ.get('HTTP_USER_AGENT'): statement.context.extensions[ 'http://id.tincanapi.com/extension/browser-info'][ 'user-agent'] = request.environ.get('HTTP_USER_AGENT') if request and request.environ.get('HTTP_REFERER'): statement.context.extensions[ 'http://id.tincanapi.com/extension/browser-info'][ 'referer'] = request.environ.get('HTTP_REFERER') return statement
def send_statement(verb_key, activity_key, activity_extensions=None): """Send a statement with the verb and activity keys and the context extensions""" if not tracing_enabled: return def thread_function(statement): # Send statement and receive HTTP response if not _send_statement_lrs(statement): io.add_statement( statement) # Backup the statement if it couldn't been sent global statement_number # Create the statement from the actor, the verb, the context and the activity keys if verb_key not in verbs: if debug_log_print: print("Tracing: Missing verb key {}".format(verb_key)) return if activity_key not in activities: if debug_log_print: print("Tracing: Missing activity key {}".format(activity_key)) return if send_to_LRS and debug_log_print: print("Tracing: Creating and Sending statement {}, {} {}".format( statement_number, verb_key, activity_key)) elif debug_log_print: print("Tracing: Creating (without sending) statement {}, {} {}".format( statement_number, verb_key, activity_key)) statement_number += 1 verb = verbs[verb_key] activity = activities[activity_key] extensions = { "https://www.lip6.fr/mocah/invalidURI/extensions/session-id": session_id, "https://www.lip6.fr/mocah/invalidURI/extensions/machine-id": machine_id, "https://www.lip6.fr/mocah/invalidURI/extensions/input-context": input_type } context = Context(extensions=extensions) if activity_extensions: activity = copy.deepcopy(activity) activity.definition.extensions = activity_extensions statement_time = datetime.datetime.utcnow() statement_time = statement_time.replace(tzinfo=datetime.timezone.utc) statement = Statement(actor=actor, verb=verb, object=activity, context=context, timestamp=statement_time) if debug_log_print: io.add_statement_debug(statement, statement_number) # Send the statement from another thread if send_to_LRS: x = threading.Thread(target=thread_function, args=(statement, )) x.start()
def get_context(self, user_details, course_details): """ Get Context for the statement. """ return Context(extensions=Extensions( { 'http://id.tincanapi.com/extension/user-details': user_details, 'http://id.tincanapi.com/extension/course-details': course_details, }, ))
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 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 test_InitEmpty(self): ctx = Context() self.assertIsInstance(ctx, Context) self.assertEqual(vars(ctx), {'_context_activities': None, '_extensions': None, '_instructor': None, '_language': None, '_platform': None, '_registration': None, '_revision': None, '_statement': None, '_team': None})
def _enhance_statement(self, statement): context = Context(registration=self._SC._session_id, instructor=self._SC._instructor_actor) statement.context = context statement.timestamp = time.time() statement.id = str(uuid.uuid4()) # embed more info into the statement: # in the context extensions encode the settings: if follow/mode and locked_navigationis on, # add result: time spent on slide, average slide time (if available in slide DOM node) # slide indices # progress? return statement
def create_statement(arbtt_csv_entry): """Creates a Tincan statement from arbtt csv input""" arbtt_record = ArbttRecord(arbtt_csv_entry) app = arbtt_record.application duration = arbtt_record.duration # XXX: Look for a cleaner way to get user details user = os.environ['LOGNAME'] email_address = "*****@*****.**" % (user, ) actor = Agent( name=user, mbox='mailto:' + email_address, ) verb = Verb( id='http://adlnet.gov/expapi/verbs/interacted', display=LanguageMap({'en-US': 'interacted'}), ) # Get activity from config or set the activity as 'unknown' activity_from_map = activity_map.get(app, "unknown") object = Activity( id=os.path.join(lrs['activities_uri'], activity_from_map), definition=ActivityDefinition( name=LanguageMap({'en-US': activity_from_map}), extensions=Extensions( {'http://id.tincanapi.com/extension/duration': duration}, ), ), ) context = Context(platform=app) # Construct the statement return Statement( actor=actor, verb=verb, object=object, context=context, )
def _add_default(cls, user, statement): if not statement.timestamp: statement.timestamp = datetime.datetime.now().replace( tzinfo=pytz.utc).isoformat() statement.actor = XAPIActor.generate_actor(user) # add default context info if not statement.context: statement.context = Context() if not statement.context.context_activities: statement.context.context_activities = ContextActivities() if not statement.context.context_activities.category: statement.context.context_activities.category = ActivityList() statement.context.context_activities.category.append( XAPIActivity.compair_source()) if request and request.environ.get('HTTP_USER_AGENT'): if not statement.context.extensions: statement.context.extensions = Extensions() browser_info_key = XAPIExtension.context_extensions.get( 'browser information') statement.context.extensions[ browser_info_key] = request.environ.get('HTTP_USER_AGENT') if request and request.environ.get('HTTP_REFERER'): if not statement.context.extensions: statement.context.extensions = Extensions() referer_key = XAPIExtension.context_extensions.get('referer') statement.context.extensions[referer_key] = request.environ.get( 'HTTP_REFERER') return statement
def get_context(self, event): """Get Context for the statement.""" return Context(platform=settings.OPENEDX_PLATFORM_URI, )
def track_topic_view(sender, topic, user, request, response, **kwargs): """Log a XAPI statement when a user views a topic.""" 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/topic/{topic.pk}", definition=ActivityDefinition( name=LanguageMap( {to_locale(settings.LANGUAGE_CODE).replace("_", "-"): topic.subject} ), type="http://id.tincanapi.com/activitytype/discussion", extensions={ "https://w3id.org/xapi/acrossx/extensions/total-items": topic.posts_count, "https://w3id.org/xapi/acrossx/extensions/total-pages": ( (topic.posts_count - 1) // machina_settings.TOPIC_POSTS_NUMBER_PER_PAGE ) + 1, }, ), ) parent_activities = [ Activity( id=f"uuid://{topic.forum.lti_id}", definition=ActivityDefinition( name=LanguageMap( { to_locale(settings.LANGUAGE_CODE).replace( "_", "-" ): topic.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.append( Activity( id=lti_context.lti_id, definition=ActivityDefinition( type="http://adlnet.gov/expapi/activities/course" ), ) ) except LTIContext.DoesNotExist: pass context = Context( context_activities=ContextActivities(parent=parent_activities), extensions={ "http://www.risc-inc.com/annotator/extensions/page": int( request.GET.get("page", default=1) ) }, ) statement = build_statement(user, verb, obj, context) if statement: xapi_logger.info(statement.to_json())
def sendStatement(self, reqData): #load requested data for statement generation data = json.loads(reqData) # create RemoteLRS endpoint lrs = self.LRS # generate statement # 1. actor actor = Agent( name=data["name"], mbox='mailto:' + data["name"] + '@id.lrs', ) # 2. verb verb = Verb( id=self.verbs.get(data["verb"]), display=LanguageMap({'en-US': data["verb"]}), ) # 3. object obj = Activity( id=self.objects.get(data["activity"]), definition=ActivityDefinition( name=LanguageMap({'en-US': data["activityid"]}) ) ) # 4. context context = Context( extensions=Extensions({ self.extensions.get("difficulty"): data["difficulty"], self.extensions.get("interaction"): data["interaction"], self.extensions.get("topic"): data["topic"] }) ) # 5. result result = Result( score=Score( raw=data["score"] ), success=data["success"] ) # build statement statement = Statement( actor=actor, verb=verb, object=obj, context=context, result=result ) # save statement response = lrs.save_statement(statement) # check response if not response: raise ValueError("statement failed to save") return str(True)
def socialmedia_builder(verb, platform, account_name, account_homepage, object_type, object_id, message, tags=[], parent_object_type=None, parent_id=None, rating=None, instructor_name=None, instructor_email=None, team_name=None, course_code=None, account_email=None, user_name=None, timestamp=None): verbmapper = {'created': 'http://activitystrea.ms/schema/1.0/create', 'shared': 'http://activitystrea.ms/schema/1.0/share', 'liked': 'http://activitystrea.ms/schema/1.0/like', 'rated': 'http://id.tincanapi.com/verb/rated', 'commented': 'http://adlnet.gov/expapi/verbs/commented'} objectmapper = {'Note': 'http://activitystrea.ms/schema/1.0/note', 'Tag': 'http://id.tincanapi.com/activitytype/tag', 'Article': 'http://activitystrea.ms/schema/1.0/article', 'Video': 'http://activitystrea.ms/schema/1.0/video'} agentaccount = AgentAccount(name=account_name, home_page=account_homepage) actor = Agent(account=agentaccount) if (account_email is not None): actor.mbox = account_email if (user_name is not None): actor.name = user_name verb_obj = Verb(id=verbmapper[verb],display=LanguageMap({'en-US': verb})) #message = message.decode('utf-8').encode('ascii', 'ignore') #message.decode('utf-8').replace(u"\u2018", "'").replace(u"\u2019", "'").replace(u"\u2013", "-").replace(u"\ud83d", " ").replace(u"\ude09", " ").replace(u"\u00a0l", " ").replace(u"\ud83d", " ").replace(u"\u2026", " ").replace(u"\ude09", " ").replace(u"\u00a0"," ") object = Activity( id=object_id, object_type=object_type, definition=ActivityDefinition( name=LanguageMap({'en-US': message}), type=objectmapper[object_type] ), ) taglist = [] for tag in tags: tagobject = Activity( id='http://id.tincanapi.com/activity/tags/tincan', object_type='Activity', definition=ActivityDefinition( name=LanguageMap({'en-US': tag}), type=objectmapper['Tag'] ), ) taglist.append(tagobject) parentlist = [] if (verb in ['liked','shared','commented','rated']): parentobject = Activity( id=parent_id, object_type=parent_object_type, ) parentlist.append(parentobject) courselist = [] if (course_code is not None): courseobject = Activity( id=course_code, object_type='Course', definition=ActivityDefinition(type="http://adlnet.gov/expapi/activities/course") ) courselist.append(courseobject) instructor = None if (instructor_name is not None): instructor=Agent(name=instructor_name,mbox=instructor_email) team = None if (team_name is not None): team = Group(Agent(name=team_name), object_type='Group') result = None if (rating is not None): rating_as_float = float(rating) result = Result(score=Score(raw=rating_as_float)) context = Context( registration=uuid.uuid4(), platform=platform, instructor=instructor, team=team, context_activities=ContextActivities(other=ActivityList(taglist),parent=ActivityList(parentlist),grouping=ActivityList(courselist)) ) statement = statement_builder(actor, verb_obj, object, context, result, timestamp) return statement
object = Activity( id='http://tincanapi.com/TinCanPython/Example/0', definition=ActivityDefinition( name=LanguageMap({'en-US': 'TinCanPython Library'}), description=LanguageMap( {'en-US': 'Use of, or interaction with, the TinCanPython Library'}), ), ) print("...done") # construct a context for the statement print("constructing the Context...") context = Context( registration=uuid.uuid4(), instructor=Agent( name='Lord TinCan', mbox='mailto:[email protected]', ), # language='en-US', ) print("...done") # construct the actual statement print("constructing the Statement...") statement = Statement( actor=actor, verb=verb, object=object, context=context, ) print("...done") # save our statement to the remote_lrs and store the response in 'response' print("saving the Statement...")