Exemplo n.º 1
0
    def test_on_user_modified(self):
        # no changes provided
        on_user_modified.send(
            current_app._get_current_object(),
            event_name=on_user_modified.name,
            user=self.user
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
        self.assertEqual(statements[0]['verb'], {
            'id': 'http://activitystrea.ms/schema/1.0/update',
            'display': {'en-US': 'updated'}
        })
        self.assertEqual(statements[0]['object'], {
            'id': 'https://localhost:8888/app/#/user/'+self.user.uuid,
            'definition': {'type': 'http://id.tincanapi.com/activitytype/user-profile', 'name': {'en-US': 'user profile'}},
            'objectType': 'Activity'
        })
        self.assertNotIn('result', statements[0])
        self.assertNotIn('context', statements[0])

        # test with changes
        changes = {
            'some_string': 'some_value',
            'some_number': 42,
            'some_dict': {
                'some_string': 'some_value',
                'some_number': 42
            }
        }
        on_user_modified.send(
            current_app._get_current_object(),
            event_name=on_user_modified.name,
            user=self.user,
            data={'changes': changes}
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
        self.assertEqual(statements[0]['verb'], {
            'id': 'http://activitystrea.ms/schema/1.0/update',
            'display': {'en-US': 'updated'}
        })
        self.assertEqual(statements[0]['object'], {
            'id': 'https://localhost:8888/app/#/user/'+self.user.uuid,
            'definition': {'type': 'http://id.tincanapi.com/activitytype/user-profile', 'name': {'en-US': 'user profile'}},
            'objectType': 'Activity'
        })
        self.assertEqual(statements[0]['result'], {
            'extensions': {'http://xapi.learninganalytics.ubc.ca/extension/fields-changed': changes}
        })
        self.assertNotIn('context', statements[0])
Exemplo n.º 2
0
    def test_on_criterion_update(self):
        on_criterion_update.send(
            current_app._get_current_object(),
            event_name=on_criterion_update.name,
            user=self.user,
            criterion=self.criterion,
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 1)

        self.assertEqual(statements[0]["actor"], self.get_compair_actor(self.user))
        self.assertEqual(
            statements[0]["verb"], {"id": "http://activitystrea.ms/schema/1.0/update", "display": {"en-US": "updated"}}
        )
        self.assertEqual(
            statements[0]["object"],
            {
                "id": "https://localhost:8888/app/xapi/criterion/" + self.criterion.uuid,
                "definition": {
                    "type": "http://adlnet.gov/expapi/activities/question",
                    "name": {"en-US": self.criterion.name},
                    "description": {"en-US": self.criterion.description},
                },
                "objectType": "Activity",
            },
        )
        self.assertNotIn("result", statements[0])
        self.assertNotIn("context", statements[0])
Exemplo n.º 3
0
    def file_retrieve(file_type, file_name):
        file_dirs = {
            'attachment': app.config['ATTACHMENT_UPLOAD_FOLDER'],
            'report': app.config['REPORT_FOLDER']
        }
        file_path = '{}/{}'.format(file_dirs[file_type], file_name)

        if not os.path.exists(file_path):
            return make_response('invalid file name', 404)

        # TODO: add bouncer
        mimetype, encoding = mimetypes.guess_type(file_name)
        attachment_filename = None
        as_attachment = False

        if file_type == 'attachment' and mimetype != "application/pdf":
            params = attachment_download_parser.parse_args()
            attachment_filename = params.get('name') #optionally set the download file name
            as_attachment = True

        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=current_user,
            file_type=file_type,
            file_name=file_name,
            data={'file_path': file_path, 'mimetype': mimetype})

        return send_file(file_path, mimetype=mimetype,
            attachment_filename=attachment_filename, as_attachment=as_attachment)
Exemplo n.º 4
0
    def test_on_assignment_delete(self):
        on_assignment_delete.send(
            current_app._get_current_object(),
            event_name=on_assignment_delete.name,
            user=self.user,
            assignment=self.assignment
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 1)

        self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
        self.assertEqual(statements[0]['verb'], {
            'id': 'http://activitystrea.ms/schema/1.0/delete',
            'display': {'en-US': 'deleted'}
        })
        self.assertEqual(statements[0]['object'], {
            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
            'definition': {
                'type': 'http://adlnet.gov/expapi/activities/assessment',
                'name': {'en-US': self.assignment.name },
                'description': {'en-US': self.assignment.description }
            },
            'objectType': 'Activity'
        })
        self.assertNotIn('result', statements[0])
        self.assertEqual(statements[0]['context'], {
            'contextActivities': {
                'parent': [{
                    'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                    'objectType': 'Activity'
                }]
            }
        })
Exemplo n.º 5
0
    def file_retrieve(file_type, file_name):
        file_dirs = {
            'attachment': app.config['ATTACHMENT_UPLOAD_FOLDER'],
            'report': app.config['REPORT_FOLDER']
        }
        file_path = '{}/{}'.format(file_dirs[file_type], file_name)
        params = attachment_download_parser.parse_args()

        if file_type == 'attachment':
            attachment = File.get_by_file_name_or_404(
                file_name,
                joinedloads=['answers', 'assignments']
            )

            for answer in attachment.answers:
                require(READ, answer,
                    title="Attachment Unavailable",
                    message="Sorry, your role does not allow you to view the attachment.")

            for assignment in attachment.assignments:
                require(READ, assignment,
                    title="Attachment Unavailable",
                    message="Sorry, your role does not allow you to view the attachment.")

            # If attachment is in Kaltura, redirect the user
            if attachment.kaltura_media and KalturaAPI.enabled():
                entry_id = attachment.kaltura_media.entry_id
                download_url = attachment.kaltura_media.download_url
                if entry_id:
                    # Short-lived session of 60 seconds for user to start the media download
                    kaltura_url = KalturaAPI.get_direct_access_url(entry_id, download_url, 60)
                    return redirect(kaltura_url)

        if not os.path.exists(file_path):
            return make_response('invalid file name', 404)

        # TODO: add bouncer for reports
        mimetype, encoding = mimetypes.guess_type(file_name)
        attachment_filename = None
        as_attachment = False

        if file_type == 'attachment' and mimetype != "application/pdf":
            attachment_filename = params.get('name') #optionally set the download file name
            as_attachment = True

        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=current_user,
            file_type=file_type,
            file_name=file_name,
            data={'file_path': file_path, 'mimetype': mimetype})

        return send_file(file_path, mimetype=mimetype,
            attachment_filename=attachment_filename, as_attachment=as_attachment)
Exemplo n.º 6
0
    def test_on_answer_flag(self):
        for draft in [True, False]:
            for flagged in [True, False]:
                self.answer.draft = draft
                self.answer.flagged = flagged
                db.session.commit()

                on_answer_flag.send(
                    current_app._get_current_object(),
                    event_name=on_answer_flag.name,
                    user=self.user,
                    answer=self.answer
                )

                statements = self.get_and_clear_statement_log()
                self.assertEqual(len(statements), 1)

                self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))

                if flagged:
                    self.assertEqual(statements[0]['verb'], {
                        'id': 'http://xapi.learninganalytics.ubc.ca/verb/flag',
                        'display': {'en-US': 'flagged'}
                    })
                else:
                    self.assertEqual(statements[0]['verb'], {
                        'id': 'http://xapi.learninganalytics.ubc.ca/verb/unflag',
                        'display': {'en-US': 'unflagged'}
                    })

                self.assertEqual(statements[0]['object'], {
                    'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                    'definition': {'type': 'http://id.tincanapi.com/activitytype/solution', 'name': {'en-US': 'Assignment answer'}},
                    'objectType': 'Activity'
                })
                self.assertNotIn('result', statements[0])
                self.assertEqual(statements[0]['context'], {
                    'contextActivities': {
                        'grouping': [{
                            'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                            'objectType': 'Activity'
                        },{
                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                            'objectType': 'Activity'
                        },],
                        'parent': [{
                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question',
                            'objectType': 'Activity'
                        }]
                    }
                })
Exemplo n.º 7
0
    def test_on_assignment_modified(self):
        on_assignment_modified.send(
            current_app._get_current_object(),
            event_name=on_assignment_modified.name,
            user=self.user,
            assignment=self.assignment
        )

        events = self.get_and_clear_caliper_event_log()
        expected_caliper_event = {
            'action': 'Modified',
            'actor': self.get_compair_caliper_actor(self.user),
            'membership': self.get_caliper_membership(self.course, self.user, self.lti_context),
            'object': self.expected_caliper_assignment,
            'session': self.get_caliper_session(self.get_compair_caliper_actor(self.user)),
            'type': 'Event'
        }

        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], expected_caliper_event)


        statements = self.get_and_clear_xapi_statement_log()
        expected_xapi_statement = {
            "actor": self.get_compair_xapi_actor(self.user),
            "verb": {
                'id': 'http://activitystrea.ms/schema/1.0/update',
                'display': {'en-US': 'updated'}
            },
            "object": self.expected_xapi_assignment,
            "context": {
                'contextActivities': {
                    'parent': [self.expected_xapi_course],
                    'grouping': [self.expected_xapi_sis_course, self.expected_xapi_sis_section]
                },
                'extensions': {
                    'http://id.tincanapi.com/extension/browser-info': {},
                    'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
                }
            }
        }

        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0], expected_xapi_statement)
