Пример #1
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()
Пример #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
Пример #3
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)
Пример #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
Пример #5
0
def staff_group_add(cid, email, aid):
    assign = Assignment.query.filter_by(id=aid, course_id=cid).one_or_none()
    if not assign or not Assignment.can(assign, current_user, 'grade'):
        flash('Cannot access assignment', 'error')
        return abort(404)

    form = forms.StaffAddGroupFrom()
    result_page = url_for('.student_assignment_detail', cid=cid,
                          email=email, aid=aid)

    student = User.lookup(email)
    if not student:
        return abort(404)

    if form.validate_on_submit():
        target = User.lookup(form.email.data)
        if not target or not target.is_enrolled(cid):
            flash("This user is not enrolled", 'warning')
            return redirect(result_page)
        try:
            Group.force_add(current_user, student, target, assign)
        except BadRequest as e:
            flash("Error: {}".format(str(e.description)), 'error')
            return redirect(result_page)

    return redirect(result_page)
Пример #6
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
Пример #7
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
Пример #8
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)
Пример #9
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)
Пример #10
0
def staff_group_remove(cid, email, aid):
    assign = Assignment.query.filter_by(id=aid, course_id=cid).one_or_none()
    if not assign or not Assignment.can(assign, current_user, 'grade'):
        return abort(404)

    student = User.lookup(email)
    if not student:
        abort(404)

    result_page = url_for('.student_assignment_detail',
                          cid=cid,
                          email=email,
                          aid=aid)

    form = forms.CSRFForm()
    if form.validate_on_submit():
        target = User.lookup(request.form['target'])
        if not target:
            flash('{} does not exist'.format(request.form['target']), 'error')
            return redirect(result_page)
        try:
            Group.force_remove(current_user, student, target, assign)
        except BadRequest as e:
            flash("Error: {}".format(str(e.description)), 'error')
    return redirect(result_page)
Пример #11
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)
Пример #12
0
def staff_group_add(cid, email, aid):
    assign = Assignment.query.filter_by(id=aid, course_id=cid).one_or_none()
    if not assign or not Assignment.can(assign, current_user, 'grade'):
        flash('Cannot access assignment', 'error')
        return abort(404)

    form = forms.StaffAddGroupFrom()
    result_page = url_for('.student_assignment_detail', cid=cid,
                          email=email, aid=aid)

    student = User.lookup(email)
    if not student:
        return abort(404)

    if form.validate_on_submit():
        target = User.lookup(form.email.data)
        if not target or not target.is_enrolled(cid):
            flash("This user is not enrolled", 'warning')
            return redirect(result_page)
        try:
            Group.force_add(current_user, student, target, assign)
        except BadRequest as e:
            flash("Error: {}".format(str(e.description)), 'error')
            return redirect(result_page)

    return redirect(result_page)
Пример #13
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()
Пример #14
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()
Пример #15
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
Пример #16
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
Пример #17
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
Пример #18
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
Пример #19
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}
Пример #20
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}
Пример #21
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)
Пример #22
0
    def test_invite_in_group(self):
        Group.invite(self.user1, self.user2, self.assignment)

        self.assertRaises(BadRequest, Group.invite, self.user1, self.user1, self.assignment)
        self.assertRaises(BadRequest, Group.invite, self.user1, self.user2, self.assignment)

        self.assertRaises(BadRequest, Group.invite, self.user2, self.user1, self.assignment)
        self.assertRaises(BadRequest, Group.invite, self.user2, self.user2, self.assignment)
        self.assertRaises(BadRequest, Group.invite, self.user2, self.user3, self.assignment)

        self.assertRaises(BadRequest, Group.invite, self.user3, self.user1, self.assignment)
        self.assertRaises(BadRequest, Group.invite, self.user3, self.user2, self.assignment)
        self.assertRaises(BadRequest, Group.invite, self.user3, self.user3, self.assignment)
Пример #23
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)
Пример #24
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
Пример #25
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
Пример #26
0
    def create(cls):
        # get group name from request
        group_name = request.form.get("groupName", u"", type=unicode)

        if group_name != "":
            # create group
            group = Group(name=group_name)
            group_key = group.put()

            group_id = group_key.id()
            url = request.url_root + "chat/" + str(group_id)

            return jsonify(id=group_id, url=url)
        else:
            return ""
