Пример #1
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)
Пример #2
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])
Пример #3
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])
Пример #4
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)
Пример #5
0
    def test_on_logout(self):
        # not method provided
        on_logout.send(current_app._get_current_object(),
                       event_name=on_logout.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': 'https://brindlewaye.com/xAPITerms/verbs/loggedout/',
                'display': {
                    'en-US': 'logged out'
                }
            })
        self.assertEqual(
            statements[0]['object'], {
                'id': 'https://localhost:8888/',
                'definition': {
                    'type': 'http://activitystrea.ms/schema/1.0/service',
                    'name': {
                        'en-US': 'ComPAIR'
                    }
                },
                'objectType': 'Activity'
            })
        self.assertNotIn('result', statements[0])
        self.assertNotIn('context', statements[0])
Пример #6
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'
                }]
            }
        })
Пример #7
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])
Пример #8
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)
Пример #9
0
    def test_on_criterion_create(self):
        on_criterion_create.send(
            current_app._get_current_object(),
            event_name=on_criterion_create.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/author',
            'display': {'en-US': 'authored'}
        })
        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])
Пример #10
0
    def test_on_course_modified(self):
        on_course_modified.send(current_app._get_current_object(),
                                event_name=on_course_modified.name,
                                user=self.user,
                                course=self.course)

        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/course/' + self.course.uuid,
                'definition': {
                    'type': 'http://adlnet.gov/expapi/activities/course',
                    'name': {
                        'en-US': self.course.name
                    }
                },
                'objectType': 'Activity'
            })
        self.assertNotIn('result', statements[0])
        self.assertNotIn('context', statements[0])
Пример #11
0
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.objects(username=form.username.data).first()
        login_user(user, remember=form.remember.data)
        identity_changed.send(current_app._get_current_object(),
                              identity=Identity(user.username))
        flash("You have been logged in", category="success")
        return redirect(url_for('stock.home'))
    return render_template('main/login.html', form=form)
Пример #12
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)
Пример #13
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'
                        }]
                    }
                })
Пример #14
0
    def test_on_course_create(self):
        on_course_create.send(current_app._get_current_object(),
                              event_name=on_course_create.name,
                              user=self.user,
                              course=self.course)

        events = self.get_and_clear_caliper_event_log()
        expected_caliper_event = {
            'action':
            'Created',
            'actor':
            self.get_compair_caliper_actor(self.user),
            'membership':
            self.get_caliper_membership(self.course, self.user,
                                        self.lti_context),
            'object':
            self.expected_caliper_course,
            '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/author',
                'display': {
                    'en-US': 'authored'
                }
            },
            "object": self.expected_xapi_course,
            "context": {
                '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)
Пример #15
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)
Пример #16
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'))
Пример #17
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'
                    }]
                }
            })
Пример #18
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'
                }]
            }
        })
Пример #19
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'))
Пример #20
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'
                    }]
                }
            })
Пример #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)
Пример #22
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)
Пример #23
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'
                        }]
                    }
                })
Пример #24
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'
                    }]
                }
            })
Пример #25
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
Пример #26
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)
Пример #27
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'
                    }]
                }
            })
Пример #28
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'
                            }]
                        }
                    })
Пример #29
0
    def test_on_login_with_method(self):
        # no login method provided
        on_login_with_method.send(current_app._get_current_object(),
                                  event_name=on_login_with_method.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': 'https://brindlewaye.com/xAPITerms/verbs/loggedin/',
                'display': {
                    'en-US': 'logged in'
                }
            })
        self.assertEqual(
            statements[0]['object'], {
                'id': 'https://localhost:8888/',
                'definition': {
                    'type': 'http://activitystrea.ms/schema/1.0/service',
                    'name': {
                        'en-US': 'ComPAIR'
                    }
                },
                'objectType': 'Activity'
            })
        self.assertNotIn('result', statements[0])
        self.assertNotIn('context', statements[0])

        # test with login method
        login_method = "SAML"
        on_login_with_method.send(current_app._get_current_object(),
                                  event_name=on_login_with_method.name,
                                  user=self.user,
                                  login_method=login_method)

        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': 'https://brindlewaye.com/xAPITerms/verbs/loggedin/',
                'display': {
                    'en-US': 'logged in'
                }
            })
        self.assertEqual(
            statements[0]['object'], {
                'id': 'https://localhost:8888/',
                'definition': {
                    'type': 'http://activitystrea.ms/schema/1.0/service',
                    'name': {
                        'en-US': 'ComPAIR'
                    }
                },
                'objectType': 'Activity'
            })
        self.assertNotIn('result', statements[0])
        self.assertEqual(
            statements[0]['context'], {
                'extensions': {
                    'http://xapi.learninganalytics.ubc.ca/extension/login-method':
                    login_method
                }
            })