Exemplo n.º 8
0
def check():
    POST_USERNAME = request.form['username']
    POST_PASSWORD = request.form['password']
    print request.args.get('username')
    if models.User.query.filter_by(username=POST_USERNAME,password=POST_PASSWORD).first():
       global user
       user = models.User.query.filter_by(username=POST_USERNAME,password=POST_PASSWORD).first()
       session['logged_in'] = True
       session['user_name'] = user.username
       session['user_id'] = user.id
       #render_template('index.html',)
       login_user(user)
       identity_changed.send(current_app._get_current_object(),identity=Identity(user.id))
       global path1
       path1 = os.path.join(root,'./static/users/%s/odt/' % session['user_name'])
       return redirect(url_for('index'))
    else:
       flash('wrong password!')
       return redirect(url_for('login'))
    return redirect(url_for('index'))
Exemplo n.º 9
0
    def test_on_answer_delete(self):
        for draft in [True, False]:
            self.answer.draft = draft
            db.session.commit()

            on_answer_delete.send(
                current_app._get_current_object(),
                event_name=on_answer_delete.name,
                user=self.user,
                answer=self.answer
            )

            statements = self.get_and_clear_statement_log()
            self.assertEqual(len(statements), 1)

            self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
            self.assertEqual(statements[0]['verb'], {
                'id': 'http://activitystrea.ms/schema/1.0/delete',
                'display': {'en-US': 'deleted'}
            })
            self.assertEqual(statements[0]['object'], {
                'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                'definition': {'type': 'http://id.tincanapi.com/activitytype/solution', 'name': {'en-US': 'Assignment answer'}},
                'objectType': 'Activity'
            })
            self.assertNotIn('result', statements[0])
            self.assertEqual(statements[0]['context'], {
                'contextActivities': {
                    'grouping': [{
                        'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                        'objectType': 'Activity'
                    },],
                    'parent': [{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question',
                        'objectType': 'Activity'
                    }]
                }
            })
Exemplo n.º 10
0
    def test_on_assignment_comment_modified(self):
        on_assignment_comment_modified.send(
            current_app._get_current_object(),
            event_name=on_assignment_comment_modified.name,
            user=self.user,
            assignment_comment=self.assignment_comment
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 1)

        self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
        self.assertEqual(statements[0]['verb'], {
            'id': 'http://activitystrea.ms/schema/1.0/update',
            'display': {'en-US': 'updated'}
        })
        self.assertEqual(statements[0]['object'], {
            'id': 'https://localhost:8888/app/xapi/assignment/comment/'+self.assignment_comment.uuid,
            'definition': {'type': 'http://activitystrea.ms/schema/1.0/comment', 'name': {'en-US': 'Assignment comment'}},
            'objectType': 'Activity'
        })
        self.assertEqual(statements[0]['result'], {
            'extensions': {
                'http://xapi.learninganalytics.ubc.ca/extension/character-count': len(self.assignment_comment.content),
                'http://xapi.learninganalytics.ubc.ca/extension/word-count': len(self.assignment_comment.content.split(" "))
            },
            'response': self.assignment_comment.content
        })
        self.assertEqual(statements[0]['context'], {
            'contextActivities': {
                'grouping': [{
                    'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                    'objectType': 'Activity'
                }],
                'parent': [{
                    'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                    'objectType': 'Activity'
                }]
            }
        })
Exemplo n.º 11
0
    def test_on_comparison_update(self):
        completed_count = 0

        for (is_comparison_example, comparison) in [(True, self.example_comparison), (False, self.comparison)]:
            for completed in [False, True]:
                comparison.completed = completed
                comparison.winner = WinningAnswer.answer1 if completed else None
                db.session.commit()

                on_comparison_update.send(
                    current_app._get_current_object(),
                    event_name=on_comparison_update.name,
                    user=self.user,
                    assignment=self.assignment,
                    comparison=comparison,
                    is_comparison_example=is_comparison_example
                )

                if completed:
                    completed_count += 1
                current_comparison = completed_count if completed else completed_count + 1
                self.expected_caliper_comparison_question['name'] = "Assignment comparison #"+str(current_comparison)
                self.expected_caliper_comparison_question['id'] = "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/comparison/question/"+str(current_comparison)
                self.expected_xapi_comparison_question['definition']['name']['en-US'] = "Assignment comparison #{}".format(current_comparison)
                self.expected_xapi_comparison_question['id'] = "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/comparison/question/"+str(current_comparison)

                expected_caliper_comparison_attempt = {
                    'assignable': self.expected_caliper_comparison_question,
                    'assignee': self.get_compair_caliper_actor(self.user),
                    'id': "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/comparison/question/"+str(current_comparison)+"/attempt/"+comparison.attempt_uuid,
                    'duration': "PT05M00S",
                    'startedAtTime': comparison.attempt_started.replace(tzinfo=pytz.utc).isoformat(),
                    'endedAtTime': comparison.attempt_ended.replace(tzinfo=pytz.utc).isoformat(),
                    'type': 'Attempt'
                }

                expected_caliper_comparison = {
                    'attempt': expected_caliper_comparison_attempt,
                    'id': "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/comparison/"+comparison.uuid,
                    'type': 'Response',
                    'dateCreated': comparison.created.replace(tzinfo=pytz.utc).isoformat(),
                    'dateModified': comparison.modified.replace(tzinfo=pytz.utc).isoformat(),
                    'extensions': {
                        'pairingAlgorithm': self.comparison.pairing_algorithm.value,
                        'winner': "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/answer/"+self.answer1.uuid if completed else "Undecided",
                        'criteria': {
                            "https://localhost:8888/app/criterion/"+self.criterion.uuid: "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/answer/"+self.answer1.uuid,
                        },
                        "answers": [
                            "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/answer/"+self.answer1.uuid,
                            "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/answer/"+self.answer2.uuid,
                        ],
                        "completed": completed
                    }
                }

                events = self.get_and_clear_caliper_event_log()
                expected_caliper_events = [{
                    'action': 'Completed',
                    'actor': self.get_compair_caliper_actor(self.user),
                    'membership': self.get_caliper_membership(self.course, self.user, self.lti_context),
                    'object': self.expected_caliper_comparison_question,
                    'generated': expected_caliper_comparison,
                    'session': self.get_caliper_session(self.get_compair_caliper_actor(self.user)),
                    'type': 'AssessmentItemEvent'
                }, {
                    'action': 'Submitted',
                    'actor': self.get_compair_caliper_actor(self.user),
                    'membership': self.get_caliper_membership(self.course, self.user, self.lti_context),
                    'object': self.expected_caliper_assignment,
                    'generated': {
                        'assignable': self.expected_caliper_assignment,
                        'assignee': self.get_compair_caliper_actor(self.user),
                        'id': "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/attempt/"+comparison.attempt_uuid,
                        'duration': "PT05M00S",
                        'startedAtTime': comparison.attempt_started.replace(tzinfo=pytz.utc).isoformat(),
                        'endedAtTime': comparison.attempt_ended.replace(tzinfo=pytz.utc).isoformat(),
                        'type': 'Attempt'
                    },
                    'session': self.get_caliper_session(self.get_compair_caliper_actor(self.user)),
                    'type': 'AssessmentEvent'
                }]

                if not is_comparison_example and completed:
                    expected_caliper_events.append({
                        'action': 'Ranked',
                        'actor': self.get_compair_caliper_actor(self.user),
                        'membership': self.get_caliper_membership(self.course, self.user, self.lti_context),
                        'object': self.expected_caliper_answer1,
                        'session': self.get_caliper_session(self.get_compair_caliper_actor(self.user)),
                        'type': 'Event'
                    })
                    expected_caliper_events.append({
                        'action': 'Ranked',
                        'actor': self.get_compair_caliper_actor(self.user),
                        'membership': self.get_caliper_membership(self.course, self.user, self.lti_context),
                        'object': self.expected_caliper_answer2,
                        'session': self.get_caliper_session(self.get_compair_caliper_actor(self.user)),
                        'type': 'Event'
                    })

                self.assertEqual(len(events), len(expected_caliper_events))
                for index, expected_event in enumerate(expected_caliper_events):
                    self.assertEqual(events[index], expected_event)

                expected_xapi_comparison_attempt = {
                    'id': "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/comparison/question/"+str(current_comparison)+"/attempt/"+comparison.attempt_uuid,
                    'definition': {
                        'type': 'http://adlnet.gov/expapi/activities/attempt',
                        'extensions': {
                            'http://id.tincanapi.com/extension/attempt': {
                                'duration': "PT05M00S",
                                'startedAtTime': comparison.attempt_started.replace(tzinfo=pytz.utc).isoformat(),
                                'endedAtTime': comparison.attempt_ended.replace(tzinfo=pytz.utc).isoformat(),
                            }
                        }
                    },
                    'objectType': 'Activity'
                }

                expected_xapi_comparison = {
                    'id': "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/comparison/"+comparison.uuid,
                    'definition': {
                        'type': 'http://id.tincanapi.com/activitytype/solution',
                        'name': { 'en-US': "Assignment comparison" },
                        'extensions': {
                            'http://id.tincanapi.com/extension/completed': completed
                        }
                    },
                    'objectType': 'Activity'
                }


                statements = self.get_and_clear_xapi_statement_log()
                expected_xapi_statements = [{
                    "actor": self.get_compair_xapi_actor(self.user),
                    "verb": {
                        'id': 'http://adlnet.gov/expapi/verbs/completed',
                        'display': {'en-US': 'completed'}
                    },
                    "object": expected_xapi_comparison,
                    "context": {
                        'registration': comparison.attempt_uuid,
                        'contextActivities': {
                            'parent': [self.expected_xapi_comparison_question, self.expected_xapi_answer1, self.expected_xapi_answer2, expected_xapi_comparison_attempt],
                            'grouping': [self.expected_xapi_assignment, self.expected_xapi_course, self.expected_xapi_sis_course, self.expected_xapi_sis_section]
                        },
                        'extensions': {
                            'http://id.tincanapi.com/extension/browser-info': {},
                            'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
                        }
                    },
                    "result": {
                        'success': True,
                        'duration': "PT05M00S",
                        'completion': completed,
                        'response': "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/answer/"+self.answer1.uuid if completed else "Undecided",
                        'extensions': {
                            'http://xapi.learninganalytics.ubc.ca/extension/criteria': {
                                "https://localhost:8888/app/criterion/"+self.criterion.uuid: "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/answer/"+self.answer1.uuid,
                            }
                        }
                    }
                }, {
                    "actor": self.get_compair_xapi_actor(self.user),
                    "verb": {
                        'id': 'http://activitystrea.ms/schema/1.0/submit',
                        'display': {'en-US': 'submitted'}
                    },
                    "object": {
                        'id': "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/attempt/"+comparison.attempt_uuid,
                        'definition': {
                            'type': 'http://adlnet.gov/expapi/activities/attempt',
                            'extensions': {
                                'http://id.tincanapi.com/extension/attempt': {
                                    'duration': "PT05M00S",
                                    'startedAtTime': comparison.attempt_started.replace(tzinfo=pytz.utc).isoformat(),
                                    'endedAtTime': comparison.attempt_ended.replace(tzinfo=pytz.utc).isoformat(),
                                }
                            }
                        },
                        'objectType': 'Activity'
                    },
                    "context": {
                        'registration': comparison.attempt_uuid,
                        'contextActivities': {
                            'parent': [self.expected_xapi_assignment],
                            'grouping': [self.expected_xapi_course, self.expected_xapi_sis_course, self.expected_xapi_sis_section]
                        },
                        'extensions': {
                            'http://id.tincanapi.com/extension/browser-info': {},
                            'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
                        }
                    },
                    "result": {
                        'success': True,
                        'completion': completed
                    }
                }]

                if not is_comparison_example and completed:
                    expected_xapi_statements.append({
                        "actor": self.get_compair_xapi_actor(self.user),
                        "verb": {
                            'id': 'https://w3id.org/xapi/dod-isd/verbs/ranked',
                            'display': {'en-US': 'ranked'}
                        },
                        "object": self.expected_xapi_answer1,
                        "context": {
                            'registration': comparison.attempt_uuid,
                            'contextActivities': {
                                'parent': [self.expected_xapi_assignment_question, self.expected_xapi_answer1_attempt],
                                'grouping': [self.expected_xapi_assignment, self.expected_xapi_course, self.expected_xapi_sis_course, self.expected_xapi_sis_section]
                            },
                            'extensions': {
                                'http://id.tincanapi.com/extension/browser-info': {},
                                'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
                            }
                        },
                        "result": {
                            'score': {'raw': 5.0},
                            'extensions': {
                                'http://xapi.learninganalytics.ubc.ca/extension/score-details': {
                                    'algorithm': self.assignment.scoring_algorithm.value,
                                    'loses': 0,
                                    'opponents': 0,
                                    'rounds': 0,
                                    'score': 5,
                                    'wins': 0,
                                    'criteria': {
                                        "https://localhost:8888/app/criterion/"+self.criterion.uuid: {
                                            'loses': 0,
                                            'opponents': 0,
                                            'rounds': 0,
                                            'score': 5,
                                            'wins': 0
                                        },
                                    }
                                }
                            }
                        }
                    })
                    expected_xapi_statements.append({
                        "actor": self.get_compair_xapi_actor(self.user),
                        "verb": {
                            'id': 'https://w3id.org/xapi/dod-isd/verbs/ranked',
                            'display': {'en-US': 'ranked'}
                        },
                        "object": self.expected_xapi_answer2,
                        "context": {
                            'registration': comparison.attempt_uuid,
                            'contextActivities': {
                                'parent': [self.expected_xapi_assignment_question, self.expected_xapi_answer2_attempt],
                                'grouping': [self.expected_xapi_assignment, self.expected_xapi_course, self.expected_xapi_sis_course, self.expected_xapi_sis_section]
                            },
                            'extensions': {
                                'http://id.tincanapi.com/extension/browser-info': {},
                                'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
                            }
                        },
                        "result": {
                            'score': {'raw': 5.0},
                            'extensions': {
                                'http://xapi.learninganalytics.ubc.ca/extension/score-details': {
                                    'algorithm': self.assignment.scoring_algorithm.value,
                                    'loses': 0,
                                    'opponents': 0,
                                    'rounds': 0,
                                    'score': 5,
                                    'wins': 0,
                                    'criteria': {
                                        "https://localhost:8888/app/criterion/"+self.criterion.uuid: {
                                            'loses': 0,
                                            'opponents': 0,
                                            'rounds': 0,
                                            'score': 5,
                                            'wins': 0
                                        },
                                    }
                                }
                            }
                        }
                    })

                self.assertEqual(len(statements), len(expected_xapi_statements))
                for index, expected_statement in enumerate(expected_xapi_statements):
                    self.assertEqual(statements[index], expected_statement)