Пример #27
0
def group_invite(name):
    assignment = get_assignment(name)
    email = request.form['email']
    invitee = User.lookup(email)
    if not invitee:
        flash("{0} is not enrolled".format(email), 'warning')
    else:
        try:
            Group.invite(current_user, invitee, assignment)
            success = "{0} has been invited. They can accept the invite by logging into okpy.org".format(email)
            invite_email(current_user, invitee, assignment)
            flash(success, "success")
        except BadRequest as e:
            flash(e.description, 'danger')
    return redirect(url_for('.assignment', name=assignment.name))
Пример #28
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)
Пример #29
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'))
def main(argv=sys.argv):
    if len(argv) != 2:
        usage(argv)
    config_uri = argv[1]
    setup_logging(config_uri)
    settings = get_appsettings(config_uri)
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.create_all(engine)

    with transaction.manager:
        # Create default models

        group = Group(name="group:admin")
        DBSession.add(group)

        user = User(name='Test', password=hash_password('1234'))
        DBSession.add(user)

        new_group_id = int(
            DBSession.query(Group).filter(Group.name == group.name).first().id)

        new_user_id = int(
            DBSession.query(User).filter(User.name == user.name).first().id)

        user_in_group = UserInGroup(user_id=new_user_id, group_id=new_group_id)
        DBSession.add(user_in_group)
Пример #31
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'))
Пример #32
0
    def test_group_submit_with_extension(self):
        self.set_offset(-2) # Lock assignment

        # Should fail because it's late.
        self._submit_to_api(self.user2, False)

        Group.force_add(self.staff1, self.user1, self.user2, self.assignment)
        ext = self._make_ext(self.assignment, self.user1)

        # An extension for user1 should also apply to all members of the group
        self._submit_to_api(self.user2, True)
        self._submit_to_api(self.user1, True)
        self._submit_to_api(self.user3, False)

        Group.force_add(self.staff1, self.user1, self.user3, self.assignment)
        self._submit_to_api(self.user3, True)
Пример #33
0
    def create(cls, group_id, msg_type):
        group = Group.get_by_id(group_id)
        participant_key = None
        participant_id = request.cookies.get("participant_id")

        if participant_id:
            participant_key = Participant.get_by_id(long(participant_id)).key

        message = request.form.get("message", u"", type=unicode)
        reference_id = request.form.get("reference", u"", type=unicode)

        chat = Chat(
            group_key=group.key,
            participant_key=participant_key,
            type=msg_type,
            message=message
        )

        #set reference if exist
        if reference_id:
            reference = Chat.get_by_id(long(reference_id))
            if reference is not None:
                chat.reference = reference.key.id()

        chat.put()

        # send same group members (include myself)
        cls.__broadcast(group_id, chat)

        # message is send by channel, so you don't need return
        return ""
Пример #34
0
    def index(cls, group_id):
        # confirm participant id in cookie
        c_group_id = request.cookies.get("group_id")
        participant_id = request.cookies.get("participant_id")

        # get group
        group = Group.get_by_id(group_id)

        # if participant is none or login to another group, create new participant in group
        if not participant_id or c_group_id != str(group_id):
            # create new participant todo:consider the case that group is None
            participant = Participant()
            participant.group_key = group.key
            participant_id = participant.put().id()  # save it to datastore

        # create channel
        participant_id_str = str(participant_id)
        cache = GAEMemcachedCache()
        token = cache.get(participant_id_str)
        if token is None:
            token = channel.create_channel(participant_id_str)
            # expiration of channel api token is 2 hour
            # https://developers.google.com/appengine/docs/python/channel/?hl=ja#Python_Tokens_and_security
            cache.set(participant_id_str, token, 3600 * 2)

        # return response
        resp = make_response(render_template('chat.html', token=token, group_name=group.name))

        # set participant_id to cookie
        resp.set_cookie("group_id", str(group_id),  expires=Config.calculate_expiration())
        resp.set_cookie("participant_id", participant_id_str, expires=Config.calculate_expiration())

        return resp
Пример #35
0
    def test_group_submit_with_extension(self):
        self.set_offset(-1) # Lock assignment

        # Should fail because it's late.
        self._submit_to_api(self.user2, False)

        Group.force_add(self.staff1, self.user1, self.user2, self.assignment)
        ext = self._make_ext(self.assignment, self.user1)

        # An extension for user1 should also apply to all members of the group
        self._submit_to_api(self.user2, True)
        self._submit_to_api(self.user1, True)
        self._submit_to_api(self.user3, False)

        Group.force_add(self.staff1, self.user1, self.user3, self.assignment)
        self._submit_to_api(self.user3, True)
