Beispiel #1
0
    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)
Beispiel #2
0
    def basic(cls, **kwargs):
        result = Result()

        if kwargs:
            if kwargs.get('success') != None:
                result.success = kwargs.get('success')
            if kwargs.get('completion') != None:
                result.completion = kwargs.get('completion')
            if kwargs.get('changes') != None:
                result.extensions = Extensions() if not result.extensions else result.extensions
                result.extensions['http://xapi.learninganalytics.ubc.ca/extension/changes'] = kwargs.get('changes')

        return result
Beispiel #3
0
 def get_result(self, event):
     event_data = self.get_event_data(event)
     cur_time = event_data.get('currentTime',
                               event_data.get('current_time', 0))
     return Result(extensions={
         constants.XAPI_RESULT_VIDEO_TIME: cur_time,
     })
Beispiel #4
0
    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)
Beispiel #5
0
    def get_result(self, event):
        event_data = self.get_event_data(event)
        cur_time = event_data.get('currentTime',
                                  event_data.get('current_time', 0))
        cur_time = float('{:.2f}'.format(cur_time))
        cur_time = jsonify_timedelta((datetime.timedelta(seconds=cur_time)))

        return Result(success=True, completion=False, duration=cur_time)
    def test_serialize_deserialize(self):
        res = Result()
        res.completion = True
        res.duration = timedelta(seconds=1.75)
        # res.duration = 'PT1.75S'     # ISO 8601
        res.extensions = self.extensions
        res.response = "Here's a response"
        res.score = self.score
        res.success = False

        self.assertSerializeDeserialize(res)
 def test_InitResult(self):
     statement = Statement(result=Result(duration=timedelta(days=7)))
     self.assertIsNone(statement.id)
     self.assertIsNone(statement.actor)
     self.assertIsNone(statement.verb)
     self.assertIsNone(statement.object)
     self.assertIsNone(statement.timestamp)
     self.assertIsNone(statement.stored)
     self.assertIsNone(statement.authority)
     self.resultVerificationHelper(statement.result)
Beispiel #8
0
    def get_result(self):
        """
        Get result for xAPI transformed event.

        Returns:
            `Result`
        """
        return Result(extensions=Extensions({
            constants.XAPI_RESULT_VIDEO_TIME:
            convert_seconds_to_float(self.get_data('data.currentTime'))
        }))
Beispiel #9
0
    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,
        )
Beispiel #10
0
 def get_result(self, event):
     event_data = self.get_event_data(event)
     earned = event_data['weighted_earned']
     possible = event_data['weighted_possible']
     return Result(
         score={
             'raw': earned,
             'min': 0,
             'max': possible,
             'scaled': float(earned / possible) if possible > 0 else 0
         },
         success=True if earned >= possible else False,
     )
Beispiel #11
0
    def test_serialize_deserialize(self):
        res = Result()
        res.completion = True
        res.duration = timedelta(seconds=1.75)
        # res.duration = 'PT1.75S'     # ISO 8601
        res.extensions = self.extensions
        res.response = "Here's a response"
        res.score = self.score
        res.success = False

        self.assertSerializeDeserialize(res)
    def test_serialize_deserialize_init(self):
        data = {
            'completion': True,
            'duration': timedelta(seconds=1.75),
            # 'duration': 'PT1.75S',   # ISO 8601
            'extensions': self.extensions,
            'response': "Here's a response",
            'score': self.score,
            'success': False,
        }
        res = Result(**data)

        self.assertSerializeDeserialize(res)
Beispiel #13
0
    def get_result(self):
        """
        Get result for xAPI transformed event.

        Returns:
            `Result`
        """
        return Result(extensions=Extensions({
            constants.XAPI_RESULT_VIDEO_TIME_FROM:
            convert_seconds_to_float(self.get_data('data.old_time')),
            constants.XAPI_RESULT_VIDEO_TIME_TO:
            convert_seconds_to_float(self.get_data('data.new_time')),
        }), )
Beispiel #14
0
 def sendstatement_unlocked_followme(self, conn):
     # the object of this statement is the presentation, in the context of session
     verb = Verb(
         id='http://adlnet.gov/expapi/verbs/interacted',
         display=LanguageMap({'en-US': 'interacted'}),
     )
     result_obj = Result(extensions=Extensions(
         {'https://iltserver.com/extensions/follow-me': 'off'}))
     statement = Statement(actor=conn._actor,
                           verb=verb,
                           object=self._presentation_object,
                           result=result_obj)
     self._send_to_LRS(statement)
