Exemple #1
0
    def test_remove_degenerate(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.remove(self.user1, self.user1)

        assert Group.lookup(self.user1, self.assignment) is None
        assert Group.lookup(self.user2, self.assignment) is None
Exemple #2
0
    def test_remove_degenerate(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.remove(self.user1, self.user1)

        assert Group.lookup(self.user1, self.assignment) is None
        assert Group.lookup(self.user2, self.assignment) is None
Exemple #3
0
    def test_decline_degenerate(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.decline(self.user2)

        assert Group.lookup(self.user1, self.assignment) is None
        assert Group.lookup(self.user2, self.assignment) is None
Exemple #4
0
    def test_decline_degenerate(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.decline(self.user2)

        assert Group.lookup(self.user1, self.assignment) is None
        assert Group.lookup(self.user2, self.assignment) is None
Exemple #5
0
    def test_decline(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)
        group.decline(self.user3)

        assert group.has_status(self.user1, 'active')
        assert group.has_status(self.user2, 'active')
        assert Group.lookup(self.user3, self.assignment) is None
        assert group.size() == 2
Exemple #6
0
    def test_decline(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)
        group.decline(self.user3)

        assert group.has_status(self.user1, 'active')
        assert group.has_status(self.user2, 'active')
        assert Group.lookup(self.user3, self.assignment) is None
        assert group.size() == 2
Exemple #7
0
    def test_remove_self(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)
        group.accept(self.user3)
        group.remove(self.user1, self.user1)

        assert Group.lookup(self.user1, self.assignment) is None
        assert group.has_status(self.user2, 'active')
        assert group.has_status(self.user3, 'active')
Exemple #8
0
    def test_remove_self(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)
        group.accept(self.user3)
        group.remove(self.user1, self.user1)

        assert Group.lookup(self.user1, self.assignment) is None
        assert group.has_status(self.user2, 'active')
        assert group.has_status(self.user3, 'active')
Exemple #9
0
    def test_accept_not_pending(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        self.assertRaises(BadRequest, group.accept, self.user2)
        self.assertRaises(BadRequest, group.accept, self.user3)
Exemple #10
0
def assignment(name):
    assign = get_assignment(name)
    user_ids = assign.active_user_ids(current_user.id)
    fs = assign.final_submission(user_ids)
    revision = assign.revision(user_ids)
    scores = assign.scores(user_ids)

    group = Group.lookup(current_user, assign)
    can_invite = assign.max_group_size > 1 and assign.active
    can_remove = group and group.has_status(current_user, 'active')

    if group:
        can_invite = len(group.members) < assign.max_group_size

    data = {
        'course': assign.course,
        'assignment': assign,
        'backups': assign.backups(user_ids).limit(5).all(),
        'subms': assign.submissions(user_ids).limit(5).all(),
        'final_submission': fs,
        'flagged': fs and fs.flagged,
        'group': group,
        'revision': revision,
        'scores': scores,
        'can_invite': can_invite,
        'can_remove': can_remove,
        'csrf_form': CSRFForm()
    }
    return render_template('student/assignment/index.html', **data)
Exemple #11
0
    def setUp(self):
        super(TestGrading, self).setUp()
        self.setup_course()

        message_dict = {'file_contents': {'backup.py': '1'}, 'analytics': {}}

        self.active_user_ids = [self.user1.id, self.user2.id, self.user3.id]
        self.active_staff = [self.staff1, self.staff2]
        self.active_assignments = [self.assignment, self.assignment2]

        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        # Creates 5 submissions for each assignment per user, each spaced two minutes apart

        for assign in self.active_assignments:
            time = assign.due_date - datetime.timedelta(minutes=30)
            for num in range(5):
                for user_id in self.active_user_ids:
                    num += 1
                    time += datetime.timedelta(minutes=2)
                    backup = Backup(submitter_id=user_id,
                        assignment=assign, submit=True)
                    messages = [Message(kind=k, backup=backup,
                        contents=m) for k, m in message_dict.items()]
                    backup.created = time
                    db.session.add_all(messages)
                    db.session.add(backup)
                    # Debugging print if tests fails
                    # print("User {} | Assignment {} | Submission {} | Time {}".format(
                    #     user_id, assign.id, num, time))
        db.session.commit()
Exemple #12
0
    def setUp(self):
        """ Add submissions for 3 users. """
        super(TestRevision, self).setUp()
        self.setup_course()

        message_dict = {'file_contents': {'backup.py': '1'}, 'analytics': {}}

        self.active_user_ids = [self.user1.id, self.user2.id, self.user3.id]

        self.assignment.revisions_allowed = True

        time = self.assignment.due_date # Set to dt.now(), so future subms are late
        for user_id in self.active_user_ids:
            time -= datetime.timedelta(minutes=15)
            backup = Backup(submitter_id=user_id,
                            assignment=self.assignment, submit=True)
            # Revisions are submitted on time.
            backup.created = time
            messages = [Message(kind=k, backup=backup,
                                contents=m) for k, m in message_dict.items()]
            db.session.add_all(messages)
            db.session.add(backup)

        # Put user 3 in a group with user 4
        Group.invite(self.user3, self.user4, self.assignment)
        group = Group.lookup(self.user3, self.assignment)
        group.accept(self.user4)

        okversion = Version(name="ok-client", current_version="v1.5.0",
            download_link="http://localhost/ok")
        db.session.add(okversion)

        db.session.commit()
Exemple #13
0
def assignment(name):
    assign = get_assignment(name)
    user_ids = assign.active_user_ids(current_user.id)
    fs = assign.final_submission(user_ids)
    revision = assign.revision(user_ids)
    scores = assign.scores(user_ids)

    group = Group.lookup(current_user, assign)
    can_invite = assign.max_group_size > 1 and assign.active
    can_remove = group and group.has_status(current_user, 'active')

    if group:
        can_invite = len(group.members) < assign.max_group_size

    data = {
        'course': assign.course,
        'assignment': assign,
        'backups': assign.backups(user_ids).limit(5).all(),
        'subms': assign.submissions(user_ids).limit(5).all(),
        'final_submission': fs,
        'flagged': fs and fs.flagged,
        'group': group,
        'revision': revision,
        'scores': scores,
        'can_invite': can_invite,
        'can_remove': can_remove,
        'csrf_form': CSRFForm()
    }
    return render_template('student/assignment/index.html', **data)
Exemple #14
0
    def test_remove_not_in_group(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        self.assertRaises(BadRequest, group.remove, self.user2, self.user3)
        self.assertRaises(BadRequest, group.remove, self.user3, self.user2)
Exemple #15
0
    def test_remove_not_in_group(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        self.assertRaises(BadRequest, group.remove, self.user2, self.user3)
        self.assertRaises(BadRequest, group.remove, self.user3, self.user2)
Exemple #16
0
    def test_accept_not_pending(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        self.assertRaises(BadRequest, group.accept, self.user2)
        self.assertRaises(BadRequest, group.accept, self.user3)
Exemple #17
0
    def setUp(self):
        super(TestGrading, self).setUp()
        self.setup_course()

        message_dict = {'file_contents': {'backup.py': '1'}, 'analytics': {}}

        self.active_user_ids = [self.user1.id, self.user2.id, self.user3.id]
        self.active_staff = [self.staff1, self.staff2]
        self.active_assignments = [self.assignment, self.assignment2]

        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        # Creates 5 submissions for each assignment per user, each spaced two minutes apart

        for assign in self.active_assignments:
            time = assign.due_date - datetime.timedelta(minutes=30)
            for num in range(5):
                for user_id in self.active_user_ids:
                    num += 1
                    time += datetime.timedelta(minutes=2)
                    backup = Backup(submitter_id=user_id,
                        assignment=assign, submit=True)
                    messages = [Message(kind=k, backup=backup,
                        contents=m) for k, m in message_dict.items()]
                    backup.created = time
                    db.session.add_all(messages)
                    db.session.add(backup)
                    # Debugging print if tests fails
                    # print("User {} | Assignment {} | Submission {} | Time {}".format(
                    #     user_id, assign.id, num, time))
        db.session.commit()
Exemple #18
0
    def test_remove(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        Group.invite(self.user1, self.user4, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        group.remove(self.user1, self.user2)
        assert group.has_status(self.user1, 'active')
        assert Group.lookup(self.user2, self.assignment) is None
        assert group.has_status(self.user3, 'pending')
        assert group.size() == 3

        group.remove(self.user1, self.user3)
        assert group.has_status(self.user1, 'active')
        assert Group.lookup(self.user3, self.assignment) is None
        assert group.size() == 2
Exemple #19
0
    def test_remove(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        Group.invite(self.user1, self.user4, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        group.remove(self.user1, self.user2)
        assert group.has_status(self.user1, 'active')
        assert Group.lookup(self.user2, self.assignment) is None
        assert group.has_status(self.user3, 'pending')
        assert group.size() == 3

        group.remove(self.user1, self.user3)
        assert group.has_status(self.user1, 'active')
        assert Group.lookup(self.user3, self.assignment) is None
        assert group.size() == 2
Exemple #20
0
    def test_accept(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        assert group.has_status(self.user1, 'active')
        assert group.has_status(self.user2, 'active')
        assert group.size() == 2
Exemple #21
0
    def test_accept(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        assert group.has_status(self.user1, 'active')
        assert group.has_status(self.user2, 'active')
        assert group.size() == 2
Exemple #22
0
    def test_invite_full(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        Group.invite(self.user1, self.user4, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        assert group.size() == 4
        self.assertRaises(BadRequest, Group.invite, self.user1, self.user5, self.assignment)
Exemple #23
0
    def test_invite_full(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        Group.invite(self.user1, self.user4, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        assert group.size() == 4
        self.assertRaises(BadRequest, Group.invite, self.user1, self.user5,
                          self.assignment)
Exemple #24
0
    def test_accept_unflag(self):
        # when a user accepts an invitation, unflag their submissions.
        submission = self.assignment.submissions([self.user1.id]).all()[3]
        self.assignment.flag(submission.id, [self.user1.id])

        Group.invite(self.user2, self.user1, self.assignment)
        assert submission.flagged

        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user1)
        assert not submission.flagged
    def test_accept_unflag(self):
        # when a user accepts an invitation, unflag their submissions.
        submission = self.assignment.submissions([self.user1.id]).all()[3]
        self.assignment.flag(submission.id, [self.user1.id])

        Group.invite(self.user2, self.user1, self.assignment)
        assert submission.flagged

        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user1)
        assert not submission.flagged
Exemple #26
0
    def test_active_user_ids(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        assert self.assignment.active_user_ids(self.user1.id) == \
            {self.user1.id, self.user2.id}
        assert self.assignment.active_user_ids(self.user2.id) == \
            {self.user1.id, self.user2.id}
        assert self.assignment.active_user_ids(self.user3.id) == \
            {self.user3.id}
    def test_active_user_ids(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        assert self.assignment.active_user_ids(self.user1.id) == \
            {self.user1.id, self.user2.id}
        assert self.assignment.active_user_ids(self.user2.id) == \
            {self.user1.id, self.user2.id}
        assert self.assignment.active_user_ids(self.user3.id) == \
            {self.user3.id}
Exemple #28
0
def submit_assignment(name):
    assign = get_assignment(name)
    group = Group.lookup(current_user, assign)
    user_ids = assign.active_user_ids(current_user.id)
    fs = assign.final_submission(user_ids)

    if not assign.uploads_enabled:
        flash("This assignment cannot be submitted online", 'warning')
        return redirect(url_for('.assignment', name=assign.name))
    if not assign.active:
        flash("It's too late to submit this assignment", 'warning')
        return redirect(url_for('.assignment', name=assign.name))

    form = UploadSubmissionForm()
    if form.validate_on_submit():
        files = request.files.getlist("upload_files")
        if files:
            templates = assign.files
            messages = {'file_contents': {}}
            for upload in files:
                data = upload.read()
                if len(data) > 2097152:
                    # File is too large (over 2 MB)
                    flash("{} is over the maximum file size limit of 2MB".format(upload.filename),
                          'danger')
                    return redirect(url_for('.submit_assignment', name=assign.name))
                messages['file_contents'][upload.filename] = str(data, 'latin1')
            if templates:
                missing = []
                for template in templates:
                    if template not in messages['file_contents']:
                        missing.append(template)
                if missing:
                    flash(("Missing files: {}. The following files are required: {}"
                           .format(', '.join(missing), ', '.join([t for t in templates]))
                           ), 'danger')
                    return redirect(url_for('.submit_assignment', name=assign.name))

            backup = make_backup(current_user, assign.id, messages, True)
            if form.flag_submission.data:
                assign.flag(backup.id, user_ids)
            if assign.autograding_key:
                try:
                    submit_continous(backup)
                except ValueError as e:
                    logger.warning('Web submission did not autograde', exc_info=True)
                    flash('Did not send to autograder: {}'.format(e), 'warning')

            flash("Uploaded submission (ID: {})".format(backup.hashid), 'success')
            return redirect(url_for('.assignment', name=assign.name))

    return render_template('student/assignment/submit.html', assignment=assign,
                           group=group, course=assign.course, form=form)
Exemple #29
0
    def test_group_api(self):
        self._test_backup(True)
        self.logout()

        student = User.lookup(self.user1.email)

        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)
        base_api = '/api/v3/assignment/{0}/group/{1}'
        endpoint = base_api.format(self.assignment.name, self.user1.email)

        response = self.client.get(endpoint)
        self.assert_401(response)

        self.login(self.user1.email)
        response = self.client.get(endpoint)
        self.assert_200(response)
        members = response.json['data']['members']
        self.assertEquals(len(members), 2)
        assert 'email' in members[0]['user']

        # Make sure user2 can access user1's endpoint
        self.login(self.user2.email)
        response = self.client.get(endpoint)
        self.assert_200(response)
        members = response.json['data']['members']
        self.assertEquals(len(members), 2)
        assert 'email' in members[1]['user']

        self.login(self.staff1.email)
        response = self.client.get(endpoint)

        self.assert_200(response)
        members = response.json['data']['members']
        self.assertEquals(len(members), 2)
        assert 'email' in members[0]['user']

        # Login as some random user
        self.login(self.user3.email)
        response = self.client.get(endpoint)
        self.assert_403(response)

        # Check for existence of email
        response = self.client.get(
            base_api.format(self.assignment.name, '*****@*****.**'))
        self.assert_403(response)

        self.login(self.admin.email)
        response = self.client.get(
            base_api.format(self.assignment.name, '*****@*****.**'))
        self.assert_404(response)
Exemple #30
0
    def test_group_api(self):
        self._test_backup(True)
        self.logout()

        student = User.lookup(self.user1.email)

        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)
        base_api = '/api/v3/assignment/{0}/group/{1}'
        endpoint = base_api.format(self.assignment.name, self.user1.email)

        response = self.client.get(endpoint)
        self.assert_401(response)

        self.login(self.user1.email)
        response = self.client.get(endpoint)
        self.assert_200(response)
        members = response.json['data']['members']
        self.assertEqual(len(members), 2)
        assert 'email' in members[0]['user']

        # Make sure user2 can access user1's endpoint
        self.login(self.user2.email)
        response = self.client.get(endpoint)
        self.assert_200(response)
        members = response.json['data']['members']
        self.assertEqual(len(members), 2)
        assert 'email' in members[1]['user']


        self.login(self.staff1.email)
        response = self.client.get(endpoint)

        self.assert_200(response)
        members = response.json['data']['members']
        self.assertEqual(len(members), 2)
        assert 'email' in  members[0]['user']

        # Login as some random user
        self.login(self.user3.email)
        response = self.client.get(endpoint)
        self.assert_403(response)

        # Check for existence of email
        response = self.client.get(base_api.format(self.assignment.name, '*****@*****.**'))
        self.assert_403(response)

        self.login(self.admin.email)
        response = self.client.get(base_api.format(self.assignment.name, '*****@*****.**'))
        self.assert_404(response)
Exemple #31
0
    def test_invite(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)

        assert group.has_status(self.user1, 'active')
        assert group.has_status(self.user2, 'pending')
        assert group.size() == 2

        Group.invite(self.user1, self.user3, self.assignment)

        assert group.has_status(self.user1, 'active')
        assert group.has_status(self.user2, 'pending')
        assert group.has_status(self.user3, 'pending')
        assert group.size() == 3
Exemple #32
0
    def test_invite(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)

        assert group.has_status(self.user1, 'active')
        assert group.has_status(self.user2, 'pending')
        assert group.size() == 2

        Group.invite(self.user1, self.user3, self.assignment)

        assert group.has_status(self.user1, 'active')
        assert group.has_status(self.user2, 'pending')
        assert group.has_status(self.user3, 'pending')
        assert group.size() == 3
Exemple #33
0
    def test_locked(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        Group.invite(self.user1, self.user4, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        self.assignment.lock_date = datetime.datetime.now() - datetime.timedelta(days=1)
        db.session.commit()

        self.assertRaises(BadRequest, Group.invite, self.user1, self.user2, self.assignment)
        self.assertRaises(BadRequest, group.accept, self.user3)
        self.assertRaises(BadRequest, group.decline, self.user3)
        self.assertRaises(BadRequest, group.remove, self.user1, self.user2)
Exemple #34
0
    def test_locked(self):
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        Group.invite(self.user1, self.user4, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        self.assignment.lock_date = datetime.datetime.now(
        ) - datetime.timedelta(days=1)
        db.session.commit()

        self.assertRaises(BadRequest, Group.invite, self.user1, self.user2,
                          self.assignment)
        self.assertRaises(BadRequest, group.accept, self.user3)
        self.assertRaises(BadRequest, group.decline, self.user3)
        self.assertRaises(BadRequest, group.remove, self.user1, self.user2)
Exemple #35
0
    def test_group_permission(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)

        # Only the original creator and staff can accept the files
        self.assertTrue(ExternalFile.can(self.file2, self.user1, 'download'))
        self.assertTrue(ExternalFile.can(self.file2, self.staff1, 'download'))
        self.assertFalse(ExternalFile.can(self.file2, self.user2, 'download'))

        group.accept(self.user2)

        # Now all group members can access the files
        self.assertTrue(ExternalFile.can(self.file2, self.user1, 'download'))
        self.assertTrue(ExternalFile.can(self.file2, self.staff1, 'download'))
        self.assertTrue(ExternalFile.can(self.file2, self.user2, 'download'))
        self.assertFalse(ExternalFile.can(self.file2, self.user3, 'download'))
Exemple #36
0
    def test_group_permission(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)

        # Only the original creator and staff can accept the files
        self.assertTrue(ExternalFile.can(self.file2, self.user1, 'download'))
        self.assertTrue(ExternalFile.can(self.file2, self.staff1, 'download'))
        self.assertFalse(ExternalFile.can(self.file2, self.user2, 'download'))

        group.accept(self.user2)

        # Now all group members can access the files
        self.assertTrue(ExternalFile.can(self.file2, self.user1, 'download'))
        self.assertTrue(ExternalFile.can(self.file2, self.staff1, 'download'))
        self.assertTrue(ExternalFile.can(self.file2, self.user2, 'download'))
        self.assertFalse(ExternalFile.can(self.file2, self.user3, 'download'))
Exemple #37
0
    def test_extension_group(self):
        self.set_offset(1) # Allow assignment to be active
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)
        self.set_offset(-1) # Lock assignment

        ext = self._make_ext(self.assignment, self.user1)
        self.assertEquals(ext, Extension.get_extension(self.user1, self.assignment))
        self.assertEquals(ext, Extension.get_extension(self.user2, self.assignment))
        # User 3 has not accepted yet so does not get an extension
        self.assertFalse(Extension.get_extension(self.user3, self.assignment))

        # If user 2 leaves, they no longer have access to the extension
        group.remove(self.user1, self.user2)
        self.assertFalse(Extension.get_extension(self.user2, self.assignment))
Exemple #38
0
def submit_assignment(name):
    assign = get_assignment(name)
    group = Group.lookup(current_user, assign)
    user_ids = assign.active_user_ids(current_user.id)
    fs = assign.final_submission(user_ids)

    if not assign.uploads_enabled:
        flash("This assignment cannot be submitted online", 'warning')
        return redirect(url_for('.assignment', name=assign.name))
    if not assign.active:
        flash("It's too late to submit this assignment", 'warning')
        return redirect(url_for('.assignment', name=assign.name))

    form = UploadSubmissionForm()
    if form.validate_on_submit():
        backup = Backup(
            submitter=current_user,
            assignment=assign,
            submit=True,
        )
        if form.upload_files.upload_backup_files(backup):
            db.session.add(backup)
            db.session.commit()
            if assign.autograding_key:
                try:
                    submit_continous(backup)
                except ValueError as e:
                    logger.warning('Web submission did not autograde',
                                   exc_info=True)
                    flash('Did not send to autograder: {}'.format(e),
                          'warning')
            flash('Uploaded submission', 'success')
            return redirect(
                url_for(
                    '.code',
                    name=assign.name,
                    submit=backup.submit,
                    bid=backup.id,
                ))

    return render_template('student/assignment/submit.html',
                           assignment=assign,
                           group=group,
                           course=assign.course,
                           form=form)
Exemple #39
0
    def test_extension_group(self):
        self.set_offset(1) # Allow assignment to be active
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)
        self.set_offset(-2) # Lock assignment

        ext = self._make_ext(self.assignment, self.user1)
        self.assertEqual(ext, Extension.get_extension(self.user1, self.assignment))
        self.assertEqual(ext, Extension.get_extension(self.user2, self.assignment))
        # User 3 has not accepted yet so does not get an extension
        self.assertFalse(Extension.get_extension(self.user3, self.assignment))

        # If user 2 leaves, they no longer have access to the extension
        self.set_offset(1) # Allow assignment to be active to remove the user.
        group.remove(self.user1, self.user2)
        self.assertFalse(Extension.get_extension(self.user2, self.assignment))
Exemple #40
0
    def test_backup_owners(self):
        backup = Backup(submitter_id=self.user1.id,
                        assignment=self.assignment,
                        submit=True)
        backup2 = Backup(submitter_id=self.user2.id,
                         assignment=self.assignment,
                         submit=True)
        db.session.add(backup)
        db.session.add(backup2)
        db.session.commit()
        assert backup2.owners() == {self.user2.id}

        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        assert backup.owners() == {self.user1.id, self.user2.id}
        assert backup2.owners() == {self.user1.id, self.user2.id}
    def test_backup_owners(self):
        backup = Backup(
            submitter_id=self.user1.id,
            assignment=self.assignment,
            submit=True)
        backup2 = Backup(
            submitter_id=self.user2.id,
            assignment=self.assignment,
            submit=True)
        db.session.add(backup)
        db.session.add(backup2)
        db.session.commit()
        assert backup2.owners() == {self.user2.id}

        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)

        assert backup.owners() == {self.user1.id, self.user2.id}
        assert backup2.owners() == {self.user1.id, self.user2.id}
Exemple #42
0
def group_respond(name):
    assignment = get_assignment(name)
    action = request.form.get('action')
    target = request.form.get('email')
    if not action or action not in ['accept', 'decline', 'revoke']:
        abort(400)
    group = Group.lookup(current_user, assignment)
    if not group:
        flash("You are not in a group")
    else:
        try:

            if action == "accept":
                group.accept(current_user)
                subject = "{0} has accepted the invitation to join your group".format(
                    current_user.email)
                body = "Your group for {0} now has {1} members".format(
                    assignment.display_name, len(group.members))
                group_action_email(group.members, subject, body)
            elif action == "decline":
                members = [m.user.email for m in group.members]
                group.decline(current_user)
                subject = "{0} declined an invite to join the group".format(
                    current_user.email)
                body = "{0} declined to join the group for {1}".format(
                    current_user.email, assignment.display_name)
                send_email(members, subject, body)
            elif action == "revoke":
                members = [m.user.email for m in group.members]
                group.decline(current_user)
                subject = "{0} invitation for {1} revoked".format(
                    assignment.display_name, target)
                body = "{0} has revoked the invitation for {1}".format(
                    current_user.email, target)
                send_email(members, subject, body)

        except BadRequest as e:
            flash(e.description, 'danger')
    return redirect(url_for('.assignment', name=assignment.name))
Exemple #43
0
def submit_assignment(name):
    assign = get_assignment(name)
    group = Group.lookup(current_user, assign)
    user_ids = assign.active_user_ids(current_user.id)
    fs = assign.final_submission(user_ids)

    if not assign.uploads_enabled:
        flash("This assignment cannot be submitted online", 'warning')
        return redirect(url_for('.assignment', name=assign.name))
    if not assign.active:
        flash("It's too late to submit this assignment", 'warning')
        return redirect(url_for('.assignment', name=assign.name))

    form = UploadSubmissionForm()
    if form.validate_on_submit():
        backup = Backup(
            submitter=current_user,
            assignment=assign,
            submit=True,
        )
        if form.upload_files.upload_backup_files(backup):
            db.session.add(backup)
            db.session.commit()
            if assign.autograding_key:
                try:
                    submit_continous(backup)
                except ValueError as e:
                    logger.warning('Web submission did not autograde', exc_info=True)
                    flash('Did not send to autograder: {}'.format(e), 'warning')
            flash('Uploaded submission', 'success')
            return redirect(url_for(
                '.code',
                name=assign.name,
                submit=backup.submit,
                bid=backup.id,
            ))

    return render_template('student/assignment/submit.html', assignment=assign,
                           group=group, course=assign.course, form=form)
Exemple #44
0
def group_remove(name):
    assignment = get_assignment(name)
    target = User.lookup(request.form['email'])
    group = Group.lookup(current_user, assignment)
    if not target:
        flash("{0} is not enrolled".format(request.form['email']), 'warning')
    elif not group:
        flash("You are not in a group", 'warning')
    else:
        try:
            members = [m.user.email for m in group.members]
            group.remove(current_user, target)
            subject = "{0} has been removed from your {1} group".format(target.email,
                                                                        assignment.display_name)
            if target.email == current_user.email:
                descriptor = "themselves"
            else:
                descriptor = target.email
            body = "{0} removed {1} from the group.".format(current_user.email, descriptor)
            send_email(members, subject, body)
        except BadRequest as e:
            flash(e.description, 'danger')
    return redirect(url_for('.assignment', name=assignment.name))
Exemple #45
0
def group_respond(name):
    assignment = get_assignment(name)
    action = request.form.get('action')
    target = request.form.get('email')
    if not action or action not in ['accept', 'decline', 'revoke']:
        abort(400)
    group = Group.lookup(current_user, assignment)
    if not group:
        flash("You are not in a group")
    else:
        try:

            if action == "accept":
                group.accept(current_user)
                subject = "{0} has accepted the invitation to join your group".format(current_user.email)
                body = "Your group for {0} now has {1} members".format(assignment.display_name,
                                                                       len(group.members))
                group_action_email(group.members, subject, body)
            elif action == "decline":
                members = [m.user.email for m in group.members]
                group.decline(current_user)
                subject = "{0} declined an invite to join the group".format(current_user.email)
                body = "{0} declined to join the group for {1}".format(current_user.email,
                                                                       assignment.display_name)
                send_email(members, subject, body)
            elif action == "revoke":
                members = [m.user.email for m in group.members]
                group.decline(current_user)
                subject = "{0} invitation for {1} revoked".format(assignment.display_name,
                                                                  target)
                body = "{0} has revoked the invitation for {1}".format(current_user.email,
                                                                       target)
                send_email(members, subject, body)

        except BadRequest as e:
            flash(e.description, 'danger')
    return redirect(url_for('.assignment', name=assignment.name))
Exemple #46
0
    def setUp(self):
        """ Add submissions for 3 users. """
        super(TestRevision, self).setUp()
        self.setup_course()

        message_dict = {'file_contents': {'backup.py': '1'}, 'analytics': {}}

        self.active_user_ids = [self.user1.id, self.user2.id, self.user3.id]

        self.assignment.revisions_allowed = True

        time = self.assignment.due_date  # Set to dt.now(), so future subms are late
        for user_id in self.active_user_ids:
            time -= datetime.timedelta(minutes=15)
            backup = Backup(submitter_id=user_id,
                            assignment=self.assignment,
                            submit=True)
            # Revisions are submitted on time.
            backup.created = time
            messages = [
                Message(kind=k, backup=backup, contents=m)
                for k, m in message_dict.items()
            ]
            db.session.add_all(messages)
            db.session.add(backup)

        # Put user 3 in a group with user 4
        Group.invite(self.user3, self.user4, self.assignment)
        group = Group.lookup(self.user3, self.assignment)
        group.accept(self.user4)

        okversion = Version(name="ok-client",
                            current_version="v1.5.0",
                            download_link="http://localhost/ok")
        db.session.add(okversion)

        db.session.commit()
Exemple #47
0
def submit_assignment(name):
    assign = get_assignment(name)
    group = Group.lookup(current_user, assign)
    user_ids = assign.active_user_ids(current_user.id)
    fs = assign.final_submission(user_ids)

    if not assign.uploads_enabled:
        flash("This assignment cannot be submitted online", 'warning')
        return redirect(url_for('.assignment', name=assign.name))
    if not assign.active:
        flash("It's too late to submit this assignment", 'warning')
        return redirect(url_for('.assignment', name=assign.name))

    form = UploadSubmissionForm()
    if form.validate_on_submit():
        files = request.files.getlist("upload_files")
        if files:
            templates = assign.files
            messages = {'file_contents': {}}
            for upload in files:
                data = upload.read()
                if len(data) > 2097152:
                    # File is too large (over 2 MB)
                    flash(
                        "{} is over the maximum file size limit of 2MB".format(
                            upload.filename), 'danger')
                    return redirect(
                        url_for('.submit_assignment', name=assign.name))
                messages['file_contents'][upload.filename] = str(
                    data, 'latin1')
            if templates:
                missing = []
                for template in templates:
                    if template not in messages['file_contents']:
                        missing.append(template)
                if missing:
                    flash((
                        "Missing files: {}. The following files are required: {}"
                        .format(', '.join(missing), ', '.join(
                            [t for t in templates]))), 'danger')
                    return redirect(
                        url_for('.submit_assignment', name=assign.name))

            backup = make_backup(current_user, assign.id, messages, True)
            if form.flag_submission.data:
                assign.flag(backup.id, user_ids)
            if assign.autograding_key:
                try:
                    submit_continous(backup)
                except ValueError as e:
                    logger.warning('Web submission did not autograde',
                                   exc_info=True)
                    flash('Did not send to autograder: {}'.format(e),
                          'warning')

            flash("Uploaded submission (ID: {})".format(backup.hashid),
                  'success')
            return redirect(url_for('.assignment', name=assign.name))

    return render_template('student/assignment/submit.html',
                           assignment=assign,
                           group=group,
                           course=assign.course,
                           form=form)
Exemple #48
0
def gen_invite(member, invitee, assignment, accept=False):
    Group.invite(member, invitee, assignment)
    group = Group.lookup(invitee, assignment)
    if accept:
        group.accept(invitee)
    return group
Exemple #49
0
    def test_decline_not_pending(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)

        self.assertRaises(BadRequest, group.decline, self.user3)
Exemple #50
0
    def test_log(self):
        def latest_action():
            return GroupAction.query.order_by(GroupAction.id.desc()).first()

        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)

        state = {
            'id': group.id,
            'assignment_id': group.assignment_id,
            'members': []
        }

        action = latest_action()
        assert action.action_type == 'invite'
        assert action.user_id == self.user1.id
        assert action.target_id == self.user2.id
        assert action.group_before == state
        state['members'].append({'user_id': self.user1.id, 'status': 'active'})
        state['members'].append({
            'user_id': self.user2.id,
            'status': 'pending'
        })
        assert action.group_after == state

        group.accept(self.user2)

        action = latest_action()
        assert action.action_type == 'accept'
        assert action.user_id == self.user2.id
        assert action.target_id == self.user2.id
        assert action.group_before == state
        state['members'][1]['status'] = 'active'
        assert action.group_after == state

        Group.invite(self.user1, self.user3, self.assignment)

        action = latest_action()
        assert action.action_type == 'invite'
        assert action.user_id == self.user1.id
        assert action.target_id == self.user3.id
        assert action.group_before == state
        state['members'].append({
            'user_id': self.user3.id,
            'status': 'pending'
        })
        assert action.group_after == state

        group.decline(self.user3)

        action = latest_action()
        assert action.action_type == 'decline'
        assert action.user_id == self.user3.id
        assert action.target_id == self.user3.id
        assert action.group_before == state
        state['members'].pop(2)
        assert action.group_after == state

        group.remove(self.user2, self.user1)
        action = latest_action()
        assert action.action_type == 'remove'
        assert action.user_id == self.user2.id
        assert action.target_id == self.user1.id
        assert action.group_before == state
        state['members'] = []
        assert action.group_after == state
Exemple #51
0
def submit_assignment(name):
    # TODO: Unify student & staff upload.
    assign = get_assignment(name)
    group = Group.lookup(current_user, assign)
    user_ids = assign.active_user_ids(current_user.id)
    fs = assign.final_submission(user_ids)
    if not assign.uploads_enabled:
        flash("This assignment cannot be submitted online", 'warning')
        return redirect(url_for('.assignment', name=assign.name))

    extension = None # No need for an extension
    if not assign.active:
        extension = Extension.get_extension(current_user, assign)
        if not extension:
            flash("It's too late to submit this assignment", 'warning')
            return redirect(url_for('.assignment', name=assign.name))

    if request.method == "POST":
        backup = Backup.create(
            submitter=current_user,
            assignment=assign,
            submit=True,
        )
        assignment = backup.assignment
        if extension:
            backup.custom_submission_time = extension.custom_submission_time

        templates = assignment.files or []
        files = {}

        def extract_file_index(file_ind):
            """ Get the index of of file objects. Used because
            request.files.getlist() does not handle uniquely indexed
            lists.
            >>> extract_file_index('file[12'])
            12
            """
            brace_loc = file_ind.find('[')
            index_str = file_ind[brace_loc+1:-1]
            return int(index_str)


        # A list of one element lists
        sorted_uploads = sorted(list(request.files.items()),
                                key=lambda x: extract_file_index(x[0]))
        uploads = [v[1] for v in sorted_uploads]
        full_path_names = list(request.form.listvalues())[0]

        template_files = assign.files or []
        file_names = [os.path.split(f)[1] for f in full_path_names]
        missing = [t for t in template_files if t not in file_names]
        if missing:
            return jsonify({
                'error': ('Missing files: {}. The following files are required: {}'
                          .format(', '.join(missing), ', '.join(template_files)))
            }), 400

        backup_folder_postfix = time.time()

        for full_path, upload in zip(full_path_names, uploads):
            data = upload.read()
            if len(data) > MAX_UPLOAD_FILE_SIZE:  # file is too large (over 25 MB)
                return jsonify({
                  'error': ('{} is larger than the maximum file size of {} MB'
                            .format(full_path, MAX_UPLOAD_FILE_SIZE/1024/1024))
                }), 400
            try:
                files[full_path] = str(data, 'utf-8')
            except UnicodeDecodeError:
                upload.stream.seek(0) # We've already read data, so reset before uploading
                dest_folder = "uploads/{}/{}/{}/".format(assign.name, current_user.id, backup_folder_postfix)
                bin_file = ExternalFile.upload(upload.stream, current_user.id, full_path,
                                               staff_file=False, prefix=dest_folder,
                                               course_id=assign.course.id,
                                               backup=backup, assignment_id=assign.id)
                db.session.add(bin_file)

        message = Message(kind='file_contents', contents=files)
        backup.messages.append(message)

        db.session.add(backup)
        db.session.commit()

        # Send to continuous autograder
        if assign.autograding_key and assign.continuous_autograding:
            try:
                submit_continuous(backup)
            except ValueError as e:
                flash('Did not send to autograder: {}'.format(e), 'warning')

        return jsonify({
            'backup': backup.hashid,
            'url': url_for('.code', name=assign.name, submit=backup.submit,
                           bid=backup.id)
        })

    return render_template('student/assignment/submit.html', assignment=assign,
                           group=group, course=assign.course)
Exemple #52
0
def gen_invite(member, invitee, assignment, accept=False):
    Group.invite(member, invitee, assignment)
    group = Group.lookup(invitee, assignment)
    if accept:
        group.accept(invitee)
    return group
Exemple #53
0
    def test_log(self):
        def latest_action():
            return GroupAction.query.order_by(GroupAction.id.desc()).first()

        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)

        state = {
            'id': group.id,
            'assignment_id': group.assignment_id,
            'members': []
        }

        action = latest_action()
        assert action.action_type == 'invite'
        assert action.user_id == self.user1.id
        assert action.target_id == self.user2.id
        assert action.group_before == state
        state['members'].append({
            'user_id': self.user1.id,
            'status': 'active'
        })
        state['members'].append({
            'user_id': self.user2.id,
            'status': 'pending'
        })
        assert action.group_after == state

        group.accept(self.user2)

        action = latest_action()
        assert action.action_type == 'accept'
        assert action.user_id == self.user2.id
        assert action.target_id == self.user2.id
        assert action.group_before == state
        state['members'][1]['status'] = 'active'
        assert action.group_after == state

        Group.invite(self.user1, self.user3, self.assignment)

        action = latest_action()
        assert action.action_type == 'invite'
        assert action.user_id == self.user1.id
        assert action.target_id == self.user3.id
        assert action.group_before == state
        state['members'].append({
            'user_id': self.user3.id,
            'status': 'pending'
        })
        assert action.group_after == state

        group.decline(self.user3)

        action = latest_action()
        assert action.action_type == 'decline'
        assert action.user_id == self.user3.id
        assert action.target_id == self.user3.id
        assert action.group_before == state
        state['members'].pop(2)
        assert action.group_after == state

        group.remove(self.user2, self.user1)
        action = latest_action()
        assert action.action_type == 'remove'
        assert action.user_id == self.user2.id
        assert action.target_id == self.user1.id
        assert action.group_before == state
        state['members'] = []
        assert action.group_after == state
Exemple #54
0
    def test_decline_not_pending(self):
        Group.invite(self.user1, self.user2, self.assignment)
        group = Group.lookup(self.user1, self.assignment)

        self.assertRaises(BadRequest, group.decline, self.user3)