Exemplo n.º 12
0
    def test_on_comparison_update(self):
        completed_count = 0

        for (is_comparison_example, comparisons) in [(True, self.example_comparisons), (False, self.comparisons)]:
            answer_uuids = [comparisons[0].answer1_uuid, comparisons[0].answer2_uuid]
            answer_uuids.sort()

            for completed in [False, True]:
                for comparison in comparisons:
                    comparison.completed = completed
                db.session.commit()
                if completed:
                    completed_count+=1

                # test without tracking
                on_comparison_update.send(
                    current_app._get_current_object(),
                    event_name=on_comparison_update.name,
                    user=self.user,
                    assignment=self.assignment,
                    comparisons=comparisons,
                    is_comparison_example=is_comparison_example
                )

                statements = self.get_and_clear_statement_log()
                if completed and not is_comparison_example:
                    self.assertEqual(len(statements), len(comparisons) + 1 + (2*len(comparisons)))
                else:
                    self.assertEqual(len(statements), len(comparisons) + 1)

                index = 0
                for comparison in comparisons:
                    self.assertEqual(statements[index]['actor'], self.get_compair_actor(self.user))
                    if completed:
                        self.assertEqual(statements[index]['verb'], {
                            'id': 'http://activitystrea.ms/schema/1.0/submit',
                            'display': {'en-US': 'submitted'}
                        })
                    else:
                        self.assertEqual(statements[index]['verb'], {
                            'id': 'http://xapi.learninganalytics.ubc.ca/verb/draft',
                            'display': {'en-US': 'drafted'}
                        })
                    self.assertEqual(statements[index]['object'], {
                        'id': 'https://localhost:8888/app/xapi/comparison/'+comparison.uuid,
                        'definition': {
                            'type': 'http://id.tincanapi.com/activitytype/solution',
                            'name': {'en-US': 'Assignment criteria comparison' }
                        },
                        'objectType': 'Activity'
                    })
                    if completed:
                        self.assertEqual(statements[index]['result'], {
                            'response': 'https://localhost:8888/app/xapi/answer/'+comparison.winner_uuid,
                            'success': True
                        })
                    else:
                        self.assertEqual(statements[index]['result'], {
                            'response': 'https://localhost:8888/app/xapi/answer/'+comparison.winner_uuid
                        })
                    self.assertEqual(statements[index]['context'], {
                        'contextActivities': {
                            'grouping': [{
                                'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                                'objectType': 'Activity'
                            },{
                                'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                                'objectType': 'Activity'
                            },{
                                'id': 'https://localhost:8888/app/xapi/answer/'+comparison.answer1_uuid,
                                'objectType': 'Activity'
                            },{
                                'id': 'https://localhost:8888/app/xapi/answer/'+comparison.answer2_uuid,
                                'objectType': 'Activity'
                            }],
                            'parent': [{
                                'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/comparison?pair='+answer_uuids[0]+','+answer_uuids[1],
                                'objectType': 'Activity'
                            },{
                                'id': 'https://localhost:8888/app/xapi/criterion/'+comparison.criterion_uuid,
                                'objectType': 'Activity'
                            }]
                        }
                    })

                    index+=1

                self.assertEqual(statements[index]['actor'], self.get_compair_actor(self.user))
                if completed:
                    self.assertEqual(statements[index]['verb'], {
                        'id': 'http://adlnet.gov/expapi/verbs/completed',
                        'display': {'en-US': 'completed'}
                    })
                else:
                    self.assertEqual(statements[index]['verb'], {
                        'id': 'http://adlnet.gov/expapi/verbs/suspended',
                        'display': {'en-US': 'suspended'}
                    })
                self.assertEqual(statements[index]['object'], {
                    'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/comparison?pair='+answer_uuids[0]+','+answer_uuids[1],
                    'definition': {
                        'type': 'http://adlnet.gov/expapi/activities/question',
                        'name': {'en-US': 'Assignment comparison #'+str(completed_count+1) },
                        'extensions': {
                            'http://xapi.learninganalytics.ubc.ca/extension/comparison': completed_count+1,
                            'http://xapi.learninganalytics.ubc.ca/extension/score-algorithm': PairingAlgorithm.random.value
                        }
                    },
                    'objectType': 'Activity'
                })
                self.assertEqual(statements[index]['result'], {
                    'completion': completed,
                    'success': True
                })

                grouping = [{
                    'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                    'objectType': 'Activity'
                }]
                for comparison in comparisons:
                    grouping.append({
                        'id': 'https://localhost:8888/app/xapi/criterion/'+comparison.criterion_uuid,
                        'objectType': 'Activity'
                    })
                self.assertEqual(statements[index]['context'], {
                    'contextActivities': {
                        'grouping': grouping,
                        'parent': [{
                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                            'objectType': 'Activity'
                        },{
                            'id': 'https://localhost:8888/app/xapi/answer/'+comparisons[0].answer1_uuid,
                            'objectType': 'Activity'
                        },{
                            'id': 'https://localhost:8888/app/xapi/answer/'+comparisons[0].answer2_uuid,
                            'objectType': 'Activity'
                        }]
                    }
                })
                index+=1

                if completed and not is_comparison_example:
                    for answer in [self.answer1, self.answer2]:
                        for score in answer.scores:
                            comparison = next(comparison for comparison in comparisons \
                                if comparison.criterion_id == score.criterion_id)

                            self.assertEqual(statements[index]['actor'], self.get_compair_actor(self.user))
                            self.assertEqual(statements[index]['verb'], {
                                'id': 'http://www.tincanapi.co.uk/verbs/evaluated',
                                'display': {'en-US': 'evaluated'}
                            })
                            self.assertEqual(statements[index]['object'], {
                                'id': 'https://localhost:8888/app/xapi/answer/'+answer.uuid+'?criterion='+score.criterion_uuid,
                                'definition': {
                                    'type': 'http://id.tincanapi.com/activitytype/solution',
                                    'name': {'en-US': 'Assignment answer based on criterion' }
                                },
                                'objectType': 'Activity'
                            })
                            self.assertEqual(statements[index]['result'], {
                                'score': { 'raw': float(score.score) },
                                'extensions': {
                                    'http://xapi.learninganalytics.ubc.ca/extension/score-details': {
                                        'algorithm': score.scoring_algorithm.value,
                                        'loses': score.loses,
                                        'opponents': score.opponents,
                                        'rounds': score.rounds,
                                        'wins': score.wins,
                                    }
                                }
                            })
                            self.assertEqual(statements[index]['context'], {
                                'contextActivities': {
                                    'grouping': [{
                                        'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                                        'objectType': 'Activity'
                                    },{
                                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                                        'objectType': 'Activity'
                                    },{
                                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question',
                                        'objectType': 'Activity'
                                    }],
                                    'other': [{
                                        'id': 'https://localhost:8888/app/xapi/comparison/'+comparison.uuid,
                                        'objectType': 'Activity'
                                    },{
                                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/comparison?pair='+answer_uuids[0]+','+answer_uuids[1],
                                        'objectType': 'Activity'
                                    }],
                                    'parent': [{
                                        'id': 'https://localhost:8888/app/xapi/answer/'+answer.uuid,
                                        'objectType': 'Activity'
                                    },{
                                        'id': 'https://localhost:8888/app/xapi/criterion/'+score.criterion_uuid,
                                        'objectType': 'Activity'
                                    }]
                                }
                            })
                            index+=1


                # test with tracking
                tracking = self.generate_tracking(with_duration=True)
                tracking_json = json.dumps({ 'tracking':  tracking })
                with self.app.test_request_context(content_type='application/json', method='POST',
                        content_length=len(tracking_json), data=tracking_json):

                    on_comparison_update.send(
                        current_app._get_current_object(),
                        event_name=on_comparison_update.name,
                        user=self.user,
                        assignment=self.assignment,
                        comparisons=comparisons,
                        is_comparison_example=is_comparison_example
                    )

                    tracking_statements = self.get_and_clear_statement_log()
                    self.assertEqual(len(statements), len(tracking_statements))

                    index = 0
                    for comparison in comparisons:
                        self.assertEqual(statements[index]['actor'], tracking_statements[index]['actor'])
                        self.assertEqual(statements[index]['verb'], tracking_statements[index]['verb'])
                        self.assertEqual(statements[index]['object'], tracking_statements[index]['object'])
                        self.assertEqual(statements[index]['result'], tracking_statements[index]['result'])
                        self.assertEqual(tracking_statements[index]['context'], {
                            'registration': tracking.get('registration'),
                            'contextActivities': {
                                'grouping': [{
                                    'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                                    'objectType': 'Activity'
                                },{
                                    'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                                    'objectType': 'Activity'
                                },{
                                    'id': 'https://localhost:8888/app/xapi/answer/'+comparison.answer1_uuid,
                                    'objectType': 'Activity'
                                },{
                                    'id': 'https://localhost:8888/app/xapi/answer/'+comparison.answer2_uuid,
                                    'objectType': 'Activity'
                                }],
                                'parent': [{
                                    'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/comparison?pair='+answer_uuids[0]+','+answer_uuids[1],
                                    'objectType': 'Activity'
                                },{
                                    'id': 'https://localhost:8888/app/xapi/criterion/'+comparison.criterion_uuid,
                                    'objectType': 'Activity'
                                }]
                            }
                        })

                        index+=1

                    self.assertEqual(statements[index]['actor'], tracking_statements[index]['actor'])
                    self.assertEqual(statements[index]['verb'], tracking_statements[index]['verb'])
                    self.assertEqual(statements[index]['object'], tracking_statements[index]['object'])
                    self.assertEqual(tracking_statements[index]['result'], {
                        'completion': completed,
                        'duration': tracking.get('duration'),
                        'success': True
                    })
                    self.assertEqual(tracking_statements[index]['context'], {
                        'registration': tracking.get('registration'),
                        'contextActivities': {
                            'grouping': grouping,
                            'parent': [{
                                'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                                'objectType': 'Activity'
                            },{
                                'id': 'https://localhost:8888/app/xapi/answer/'+comparisons[0].answer1_uuid,
                                'objectType': 'Activity'
                            },{
                                'id': 'https://localhost:8888/app/xapi/answer/'+comparisons[0].answer2_uuid,
                                'objectType': 'Activity'
                            }]
                        }
                    })
                    index+=1

                    if completed and not is_comparison_example:
                        for answer in [self.answer1, self.answer2]:
                            for score in answer.scores:
                                comparison = next(comparison for comparison in comparisons \
                                    if comparison.criterion_id == score.criterion_id)

                                self.assertEqual(statements[index]['actor'], tracking_statements[index]['actor'])
                                self.assertEqual(statements[index]['verb'], tracking_statements[index]['verb'])
                                self.assertEqual(statements[index]['object'], tracking_statements[index]['object'])
                                self.assertEqual(statements[index]['result'], tracking_statements[index]['result'])
                                self.assertEqual(tracking_statements[index]['context'], {
                                    'registration': tracking.get('registration'),
                                    'contextActivities': {
                                        'grouping': [{
                                            'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                                            'objectType': 'Activity'
                                        },{
                                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                                            'objectType': 'Activity'
                                        },{
                                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question',
                                            'objectType': 'Activity'
                                        }],
                                        'other': [{
                                            'id': 'https://localhost:8888/app/xapi/comparison/'+comparison.uuid,
                                            'objectType': 'Activity'
                                        },{
                                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/comparison?pair='+answer_uuids[0]+','+answer_uuids[1],
                                            'objectType': 'Activity'
                                        }],
                                        'parent': [{
                                            'id': 'https://localhost:8888/app/xapi/answer/'+answer.uuid,
                                            'objectType': 'Activity'
                                        },{
                                            'id': 'https://localhost:8888/app/xapi/criterion/'+score.criterion_uuid,
                                            'objectType': 'Activity'
                                        }]
                                    }
                                })
                                index+=1