Beispiel #15
0
    def get_result(self):
        """
        Get result for xAPI transformed event.

        Returns:
            `Result`
        """
        return Result(extensions=Extensions({
            constants.XAPI_RESULT_VIDEO_TIME:
            convert_seconds_to_float(self.get_data('data.duration'))
        }),
                      completion=True,
                      duration=convert_seconds_to_float(
                          self.get_data('data.duration')))
Beispiel #16
0
 def sendstatement_sync_all_to_instructor(self, conn):
     # the object of this statement is the presentation, in the context of session
     verb = Verb(
         id='http://adlnet.gov/expapi/verbs/interacted',
         display=LanguageMap({'en-US': 'interacted'}),
     )
     result_obj = Result(extensions=Extensions({
         'https://iltserver.com/extensions/sync-all-to-instructor':
         'request'
     }))
     statement = Statement(actor=conn._actor,
                           verb=verb,
                           object=self._presentation_object,
                           result=result_obj)
     self._send_to_LRS(statement)
    def get_result(self, course_grade):
        """
        Get result for the statement.

        Arguments:
            course_grade (CourseGrade): Course grade.
        """
        return Result(score=Score(
            scaled=course_grade.percent,
            raw=course_grade.percent * 100,
            min=MIN_SCORE,
            max=MAX_SCORE,
        ),
                      success=course_grade.passed,
                      completion=course_grade.passed)
Beispiel #18
0
    def get_result(self, event):

        return Result(score={
            'raw':
            event['context']['module']['progress'][0],
            'min':
            0,
            'max':
            event['context']['module']['progress'][1],
            'scaled':
            float(event['context']['module']['progress'][0] /
                  event['context']['module']['progress'][1])
        },
                      success=event['context']['module']['done'],
                      completion=True)
Beispiel #19
0
 def get_result(self, event):
     event_data = self.get_event_data(event)
     # for now we are going to assume one submission
     # TODO: when is that not true? is it ever not true? What problem types?
     submission = event_data['submission'][event_data['submission'].keys()
                                           [0]]
     return Result(
         score={
             'raw': event_data['grade'],
             'min': 0,
             'max': event_data['max_grade'],
             'scaled': float(event_data['grade'] / event_data['max_grade'])
         },
         success=event_data['success'] == 'correct',
         # TODO: to determine completion would need to know max allowed attempts?
         # probably should return True here but uswe a result extension for num attempts/attempts left
         response=json.dumps(submission['answer']))
Beispiel #20
0
    def basic(cls, **kwargs):
        result = Result()

        if kwargs:
            if kwargs.get('duration') != None:
                result.duration = kwargs.get('duration')
            if kwargs.get('success') != None:
                result.success = kwargs.get('success')
            if kwargs.get('completion') != None:
                result.completion = kwargs.get('completion')
            if kwargs.get('changes') != None:
                result.extensions = Extensions(
                ) if not result.extensions else result.extensions
                fields_changed_key = XAPIExtension.result_extensions.get(
                    'fields changed')
                result.extensions[fields_changed_key] = kwargs.get('changes')

        return result
Beispiel #21
0
    def get_result(self, event):
        event_data = self.get_event_data(event)
        # for now we are going to assume one submission
        # TODO: when is that not true? is it ever not true? What problem types?
        try:
            data = event_data['submission']
            answer = []
            for key in data:
                log.error('key {} - {}'.format(key, data[key]))
                trash = data[key]['answer']
                log.error(trash)
                if type(trash) is not unicode:
                    for i in trash:
                        p = re.sub(r"(\n.*)", r'', i)
                        answer.append(p)
                else:
                    answer.append(trash)
            if len(answer) > 1:
                answer = ', '.join("<%s>" % item for item in answer)
            else:
                answer = ''.join(answer[0])
            answer = answer.replace('\"', '').strip() #.replace('\\\\', '')
        except:
            answer = event['context']['answer'].strip() #.replace('\\\\', '')

        try:
            success = event_data['success'] == 'correct'
        except:
            success = event['event']['grade'] == event['event']['max_grade']

        return Result(
            score={
                'raw': event_data['grade'],
                'min': 0,
                'max': event_data['max_grade'],
                'scaled': float(event_data['grade']) / float(event_data['max_grade'])
            },
            success=success,
            # TODO: to determine completion would need to know max allowed attempts?
            # probably should return True here but uswe a result extension for num attempts/attempts left 
            response=answer.encode('utf-8')
        )
    def get_result(self):
        """
        Get result for xAPI transformed event.

        Returns:
            `Result`
        """
        event_data = self.get_data('data')
        return Result(success=event_data['weighted_earned'] >=
                      event_data['weighted_possible'],
                      score={
                          'min':
                          0,
                          'max':
                          event_data['weighted_possible'],
                          'raw':
                          event_data['weighted_earned'],
                          'scaled':
                          event_data['weighted_earned'] /
                          event_data['weighted_possible']
                      })
