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()
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
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)
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
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)
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)
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)
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()
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
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_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_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)
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)
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)
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
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 ""
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))
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)
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)
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)
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 ""
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
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)
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))
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))
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_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)
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
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)
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)
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)
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 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()
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)
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
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')
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)
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)
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))
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))