Exemplo n.º 13
0
    def test_on_answer_comment_create(self):
        # test self_evaluation_comment
        on_answer_comment_create.send(
            current_app._get_current_object(),
            event_name=on_answer_comment_create.name,
            user=self.user,
            answer_comment=self.self_evaluation_comment
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 0)

        # test evaluation_comment
        on_answer_comment_create.send(
            current_app._get_current_object(),
            event_name=on_answer_comment_create.name,
            user=self.user,
            answer_comment=self.evaluation_comment
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 0)

        # test public_comment/private_comment
        for comment in [self.public_comment, self.private_comment]:
            on_answer_comment_create.send(
                current_app._get_current_object(),
                event_name=on_answer_comment_create.name,
                user=self.user,
                answer_comment=comment
            )

            statements = self.get_and_clear_statement_log()
            self.assertEqual(len(statements), 1)
            self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
            self.assertEqual(statements[0]['verb'], {
                'id': 'http://adlnet.gov/expapi/verbs/commented',
                'display': {'en-US': 'commented'}
            })
            self.assertEqual(statements[0]['object'], {
                'id': 'https://localhost:8888/app/xapi/answer/comment/'+comment.uuid,
                'definition': {'type': 'http://activitystrea.ms/schema/1.0/comment', 'name': {'en-US': 'Assignment answer comment'}},
                'objectType': 'Activity'
            })
            self.assertEqual(statements[0]['result'], {
                'extensions': {
                    'http://xapi.learninganalytics.ubc.ca/extension/character-count': len(comment.content),
                    'http://xapi.learninganalytics.ubc.ca/extension/word-count': len(comment.content.split(" "))
                },
                'response': comment.content
            })
            self.assertEqual(statements[0]['context'], {
                'contextActivities': {
                    'grouping': [{
                        'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question',
                        'objectType': 'Activity'
                    }],
                    'parent': [{
                        'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                        'objectType': 'Activity'
                    }]
                }
            })