Beispiel #23
0
    def basic(cls, **kwargs):
        result = Result()

        if kwargs:
            if kwargs.get('duration') != None:
                result.duration = kwargs.get('duration')
            if kwargs.get('success') != None:
                result.success = kwargs.get('success')
            if kwargs.get('completion') != None:
                result.completion = kwargs.get('completion')
            if kwargs.get('changes') != None:
                result.extensions = Extensions() if not result.extensions else result.extensions
                fields_changed_key = XAPIExtension.result_extensions.get('fields changed')
                result.extensions[fields_changed_key] = kwargs.get('changes')

        return result
    def get_result(self, persistent_course_grade):
        """
        Get result for the statement.

        Arguments:
            persistent_course_grade (PersistentCourseGrade): PersistentCourseGrade record
        """
        completed = 0
        success = 0

        if persistent_course_grade.passed_timestamp is not None:
            completed = 1
            success = 1

        return Result(score=Score(
            scaled=persistent_course_grade.percent_grade,
            raw=persistent_course_grade.percent_grade * 100,
            min=MIN_SCORE,
            max=MAX_SCORE,
        ),
                      success=success,
                      completion=completed)
    def get_result(self):
        """
        Get result for xAPI transformed event.

        Returns:
            Result
        """
        # Do not transform result if the event is generated from browser
        if self.get_data('context.event_source') == 'browser':
            return None

        event_data = self.get_data('data')
        if event_data is None:
            event_data = {}

        submission = self._get_submission()
        if submission:
            response = submission["answer"]
        else:
            response = event_data.get('answers', None)

        return Result(
            success=event_data.get('success', None) == 'correct',
            score={
                'min':
                0,
                'max':
                event_data.get('max_grade', None),
                'raw':
                event_data.get('grade', None),
                'scaled':
                event_data.get('grade', None) /
                event_data.get('max_grade', None)
                if event_data.get('max_grade', None) is not None
                and event_data.get('grade', None) is not None else None
            },
            response=response)
    def test_bad_property_init(self):
        with self.assertRaises(AttributeError):
            Result(bad_name=2)

        with self.assertRaises(AttributeError):
            Result({'bad_name': 2})
Beispiel #27
0
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
Beispiel #28
0
 def get_result(self, event):
     return Result(completion=True, success=True)
Beispiel #29
0
def socialmedia_builder(statement_id,
                        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,
                        unit=None,
                        account_email=None,
                        user_name=None,
                        timestamp=None,
                        other_contexts=[]):

    agentaccount = AgentAccount(name=account_name, home_page=account_homepage)
    actor = Agent(account=agentaccount)

    # XAPI statements can only have one of: AgentAccount, mbox, mboxsha1 or Openid
    #if (account_email is not None):
    #    actor.mbox = account_email
    #if (user_name is not None):
    #    actor.name = user_name

    verb_obj = Verb(id=xapi_settings.get_verb_iri(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=xapi_settings.get_object_iri(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=xapi_settings.get_object_iri('Tag')),
        )
        taglist.append(tagobject)

    # Add "other" in contextActivities
    other_contexts_list = []
    for other in other_contexts:
        other_context_obj = Activity(
            id=other['obj_id'],
            object_type=other['obj_type'],
            definition=ActivityDefinition(name=LanguageMap(
                {'en-US': other['definition']['name']}),
                                          type=other['definition']['type']),
        )
        other_contexts_list.append(other_context_obj)
    taglist.extend(other_contexts_list)

    parentlist = []
    if (verb in ['liked', 'shared', 'commented',
                 'rated']):  #recipe specific config
        parentobject = Activity(
            id=parent_id,
            object_type=parent_object_type,
        )
        parentlist.append(parentobject)
    elif (platform == 'GitHub' or platform.lower() == 'trello'):
        parentobject = Activity(
            id=parent_id,
            object_type=parent_object_type,
        )
        parentlist.append(parentobject)

    courselist = []
    if unit is not None:
        courseobject = Activity(
            id="http://adlnet.gov/expapi/activities/course",
            object_type='Course',
            definition=ActivityDefinition(
                name=LanguageMap({'en-US': unit.code}),
                description=LanguageMap({
                    'en-US':
                    "A course/unit of learning hosted on the CLAToolkit"
                })))
        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)))

    # Xapi spec requires that the learning provider SHOULD provide the authority
    # Authority is a group with Agent as oauth consumer app where name is token url and homepage is consumer_key
    account = AgentAccount(name=unit.get_lrs_key(),
                           home_page=unit.get_lrs_access_token_url())

    authority = Group(Agent(account=account))

    statement = statement_builder(statement_id, actor, verb_obj, object,
                                  context, result, authority, timestamp)

    return statement