Пример #36
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)
Пример #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))
Пример #38
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))
Пример #39
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}
Пример #40
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)
Пример #41
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
Пример #42
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
Пример #43
0
    def test_submit_between_due_and_lock(self):
        """ Extensions should also change the custom submission time
        when submitted after the due date but before the lock date.
        """
        self.assignment.due_date = dt.datetime.utcnow() + dt.timedelta(hours=-1)
        self.assignment.lock_date = dt.datetime.utcnow() + dt.timedelta(hours=1)

        Group.force_add(self.staff1, self.user1, self.user2, self.assignment)

        # User 1 is allowed to submit since it's between due and lock date
        self._submit_to_api(self.user1, True)
        first_back = Backup.query.filter(Backup.submitter_id == self.user1.id,
                                         Backup.submit == True).first()
        self.assertIsNone(first_back.custom_submission_time)
        ext = self._make_ext(self.assignment, self.user1)
        self._submit_to_api(self.user2, True)

        second_back = Backup.query.filter(Backup.submitter_id == self.user2.id,
                                          Backup.submit == True).first()
        # The submission from User 2 should have a custom submission time
        self.assertEquals(second_back.custom_submission_time, ext.custom_submission_time)
Пример #44
0
    def test_submit_between_due_and_lock(self):
        """ Extensions should also change the custom submission time
        when submitted after the due date but before the lock date.
        """
        self.assignment.due_date = dt.datetime.utcnow() + dt.timedelta(hours=-1)
        self.assignment.lock_date = dt.datetime.utcnow() + dt.timedelta(hours=1)

        Group.force_add(self.staff1, self.user1, self.user2, self.assignment)

        # User 1 is allowed to submit since it's between due and lock date
        self._submit_to_api(self.user1, True)
        first_back = Backup.query.filter(Backup.submitter_id == self.user1.id,
                                         Backup.submit == True).first()
        self.assertIsNone(first_back.custom_submission_time)
        ext = self._make_ext(self.assignment, self.user1)
        self._submit_to_api(self.user2, True)

        second_back = Backup.query.filter(Backup.submitter_id == self.user2.id,
                                          Backup.submit == True).first()
        # The submission from User 2 should have a custom submission time
        self.assertEqual(second_back.custom_submission_time, ext.custom_submission_time)
Пример #45
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)
Пример #46
0
    def test_invite_in_group(self):
        Group.invite(self.user1, self.user2, self.assignment)

        self.assertRaises(BadRequest, Group.invite, self.user1, self.user1,
                          self.assignment)
        self.assertRaises(BadRequest, Group.invite, self.user1, self.user2,
                          self.assignment)

        self.assertRaises(BadRequest, Group.invite, self.user2, self.user1,
                          self.assignment)
        self.assertRaises(BadRequest, Group.invite, self.user2, self.user2,
                          self.assignment)
        self.assertRaises(BadRequest, Group.invite, self.user2, self.user3,
                          self.assignment)

        self.assertRaises(BadRequest, Group.invite, self.user3, self.user1,
                          self.assignment)
        self.assertRaises(BadRequest, Group.invite, self.user3, self.user2,
                          self.assignment)
        self.assertRaises(BadRequest, Group.invite, self.user3, self.user3,
                          self.assignment)
Пример #47
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}
Пример #48
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)
Пример #49
0
def staff_group_remove(cid, email, aid):
    assign = Assignment.query.filter_by(id=aid, course_id=cid).one_or_none()
    if not assign or not Assignment.can(assign, current_user, 'grade'):
        return abort(404)

    student = User.lookup(email)
    if not student:
        abort(404)

    result_page = url_for('.student_assignment_detail', cid=cid,
                          email=email, aid=aid)

    form = forms.CSRFForm()
    if form.validate_on_submit():
        target = User.lookup(request.form['target'])
        if not target:
            flash('{} does not exist'.format(request.form['target']), 'error')
            return redirect(result_page)
        try:
            Group.force_remove(current_user, student, target, assign)
        except BadRequest as e:
            flash("Error: {}".format(str(e.description)), 'error')
    return redirect(result_page)
Пример #50
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()
Пример #51
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)
Пример #52
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
Пример #53
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')
Пример #54
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
Пример #55
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')
Пример #56
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)
Пример #57
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)
Пример #58
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))
Пример #59
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))