Exemplo n.º 14
0
    def test_on_answer_comment_delete(self):
        # test self_evaluation_comment
        on_answer_comment_delete.send(
            current_app._get_current_object(),
            event_name=on_answer_comment_delete.name,
            user=self.user,
            answer_comment=self.self_evaluation_comment
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
        self.assertEqual(statements[0]['verb'], {
            'id': 'http://activitystrea.ms/schema/1.0/delete',
            'display': {'en-US': 'deleted'}
        })
        self.assertEqual(statements[0]['object'], {
            'id': 'https://localhost:8888/app/xapi/answer/comment/'+self.self_evaluation_comment.uuid,
            'definition': {'type': 'http://activitystrea.ms/schema/1.0/review', 'name': {'en-US': 'Assignment self-evaluation review'}},
            'objectType': 'Activity'
        })
        self.assertNotIn('result', statements[0])
        self.assertEqual(statements[0]['context'], {
            'contextActivities': {
                'grouping': [{
                    'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                    'objectType': 'Activity'
                },{
                    'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                    'objectType': 'Activity'
                },{
                    'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                    'objectType': 'Activity'
                }],
                'parent': [{
                    'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/self-evaluation',
                    'objectType': 'Activity'
                }]
            }
        })

        # test evaluation_comment
        on_answer_comment_delete.send(
            current_app._get_current_object(),
            event_name=on_answer_comment_delete.name,
            user=self.user,
            answer_comment=self.evaluation_comment
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
        self.assertEqual(statements[0]['verb'], {
            'id': 'http://activitystrea.ms/schema/1.0/delete',
            'display': {'en-US': 'deleted'}
        })
        self.assertEqual(statements[0]['object'], {
            'id': 'https://localhost:8888/app/xapi/answer/comment/'+self.evaluation_comment.uuid,
            'definition': {'type': 'http://activitystrea.ms/schema/1.0/comment', 'name': {'en-US': 'Assignment answer evaluation comment'}},
            'objectType': 'Activity'
        })
        self.assertNotIn('result', statements[0])
        self.assertEqual(statements[0]['context'], {
            'contextActivities': {
                'grouping': [{
                    'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                    'objectType': 'Activity'
                },{
                    'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                    'objectType': 'Activity'
                },{
                    'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question',
                    'objectType': 'Activity'
                }],
                'parent': [{
                    'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                    'objectType': 'Activity'
                }]
            }
        })


        # test public_comment/private_comment
        for comment in [self.public_comment, self.private_comment]:
            on_answer_comment_delete.send(
                current_app._get_current_object(),
                event_name=on_answer_comment_delete.name,
                user=self.user,
                answer_comment=comment
            )

            statements = self.get_and_clear_statement_log()
            self.assertEqual(len(statements), 1)
            self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
            self.assertEqual(statements[0]['verb'], {
                'id': 'http://activitystrea.ms/schema/1.0/delete',
                'display': {'en-US': 'deleted'}
            })
            self.assertEqual(statements[0]['object'], {
                'id': 'https://localhost:8888/app/xapi/answer/comment/'+comment.uuid,
                'definition': {'type': 'http://activitystrea.ms/schema/1.0/comment', 'name': {'en-US': 'Assignment answer comment'}},
                'objectType': 'Activity'
            })
            self.assertNotIn('result', statements[0])
            self.assertEqual(statements[0]['context'], {
                'contextActivities': {
                    'grouping': [{
                        'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question',
                        'objectType': 'Activity'
                    }],
                    'parent': [{
                        'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                        'objectType': 'Activity'
                    }]
                }
            })
Exemplo n.º 15
0
    def test_on_answer_modified(self):
        for draft in [True, False]:
            self.answer.draft = draft
            db.session.commit()

            self.expected_xapi_answer['definition']['extensions']['http://id.tincanapi.com/extension/isDraft'] = draft
            self.expected_caliper_answer['extensions']['isDraft'] = draft
            self.expected_caliper_answer['dateModified'] = self.answer.modified.replace(tzinfo=pytz.utc).isoformat()

            # test without tracking
            on_answer_modified.send(
                current_app._get_current_object(),
                event_name=on_answer_modified.name,
                user=self.user,
                answer=self.answer
            )

            events = self.get_and_clear_caliper_event_log()
            expected_caliper_events = [{
                'action': 'Completed',
                'actor': self.get_compair_caliper_actor(self.user),
                'membership': self.get_caliper_membership(self.course, self.user, self.lti_context),
                'object': self.expected_caliper_assignment_question,
                'generated': self.expected_caliper_answer,
                'session': self.get_caliper_session(self.get_compair_caliper_actor(self.user)),
                'type': 'AssessmentItemEvent'
            }, {
                'action': 'Submitted',
                'actor': self.get_compair_caliper_actor(self.user),
                'membership': self.get_caliper_membership(self.course, self.user, self.lti_context),
                'object': self.expected_caliper_assignment,
                'generated': {
                    'assignable': self.expected_caliper_assignment,
                    'assignee': self.get_compair_caliper_actor(self.user),
                    'id': "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/attempt/"+self.answer.attempt_uuid,
                    'duration': "PT05M00S",
                    'startedAtTime': self.answer.attempt_started.replace(tzinfo=pytz.utc).isoformat(),
                    'endedAtTime': self.answer.attempt_ended.replace(tzinfo=pytz.utc).isoformat(),
                    'type': 'Attempt'
                },
                'session': self.get_caliper_session(self.get_compair_caliper_actor(self.user)),
                'type': 'AssessmentEvent'
            }]

            self.assertEqual(len(events), len(expected_caliper_events))
            for index, expected_event in enumerate(expected_caliper_events):
                self.assertEqual(events[index], expected_event)


            statements = self.get_and_clear_xapi_statement_log()
            expected_xapi_statements = [{
                "actor": self.get_compair_xapi_actor(self.user),
                "verb": {
                    'id': 'http://adlnet.gov/expapi/verbs/completed',
                    'display': {'en-US': 'completed'}
                },
                "object": self.expected_xapi_answer,
                "context": {
                    'registration': self.answer.attempt_uuid,
                    'contextActivities': {
                        'parent': [self.expected_xapi_assignment_question, self.expected_xapi_answer_attempt],
                        'grouping': [self.expected_xapi_assignment, self.expected_xapi_course, self.expected_xapi_sis_course, self.expected_xapi_sis_section]
                    },
                    'extensions': {
                        'http://id.tincanapi.com/extension/browser-info': {},
                        'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
                    }
                },
                "result": {
                    'success': True,
                    'duration': "PT05M00S",
                    'completion': not draft,
                    'response': self.answer.content,
                    'extensions': {
                        'http://xapi.learninganalytics.ubc.ca/extension/character-count': len(self.answer.content),
                        'http://xapi.learninganalytics.ubc.ca/extension/word-count': len(self.answer.content.split(" "))
                    }
                }
            }, {
                "actor": self.get_compair_xapi_actor(self.user),
                "verb": {
                    'id': 'http://activitystrea.ms/schema/1.0/submit',
                    'display': {'en-US': 'submitted'}
                },
                "object": {
                    'id': "https://localhost:8888/app/course/"+self.course.uuid+"/assignment/"+self.assignment.uuid+"/attempt/"+self.answer.attempt_uuid,
                    'definition': {
                        'type': 'http://adlnet.gov/expapi/activities/attempt',
                        'extensions': {
                            'http://id.tincanapi.com/extension/attempt': {
                                'duration': "PT05M00S",
                                'startedAtTime': self.answer.attempt_started.replace(tzinfo=pytz.utc).isoformat(),
                                'endedAtTime': self.answer.attempt_ended.replace(tzinfo=pytz.utc).isoformat(),
                            }
                        }
                    },
                    'objectType': 'Activity'
                },
                "context": {
                    'registration': self.answer.attempt_uuid,
                    'contextActivities': {
                        'parent': [self.expected_xapi_assignment],
                        'grouping': [self.expected_xapi_course, self.expected_xapi_sis_course, self.expected_xapi_sis_section]
                    },
                    'extensions': {
                        'http://id.tincanapi.com/extension/browser-info': {},
                        'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
                    }
                },
                "result": {
                    'success': True,
                    'completion': not draft
                }
            }]

            self.assertEqual(len(statements), len(expected_xapi_statements))
            for index, expected_statement in enumerate(expected_xapi_statements):
                self.assertEqual(statements[index], expected_statement)
Exemplo n.º 16
0
    def test_on_answer_comment_modified(self):
        for draft in [True, False]:
            self.self_evaluation_comment.draft = draft
            db.session.commit()

            # test self_evaluation_comment without tracking
            on_answer_comment_modified.send(
                current_app._get_current_object(),
                event_name=on_answer_comment_modified.name,
                user=self.user,
                answer_comment=self.self_evaluation_comment
            )

            statements = self.get_and_clear_statement_log()
            self.assertEqual(len(statements), 2)
            self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))

            if draft:
                self.assertEqual(statements[0]['verb'], {
                    'id': 'http://xapi.learninganalytics.ubc.ca/verb/draft',
                    'display': {'en-US': 'drafted'}
                })
            else:
                self.assertEqual(statements[0]['verb'], {
                    'id': 'http://activitystrea.ms/schema/1.0/submit',
                    'display': {'en-US': 'submitted'}
                })

            self.assertEqual(statements[0]['object'], {
                'id': 'https://localhost:8888/app/xapi/answer/comment/'+self.self_evaluation_comment.uuid,
                'definition': {'type': 'http://activitystrea.ms/schema/1.0/review', 'name': {'en-US': 'Assignment self-evaluation review'}},
                'objectType': 'Activity'
            })
            if draft:
                self.assertEqual(statements[0]['result'], {
                    'extensions': {
                        'http://xapi.learninganalytics.ubc.ca/extension/character-count': len(self.self_evaluation_comment.content),
                        'http://xapi.learninganalytics.ubc.ca/extension/word-count': len(self.self_evaluation_comment.content.split(" "))
                    },
                    'response': self.self_evaluation_comment.content
                })
            else:
                self.assertEqual(statements[0]['result'], {
                    'extensions': {
                        'http://xapi.learninganalytics.ubc.ca/extension/character-count': len(self.self_evaluation_comment.content),
                        'http://xapi.learninganalytics.ubc.ca/extension/word-count': len(self.self_evaluation_comment.content.split(" "))
                    },
                    'response': self.self_evaluation_comment.content,
                    'success': True
                })

            self.assertEqual(statements[0]['context'], {
                'contextActivities': {
                    'grouping': [{
                        'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                        'objectType': 'Activity'
                    }],
                    'parent': [{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/self-evaluation',
                        'objectType': 'Activity'
                    }]
                }
            })

            self.assertEqual(statements[1]['actor'], self.get_compair_actor(self.user))
            if draft:
                self.assertEqual(statements[1]['verb'], {
                    'id': 'http://adlnet.gov/expapi/verbs/suspended',
                    'display': {'en-US': 'suspended'}
                })
            else:
                self.assertEqual(statements[1]['verb'], {
                    'id': 'http://adlnet.gov/expapi/verbs/completed',
                    'display': {'en-US': 'completed'}
                })

            self.assertEqual(statements[1]['object'], {
                'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/self-evaluation',
                'definition': {'type': 'http://adlnet.gov/expapi/activities/question', 'name': {'en-US': 'Assignment self-evaluation'}},
                'objectType': 'Activity'
            })
            self.assertEqual(statements[1]['result'], {
                'completion': not draft,
                'success': True
            })
            self.assertEqual(statements[1]['context'], {
                'contextActivities': {
                    'grouping': [{
                        'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                        'objectType': 'Activity'
                    }],
                    'parent': [{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                        'objectType': 'Activity'
                    }]
                }
            })

            # test self_evaluation_comment with tracking
            tracking = self.generate_tracking(with_duration=True)
            tracking_json = json.dumps({ 'tracking':  tracking })
            with self.app.test_request_context(content_type='application/json', method='POST',
                    content_length=len(tracking_json), data=tracking_json):
                on_answer_comment_modified.send(
                    current_app._get_current_object(),
                    event_name=on_answer_comment_modified.name,
                    user=self.user,
                    answer_comment=self.self_evaluation_comment
                )

                tracking_statements = self.get_and_clear_statement_log()
                self.assertEqual(len(statements), 2)
                self.assertEqual(statements[0]['actor'], tracking_statements[0]['actor'])
                self.assertEqual(statements[0]['verb'], tracking_statements[0]['verb'])
                self.assertEqual(statements[0]['object'], tracking_statements[0]['object'])
                self.assertEqual(statements[0]['result'], tracking_statements[0]['result'])
                self.assertEqual(tracking_statements[0]['context'], {
                    'registration': tracking.get('registration'),
                    'contextActivities': {
                        'grouping': [{
                            'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                            'objectType': 'Activity'
                        },{
                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                            'objectType': 'Activity'
                        },{
                            'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                            'objectType': 'Activity'
                        }],
                        'parent': [{
                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/self-evaluation',
                            'objectType': 'Activity'
                        }]
                    }
                })
                self.assertEqual(statements[1]['actor'], tracking_statements[1]['actor'])
                self.assertEqual(statements[1]['verb'], tracking_statements[1]['verb'])
                self.assertEqual(statements[1]['object'], tracking_statements[1]['object'])
                self.assertEqual(tracking_statements[1]['context'], {
                    'registration': tracking.get('registration'),
                    'contextActivities': {
                        'grouping': [{
                            'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                            'objectType': 'Activity'
                        }],
                        'parent': [{
                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                            'objectType': 'Activity'
                        },{
                            'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                            'objectType': 'Activity'
                        }]
                    }
                })
                self.assertEqual(tracking_statements[1]['result'], {
                    'completion': not draft,
                    'duration': tracking.get('duration'),
                    'success': True
                })

        for draft in [True, False]:
            self.evaluation_comment.draft = draft
            db.session.commit()

            # test evaluation_comment
            on_answer_comment_modified.send(
                current_app._get_current_object(),
                event_name=on_answer_comment_modified.name,
                user=self.user,
                answer_comment=self.evaluation_comment
            )

            statements = self.get_and_clear_statement_log()
            self.assertEqual(len(statements), 1)

            self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
            if draft:
                self.assertEqual(statements[0]['verb'], {
                    'id': 'http://xapi.learninganalytics.ubc.ca/verb/draft',
                    'display': {'en-US': 'drafted'}
                })
            else:
                self.assertEqual(statements[0]['verb'], {
                    'id': 'http://adlnet.gov/expapi/verbs/commented',
                    'display': {'en-US': 'commented'}
                })

            self.assertEqual(statements[0]['object'], {
                'id': 'https://localhost:8888/app/xapi/answer/comment/'+self.evaluation_comment.uuid,
                'definition': {'type': 'http://activitystrea.ms/schema/1.0/comment', 'name': {'en-US': 'Assignment answer evaluation comment'}},
                'objectType': 'Activity'
            })
            self.assertEqual(statements[0]['result'], {
                'extensions': {
                    'http://xapi.learninganalytics.ubc.ca/extension/character-count': len(self.evaluation_comment.content),
                    'http://xapi.learninganalytics.ubc.ca/extension/word-count': len(self.evaluation_comment.content.split(" "))
                },
                'response': self.evaluation_comment.content
            })
            self.assertEqual(statements[0]['context'], {
                'contextActivities': {
                    'grouping': [{
                        'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question',
                        'objectType': 'Activity'
                    }],
                    'parent': [{
                        'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                        'objectType': 'Activity'
                    }]
                }
            })

            # test evaluation_comment with tracking
            tracking = self.generate_tracking(with_duration=True)
            tracking_json = json.dumps({ 'tracking':  tracking })
            with self.app.test_request_context(content_type='application/json', method='POST',
                    content_length=len(tracking_json), data=tracking_json):
                on_answer_comment_modified.send(
                    current_app._get_current_object(),
                    event_name=on_answer_comment_modified.name,
                    user=self.user,
                    answer_comment=self.evaluation_comment
                )

                tracking_statements = self.get_and_clear_statement_log()
                self.assertEqual(len(statements), 1)
                self.assertEqual(statements[0]['actor'], tracking_statements[0]['actor'])
                self.assertEqual(statements[0]['verb'], tracking_statements[0]['verb'])
                self.assertEqual(statements[0]['object'], tracking_statements[0]['object'])
                self.assertEqual(statements[0]['result'], tracking_statements[0]['result'])
                self.assertEqual(tracking_statements[0]['context'], {
                    'registration': tracking.get('registration'),
                    'contextActivities': {
                        'grouping': [{
                            'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                            'objectType': 'Activity'
                        },{
                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                            'objectType': 'Activity'
                        },{
                            'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question',
                            'objectType': 'Activity'
                        }],
                        'parent': [{
                            'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                            'objectType': 'Activity'
                        }]
                    }
                })

        for comment in [self.public_comment, self.private_comment]:
            on_answer_comment_modified.send(
                current_app._get_current_object(),
                event_name=on_answer_comment_modified.name,
                user=self.user,
                answer_comment=comment
            )

            statements = self.get_and_clear_statement_log()
            self.assertEqual(len(statements), 1)
            self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
            self.assertEqual(statements[0]['verb'], {
                'id': 'http://activitystrea.ms/schema/1.0/update',
                'display': {'en-US': 'updated'}
            })
            self.assertEqual(statements[0]['object'], {
                'id': 'https://localhost:8888/app/xapi/answer/comment/'+comment.uuid,
                'definition': {'type': 'http://activitystrea.ms/schema/1.0/comment', 'name': {'en-US': 'Assignment answer comment'}},
                'objectType': 'Activity'
            })
            self.assertEqual(statements[0]['result'], {
                'extensions': {
                    'http://xapi.learninganalytics.ubc.ca/extension/character-count': len(comment.content),
                    'http://xapi.learninganalytics.ubc.ca/extension/word-count': len(comment.content.split(" "))
                },
                'response': comment.content
            })
            self.assertEqual(statements[0]['context'], {
                'contextActivities': {
                    'grouping': [{
                        'id': 'https://localhost:8888/app/xapi/course/'+self.course.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid,
                        'objectType': 'Activity'
                    },{
                        'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question',
                        'objectType': 'Activity'
                    }],
                    'parent': [{
                        'id': 'https://localhost:8888/app/xapi/answer/'+self.answer.uuid,
                        'objectType': 'Activity'
                    }]
                }
            })