Beispiel #30
0
 def get_result(self, event):
     event_data = self.get_event_data(event)
     return Result(completion=False, response=json.dumps("[]"))
Beispiel #31
0
 def get_result(self, event):
     event_data = self.get_event_data(event)
     return Result(
         success=event_data.get('success', True),
         completion=True,
     )
Beispiel #32
0
    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST, request.FILES)
        if form.is_valid():
            data = form.cleaned_data
            project = get_object_or_404(Project, id=data['project'])
            user = data['user']

            timezone = pytz.timezone("Europe/Rome")

            actor = Agent(
                name=user.get_display_name(),
                mbox='mailto:%s' % user.email,
            )

            project_id = get_object_id(request, project)

            activity_type = xapi_activities['assessment']['type']
            object_language = 'it'
            verb = Verb(
                id=xapi_verbs['completed']['id'],
                display=LanguageMap(**xapi_verbs['completed']['display']),
            )

            file = request.FILES['file']
            filename = file.name
            extension = filename.split(".")[-1]
            content = file.read()
            records = pyexcel.get_records(file_type=extension,
                                          file_content=content)
            name_dict = records[0]
            keys = name_dict.keys()
            rows = []
            for record in records:
                date_time = record['Ora']
                lesson = record['Lezione']
                course = record['Corso']
                activity = record['Attività']
                duration_seconds = record['Durata (Secondi)']
                response_seconds = record['Tempo medio di risposta (Secondi)']
                score_percent = record['Punteggio (%)']
                questions = record['Domande con risposta']
                correct_answers = record['Risposte corrette']

                timestamp = datetime.strptime(date_time, "%d/%m/%Y %H.%M")
                timestamp = timezone.localize(timestamp)

                object_name = 'EarMaster: {}'.format(activity)
                object_description = 'Esercizio di {} in lezione EarMaster "{}"'.format(
                    activity, lesson)
                activity_definition = ActivityDefinition(
                    name=LanguageMap(**{object_language: object_name}),
                    description=object_description
                    and LanguageMap(**{object_language: object_description})
                    or None,
                    type=activity_type,
                )
                course_id = '{}{}'.format(project_id, slugify(course))
                lesson_id = '{}/{}'.format(course_id, slugify(lesson))
                object = Activity(
                    objectType='Activity',
                    id=lesson_id,
                    definition=activity_definition,
                )
                parent = {
                    'objectType': 'Activity',
                    'id': course_id,
                    'definition': {
                        'type': xapi_activities['course']['type'],
                        'name': {
                            'it': course
                        }
                    }
                }
                grouping = {
                    'objectType': 'Activity',
                    'id': project_id,
                    'definition': {
                        'type':
                        xapi_activities['project']['type'],
                        'name':
                        LanguageMap(**{get_language(project): project.name})
                    }
                }
                context = {
                    'platform': 'EarMaster',
                    'context_activities': {
                        'parent': parent,
                        'grouping': grouping
                    }
                }
                context = Context(**context)

                score_scaled = float(score_percent.replace('%', '')) / 100
                score_max = questions
                score_raw = correct_answers
                score = {
                    'min': 0,
                    'max': score_max,
                    'raw': score_raw,
                    'scaled': score_scaled
                }
                score = Score(**score)
                result = {'duration': duration_seconds, 'score': score}
                result = Result(**result)

                statement = Statement(actor=actor,
                                      verb=verb,
                                      object=object,
                                      context=context,
                                      result=result,
                                      timestamp=timestamp)
                result = send_statement(statement)
            return HttpResponseRedirect('/project/%s/' % project.slug)
        return render(request, self.template_name,
                      {'earmaster_import_results_form': form})