Пример #30
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'}
                ]
            }
        })
Пример #31
0
def logout():
    logout_user()
    identity_changed.send(current_app._get_current_object(),
                          identity=AnonymousIdentity())
    return redirect(url_for('main.login'))
Пример #32
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'
                    }]
                }
            })
Пример #33
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'
                        }]
                    }
                })
Пример #34
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)
Пример #35
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()

                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,
                    comparison=comparison,
                    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(self.example_comparison_criteria) + 1 + 1 +
                        (2 * (len(self.example_comparison_criteria) + 1)))
                else:
                    self.assertEqual(
                        len(statements),
                        len(self.example_comparison_criteria) + 1 + 1)

                index = 0

                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 comparison'
                            }
                        },
                        'objectType':
                        'Activity'
                    })
                if completed:
                    self.assertEqual(
                        statements[index]['result'], {
                            'response':
                            'https://localhost:8888/app/xapi/answer/' +
                            comparison.answer1_uuid,
                            'success':
                            True
                        })
                else:
                    self.assertEqual(statements[index]['result'],
                                     {'response': 'Undecided'})
                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/comparison/' +
                                comparison.uuid + '/question',
                                'objectType':
                                'Activity'
                            }]
                        }
                    })

                index += 1

                for comparison_criterion in comparison.comparison_criteria:
                    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/criterion/'
                            + comparison_criterion.uuid,
                            'definition': {
                                'type':
                                'http://id.tincanapi.com/activitytype/solution',
                                'name': {
                                    'en-US': 'Assignment criterion comparison'
                                }
                            },
                            'objectType':
                            'Activity'
                        })
                    if completed:
                        self.assertEqual(
                            statements[index]['result'], {
                                'response':
                                'https://localhost:8888/app/xapi/answer/' +
                                comparison_criterion.answer1_uuid,
                                'success':
                                True
                            })
                    else:
                        self.assertEqual(
                            statements[index]['result'], {
                                'response':
                                'https://localhost:8888/app/xapi/answer/' +
                                comparison_criterion.answer1_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'
                                }, {
                                    'id':
                                    'https://localhost:8888/app/xapi/comparison/'
                                    + comparison.uuid + '/question',
                                    'objectType':
                                    'Activity'
                                }],
                                'parent': [{
                                    'id':
                                    'https://localhost:8888/app/xapi/comparison/'
                                    + comparison.uuid,
                                    'objectType':
                                    'Activity'
                                }, {
                                    'id':
                                    'https://localhost:8888/app/xapi/criterion/'
                                    + comparison_criterion.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/comparison/' +
                        comparison.uuid + '/question',
                        '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.adaptive_min_delta.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_criterion in comparison.comparison_criteria:
                    grouping.append({
                        'id':
                        'https://localhost:8888/app/xapi/criterion/' +
                        comparison_criterion.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/' +
                                comparison.answer1_uuid,
                                'objectType':
                                'Activity'
                            }, {
                                'id':
                                'https://localhost:8888/app/xapi/answer/' +
                                comparison.answer2_uuid,
                                'objectType':
                                'Activity'
                            }]
                        }
                    })
                index += 1

                if completed and not is_comparison_example:
                    for answer in [self.answer1, self.answer2]:
                        score = answer.score

                        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,
                                'definition': {
                                    'type':
                                    'http://id.tincanapi.com/activitytype/solution',
                                    'name': {
                                        'en-US': 'Assignment answer'
                                    }
                                },
                                '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'
                                    }],
                                    'other': [{
                                        'id':
                                        'https://localhost:8888/app/xapi/comparison/'
                                        + comparison.uuid,
                                        'objectType':
                                        'Activity'
                                    }, {
                                        'id':
                                        'https://localhost:8888/app/xapi/comparison/'
                                        + comparison.uuid + '/question',
                                        'objectType':
                                        'Activity'
                                    }],
                                    'parent': [{
                                        'id':
                                        'https://localhost:8888/app/xapi/assignment/'
                                        + self.assignment.uuid + '/question',
                                        'objectType':
                                        'Activity'
                                    }]
                                }
                            })
                        index += 1

                        for score in answer.criteria_scores:
                            comparison_criterion = next(comparison_criterion for comparison_criterion in comparison.comparison_criteria \
                                if comparison_criterion.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/criterion/'
                                            + comparison_criterion.uuid,
                                            'objectType':
                                            'Activity'
                                        }, {
                                            'id':
                                            'https://localhost:8888/app/xapi/comparison/'
                                            + comparison.uuid,
                                            'objectType':
                                            'Activity'
                                        }, {
                                            'id':
                                            'https://localhost:8888/app/xapi/comparison/'
                                            + comparison.uuid + '/question',
                                            '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,
                        comparison=comparison,
                        is_comparison_example=is_comparison_example)

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

                    index = 0

                    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/comparison/'
                                    + comparison.uuid + '/question',
                                    'objectType':
                                    'Activity'
                                }]
                            }
                        })

                    index += 1

                    for comparison_criterion in comparison.comparison_criteria:
                        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'
                                    }, {
                                        'id':
                                        'https://localhost:8888/app/xapi/comparison/'
                                        + comparison.uuid + '/question',
                                        'objectType':
                                        'Activity'
                                    }],
                                    'parent': [{
                                        'id':
                                        'https://localhost:8888/app/xapi/comparison/'
                                        + comparison.uuid,
                                        'objectType':
                                        'Activity'
                                    }, {
                                        'id':
                                        'https://localhost:8888/app/xapi/criterion/'
                                        + comparison_criterion.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/' +
                                    comparison.answer1_uuid,
                                    'objectType':
                                    'Activity'
                                }, {
                                    'id':
                                    'https://localhost:8888/app/xapi/answer/' +
                                    comparison.answer2_uuid,
                                    'objectType':
                                    'Activity'
                                }]
                            }
                        })
                    index += 1

                    if completed and not is_comparison_example:
                        for answer in [self.answer1, self.answer2]:
                            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'
                                        }],
                                        'other': [{
                                            'id':
                                            'https://localhost:8888/app/xapi/comparison/'
                                            + comparison.uuid,
                                            'objectType':
                                            'Activity'
                                        }, {
                                            'id':
                                            'https://localhost:8888/app/xapi/comparison/'
                                            + comparison.uuid + '/question',
                                            'objectType':
                                            'Activity'
                                        }],
                                        'parent': [{
                                            'id':
                                            'https://localhost:8888/app/xapi/assignment/'
                                            + self.assignment.uuid +
                                            '/question',
                                            'objectType':
                                            'Activity'
                                        }]
                                    }
                                })
                            index += 1

                            for score in answer.criteria_scores:
                                comparison_criterion = next(comparison_criterion for comparison_criterion in comparison.comparison_criteria \
                                    if comparison_criterion.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/criterion/'
                                                + comparison_criterion.uuid,
                                                'objectType':
                                                'Activity'
                                            }, {
                                                'id':
                                                'https://localhost:8888/app/xapi/comparison/'
                                                + comparison.uuid,
                                                'objectType':
                                                'Activity'
                                            }, {
                                                'id':
                                                'https://localhost:8888/app/xapi/comparison/'
                                                + comparison.uuid +
                                                '/question',
                                                '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
Пример #36
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)
Пример #37
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)
Пример #38
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)
Пример #39
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)
Пример #40
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'
                        }]
                    }
                })
Пример #41
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)
Пример #42
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'
                        }]
                    }
                })
Пример #43
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'
                    }]
                }
            })
Пример #44
0
    def test_on_answer_delete(self):
        # send delete
        on_answer_delete.send(current_app._get_current_object(),
                              event_name=on_answer_delete.name,
                              user=self.user,
                              answer=self.answer)

        events = self.get_and_clear_caliper_event_log()
        expected_caliper_event = {
            'action':
            'Deleted',
            'actor':
            self.get_compair_caliper_actor(self.user),
            'membership':
            self.get_caliper_membership(self.course, self.user,
                                        self.lti_context),
            'object':
            self.expected_caliper_answer,
            '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/delete',
                'display': {
                    'en-US': 'deleted'
                }
            },
            "object": self.expected_xapi_answer,
            "context": {
                '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()
                }
            },
        }

        self.assertEqual(len(statements), 1)
        self.assertEqual(statements[0], expected_xapi_statement)
Пример #45
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)
Пример #46
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)
Пример #47
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)