Exemplo n.º 17
0
    def test_on_user_modified(self):
        # no changes provided
        on_user_modified.send(
            current_app._get_current_object(),
            event_name=on_user_modified.name,
            user=self.user
        )

        expected_caliper_event = {
            'action': 'Modified',
            'actor': self.get_compair_caliper_actor(self.user),
            'object': self.get_compair_caliper_actor(self.user),
            'session': self.get_caliper_session(self.get_compair_caliper_actor(self.user)),
            'type': 'Event'
        }

        events = self.get_and_clear_caliper_event_log()
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], expected_caliper_event)

        expected_xapi_verb = {
            'id': 'http://activitystrea.ms/schema/1.0/update',
            'display': {'en-US': 'updated'}
        }

        expected_xapi_context = {
            'extensions': {
                'http://id.tincanapi.com/extension/browser-info': {},
                'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
            }
        }

        expected_xapi_statement = {
            "actor": self.get_compair_xapi_actor(self.user),
            "verb": expected_xapi_verb,
            "object": self.get_compair_xapi_actor(self.user),
            "context": expected_xapi_context
        }

        statements = self.get_and_clear_xapi_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0], expected_xapi_statement)

        # test with changes
        changes = {
            'some_string': 'some_value',
            'some_number': 42,
            'some_dict': {
                'some_string': 'some_value',
                'some_number': 42
            }
        }
        on_user_modified.send(
            current_app._get_current_object(),
            event_name=on_user_modified.name,
            user=self.user,
            data={'changes': changes}
        )


        expected_caliper_event['extensions'] = {
            "changes": changes
        }

        events = self.get_and_clear_caliper_event_log()
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], expected_caliper_event)

        expected_xapi_statement['result'] = {
            'extensions': {'http://xapi.learninganalytics.ubc.ca/extension/changes': changes}
        }

        statements = self.get_and_clear_xapi_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0], expected_xapi_statement)
Exemplo n.º 18
0
    def test_actor_accounts(self):
        for user, third_party_auth in [(self.cas_user, self.cas_user_auth), (self.saml_user, self.saml_user_auth)]:

            # test without homepage set
            # (should use compair actor account)
            self.app.config['LRS_ACTOR_ACCOUNT_USE_GLOBAL_UNIQUE_IDENTIFIER'] = True
            self.app.config['LRS_ACTOR_ACCOUNT_GLOBAL_UNIQUE_IDENTIFIER_HOMEPAGE'] = None
            expected_actor = self.get_compair_xapi_actor(user)

            on_assignment_modified.send(
                current_app._get_current_object(),
                event_name=on_assignment_modified.name,
                user=user,
                assignment=self.assignment
            )
            statements = self.get_and_clear_xapi_statement_log()
            self.assertEqual(len(statements), 1)
            self.assertEqual(statements[0]['actor'], expected_actor)

            # test with homepage set and global unique identifier not set
            # (should use compair actor account)
            self.app.config['LRS_ACTOR_ACCOUNT_GLOBAL_UNIQUE_IDENTIFIER_HOMEPAGE'] = "http://third.party.homepage"
            on_assignment_modified.send(
                current_app._get_current_object(),
                event_name=on_assignment_modified.name,
                user=user,
                assignment=self.assignment
            )
            statements = self.get_and_clear_xapi_statement_log()
            self.assertEqual(len(statements), 1)
            self.assertEqual(statements[0]['actor'], expected_actor)
            expected_actor = self.get_compair_xapi_actor(user)

            # test with homepage set and global unique identifier set
            # (should use cas/saml actor account with overridden value used for name)
            user.global_unique_identifier = 'mock_puid_è_'+third_party_auth.third_party_type.value
            db.session.commit()
            expected_actor = self.get_unique_identifier_xapi_actor(
                user,
                "http://third.party.homepage/",
                'mock_puid_è_'+third_party_auth.third_party_type.value
            )
            on_assignment_modified.send(
                current_app._get_current_object(),
                event_name=on_assignment_modified.name,
                user=user,
                assignment=self.assignment
            )
            statements = self.get_and_clear_xapi_statement_log()
            self.assertEqual(len(statements), 1)
            self.assertEqual(statements[0]['actor'], expected_actor)

            # disabling LRS_ACTOR_ACCOUNT_USE_GLOBAL_UNIQUE_IDENTIFIER should skip checking global unique identifer
            self.app.config['LRS_ACTOR_ACCOUNT_USE_GLOBAL_UNIQUE_IDENTIFIER'] = False
            expected_actor = self.get_compair_xapi_actor(user)
            on_assignment_modified.send(
                current_app._get_current_object(),
                event_name=on_assignment_modified.name,
                user=user,
                assignment=self.assignment
            )
            statements = self.get_and_clear_xapi_statement_log()
            self.assertEqual(len(statements), 1)
            self.assertEqual(statements[0]['actor'], expected_actor)
Exemplo n.º 19
0
    def test_on_get_file(self):
        # not report or attachment
        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="none",
            file_name="some_file"
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 0)

        # test report
        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="report",
            file_name="some_report.csv"
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
        self.assertEqual(statements[0]['verb'], {
            'id': 'http://id.tincanapi.com/verb/downloaded',
            'display': {'en-US': 'downloaded'}
        })
        self.assertEqual(statements[0]['object'], {
            'id': 'https://localhost:8888/app/report/some_report.csv',
            'definition': {'type': 'http://activitystrea.ms/schema/1.0/file', 'name': {'en-US': 'Report'}},
            'objectType': 'Activity'
        })
        self.assertNotIn('result', statements[0])
        self.assertNotIn('context', statements[0])

        # test attachment without file record
        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="attachment",
            file_name="some_file"
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 0)

        # test attachment file record (not linked to assignments or answers)
        file_record = self.data.create_file(self.user)
        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="attachment",
            file_name=file_record.name
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 0)

        # test attachment file record (assignment)
        self.assignment.file = file_record
        db.session.commit()

        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="attachment",
            file_name=file_record.name
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
        self.assertEqual(statements[0]['verb'], {
            'id': 'http://id.tincanapi.com/verb/downloaded',
            'display': {'en-US': 'downloaded'}
        })
        self.assertEqual(statements[0]['object'], {
            'id': 'https://localhost:8888/app/attachment/'+file_record.name,
            'definition': {'type': 'http://activitystrea.ms/schema/1.0/file', 'name': {'en-US': 'Assignment attachment'}},
            'objectType': 'Activity'
        })
        self.assertNotIn('result', statements[0])
        self.assertEqual(statements[0]['context'], {
            'contextActivities': {
                'parent': [
                    {'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid, 'objectType': 'Activity'}
                ],
                'grouping': [
                    {'id': 'https://localhost:8888/app/xapi/course/'+self.data.main_course.uuid, 'objectType': 'Activity'}
                ]
            }
        })

        # test attachment file record (answer)
        self.assignment.file = None
        answer = AnswerFactory(
            assignment=self.assignment,
            user=self.user,
            file=file_record
        )
        db.session.commit()

        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="attachment",
            file_name=file_record.name
        )

        statements = self.get_and_clear_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0]['actor'], self.get_compair_actor(self.user))
        self.assertEqual(statements[0]['verb'], {
            'id': 'http://id.tincanapi.com/verb/downloaded',
            'display': {'en-US': 'downloaded'}
        })
        self.assertEqual(statements[0]['object'], {
            'id': 'https://localhost:8888/app/attachment/'+file_record.name,
            'definition': {'type': 'http://activitystrea.ms/schema/1.0/file', 'name': {'en-US': 'Assignment answer attachment'}},
            'objectType': 'Activity'
        })
        self.assertNotIn('result', statements[0])
        self.assertEqual(statements[0]['context'], {
            'contextActivities': {
                'parent': [
                    {'id': 'https://localhost:8888/app/xapi/answer/'+answer.uuid, 'objectType': 'Activity'}
                ],
                'grouping': [
                    {'id': 'https://localhost:8888/app/xapi/course/'+self.data.main_course.uuid, 'objectType': 'Activity'},
                    {'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid, 'objectType': 'Activity'},
                    {'id': 'https://localhost:8888/app/xapi/assignment/'+self.assignment.uuid+'/question', 'objectType': 'Activity'}
                ]
            }
        })
Exemplo n.º 20
0
    def test_on_get_file(self):
        # not report or attachment
        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="none",
            file_name="some_file"
        )

        events = self.get_and_clear_caliper_event_log()
        self.assertEqual(len(events), 0)

        statements = self.get_and_clear_xapi_statement_log()
        self.assertEqual(len(statements), 0)

        # test report
        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="report",
            file_name="some_report.csv"
        )

        expected_caliper_object = {
            "id": 'https://localhost:8888/app/report/some_report.csv',
            "type": "Document",
            "name": "some_report.csv",
            "mediaType": "text/csv"
        }

        expected_caliper_event = {
            'action': 'Viewed',
            'actor': self.get_compair_caliper_actor(self.user),
            'object': expected_caliper_object,
            'session': self.get_caliper_session(self.get_compair_caliper_actor(self.user)),
            'type': 'ViewEvent'
        }

        events = self.get_and_clear_caliper_event_log()
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], expected_caliper_event)

        expected_xapi_object = {
            'id': 'https://localhost:8888/app/report/some_report.csv',
            'definition': {
                'type': 'http://activitystrea.ms/schema/1.0/file',
                'name': {'en-US': 'some_report.csv'},
                'extensions': {
                    'http://id.tincanapi.com/extension/mime-type': "text/csv"
                }
            },
            'objectType': 'Activity'
        }

        expected_xapi_verb = {
            'id': 'http://id.tincanapi.com/verb/downloaded',
            'display': {'en-US': 'downloaded'}
        }

        expected_xapi_context = {
            'extensions': {
                'http://id.tincanapi.com/extension/browser-info': {},
                'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
            }
        }

        expected_xapi_statement = {
            "actor": self.get_compair_xapi_actor(self.user),
            "verb": expected_xapi_verb,
            "object": expected_xapi_object,
            "context": expected_xapi_context
        }

        statements = self.get_and_clear_xapi_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0], expected_xapi_statement)

        # test attachment without file record
        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="attachment",
            file_name="some_file"
        )

        events = self.get_and_clear_caliper_event_log()
        self.assertEqual(len(events), 0)

        statements = self.get_and_clear_xapi_statement_log()
        self.assertEqual(len(statements), 0)


        # test attachment file record (not linked to assignments or answers)
        file_record = self.data.create_file(self.user)
        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="attachment",
            file_name=file_record.name
        )

        events = self.get_and_clear_caliper_event_log()
        self.assertEqual(len(events), 0)

        statements = self.get_and_clear_xapi_statement_log()
        self.assertEqual(len(statements), 0)

        # test attachment file record (assignment)
        self.assignment.file_id = file_record.id
        db.session.commit()

        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="attachment",
            file_name=file_record.name
        )

        expected_caliper_object = {
            "id": 'https://localhost:8888/app/attachment/'+file_record.name,
            "type": "Document",
            "name": file_record.alias,
            "mediaType": 'application/pdf',
            "isPartOf": self.expected_caliper_assignment,
            "dateCreated": file_record.created.replace(tzinfo=pytz.utc).isoformat(),
            "dateModified": file_record.modified.replace(tzinfo=pytz.utc).isoformat()
        }

        self.expected_caliper_assignment['dateModified'] = self.assignment.modified.replace(tzinfo=pytz.utc).isoformat()
        expected_caliper_event['object'] = expected_caliper_object
        expected_caliper_event['membership'] = self.get_caliper_membership(self.course, self.user, self.lti_context)

        events = self.get_and_clear_caliper_event_log()
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], expected_caliper_event)

        expected_xapi_object = {
            'id': 'https://localhost:8888/app/attachment/'+file_record.name,
            'definition': {
                'type': 'http://activitystrea.ms/schema/1.0/file',
                'name': {'en-US': file_record.alias},
                'extensions': {
                    'http://id.tincanapi.com/extension/mime-type': 'application/pdf'
                }
            },
            'objectType': 'Activity'
        }

        expected_xapi_context = {
            'contextActivities': {
                'parent': [self.expected_xapi_assignment],
                'grouping': [self.expected_xapi_course, self.expected_xapi_sis_course, self.expected_xapi_sis_section]
            },
            'extensions': {
                'http://id.tincanapi.com/extension/browser-info': {},
                'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
            }
        }

        expected_xapi_statement['object'] = expected_xapi_object
        expected_xapi_statement['context'] = expected_xapi_context

        statements = self.get_and_clear_xapi_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0], expected_xapi_statement)


        # test attachment file record (answer)
        self.assignment.file_id = None
        self.answer.file_id = file_record.id
        db.session.commit()

        on_get_file.send(
            current_app._get_current_object(),
            event_name=on_get_file.name,
            user=self.user,
            file_type="attachment",
            file_name=file_record.name
        )

        self.expected_caliper_assignment_question['dateModified'] = self.assignment.modified.replace(tzinfo=pytz.utc).isoformat()
        self.expected_caliper_assignment['dateModified'] = self.assignment.modified.replace(tzinfo=pytz.utc).isoformat()
        self.expected_caliper_answer['dateModified'] = self.answer.modified.replace(tzinfo=pytz.utc).isoformat()
        expected_caliper_object["isPartOf"] = self.expected_caliper_answer

        events = self.get_and_clear_caliper_event_log()
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], expected_caliper_event)

        expected_xapi_context = {
            'contextActivities': {
                'parent': [self.expected_xapi_answer],
                'grouping': [self.expected_xapi_assignment_question, self.expected_xapi_assignment, self.expected_xapi_course, self.expected_xapi_sis_course, self.expected_xapi_sis_section]
            },
            'extensions': {
                'http://id.tincanapi.com/extension/browser-info': {},
                'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
            }
        }

        expected_xapi_statement['context'] = expected_xapi_context

        statements = self.get_and_clear_xapi_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0], expected_xapi_statement)
Exemplo n.º 21
0
    def test_on_detach_file(self):
        file_record = self.data.create_file(self.user)
        db.session.commit()

        # attache to assignment
        on_detach_file.send(
            current_app._get_current_object(),
            event_name=on_detach_file.name,
            user=self.user,
            file=file_record,
            assignment=self.assignment
        )

        expected_caliper_object = {
            "id": 'https://localhost:8888/app/attachment/'+file_record.name,
            "type": "Document",
            "name": file_record.alias,
            "mediaType": 'application/pdf',
            "isPartOf": self.expected_caliper_assignment,
            "dateCreated": file_record.created.replace(tzinfo=pytz.utc).isoformat(),
            "dateModified": file_record.modified.replace(tzinfo=pytz.utc).isoformat()
        }

        expected_caliper_event = {
            'action': 'Removed',
            'actor': self.get_compair_caliper_actor(self.user),
            'membership': self.get_caliper_membership(self.course, self.user, self.lti_context),
            'object': expected_caliper_object,
            'session': self.get_caliper_session(self.get_compair_caliper_actor(self.user)),
            'type': 'Event'
        }

        events = self.get_and_clear_caliper_event_log()
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], expected_caliper_event)

        expected_xapi_verb = {
            'id': 'http://activitystrea.ms/schema/1.0/delete',
            'display': {'en-US': 'deleted'}
        }

        expected_xapi_object = {
            'id': 'https://localhost:8888/app/attachment/'+file_record.name,
            'definition': {
                'type': 'http://activitystrea.ms/schema/1.0/file',
                'name': {'en-US': file_record.alias},
                'extensions': {
                    'http://id.tincanapi.com/extension/mime-type': 'application/pdf'
                }
            },
            'objectType': 'Activity'
        }

        expected_xapi_context = {
            'contextActivities': {
                'parent': [self.expected_xapi_assignment],
                'grouping': [self.expected_xapi_course, self.expected_xapi_sis_course, self.expected_xapi_sis_section]
            },
            'extensions': {
                'http://id.tincanapi.com/extension/browser-info': {},
                'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
            }
        }

        expected_xapi_statement = {
            "actor": self.get_compair_xapi_actor(self.user),
            "verb": expected_xapi_verb,
            "object": expected_xapi_object,
            "context": expected_xapi_context
        }

        statements = self.get_and_clear_xapi_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0], expected_xapi_statement)



        # attach to answer
        on_detach_file.send(
            current_app._get_current_object(),
            event_name=on_detach_file.name,
            user=self.user,
            file=file_record,
            answer=self.answer
        )

        expected_caliper_object["isPartOf"] = self.expected_caliper_answer

        events = self.get_and_clear_caliper_event_log()
        self.assertEqual(len(events), 1)
        self.assertEqual(events[0], expected_caliper_event)

        expected_xapi_context = {
            'contextActivities': {
                'parent': [self.expected_xapi_answer],
                'grouping': [self.expected_xapi_assignment_question, self.expected_xapi_assignment, self.expected_xapi_course, self.expected_xapi_sis_course, self.expected_xapi_sis_section]
            },
            'extensions': {
                'http://id.tincanapi.com/extension/browser-info': {},
                'http://id.tincanapi.com/extension/session-info': self.get_xapi_session_info()
            }
        }

        expected_xapi_statement['context'] = expected_xapi_context

        statements = self.get_and_clear_xapi_statement_log()
        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0], expected_xapi_statement)