def test_delete_issues_allowed_endpoints_jwt(self): """DELETE response has special jwt giving permission on Neptune.""" user, team_dict = self.create() # Add some classrooms. c1 = Classroom.create( name='C1', team_id=team_dict['uid'], contact_id='User_contact', code='a a', ) c2 = Classroom.create( name='C2', team_id=team_dict['uid'], contact_id='User_contact', code='b b', ) Classroom.put_multi([c1, c2]) response = self.testapp.delete( '/api/teams/{}'.format(team_dict['uid']), headers=self.login_headers(user), ) jwt = response.headers['Authorization'][7:] # drop "Bearer " payload, error = jwt_helper.decode(jwt) # Should include an endpoint for each classroom. self.assertEqual( set(payload['allowed_endpoints']), { 'DELETE //neptune/api/codes/a-a', 'DELETE //neptune/api/codes/b-b', }, )
def test_rserve_ru_override(self): """Can specify reporting unit ids to limit RServe request.""" team = Team.create(name='Team Foo', captain_id='User_captain', program_id=self.ep_program.uid) classroom1 = Classroom.create(name='Classroom One', team_id=team.uid, contact_id='User_contact', code='foo 1') classroom2 = Classroom.create(name='Classroom Two', team_id=team.uid, contact_id='User_contact', code='foo 2') classroom3 = Classroom.create(name='Classroom Three', team_id=team.uid, contact_id='User_contact', code='foo 3') team.put() Classroom.put_multi((classroom1, classroom2, classroom3)) response = self.testapp.get( '/cron/rserve/reports/ep?ru={}&ru={}&really_send=false'.format( classroom1.uid, classroom2.uid)) payload = json.loads(response.body)['payload'] # Only specified ids are present (class 1 and 2). self.assertEqual( set(ru['id'] for ru in payload['reporting_units']), {classroom1.uid, classroom2.uid}, )
def test_rserve_skips_existing(self): program = Program.create( name="The Engagement Project", label="ep19", preview_url='foo.com', ) week = util.datelike_to_iso_string(datetime.date.today()) org = Organization.create(name="Organization", captain_id="User_cap", program_id=program.uid) org_to_skip = Organization.create(name="Organization", captain_id="User_cap", program_id=program.uid) Organization.put_multi([org, org_to_skip]) team = Team.create(name="Team", captain_id="User_cap", program_id=program.uid) team_to_skip = Team.create(name="Team", captain_id="User_cap", program_id=program.uid) Team.put_multi([team, team_to_skip]) cl = Classroom.create(name="Classroom", team_id=team.uid, code="foo", contact_id="User_contact") cl_to_skip = Classroom.create(name="Classroom", team_id=team.uid, code="foo", contact_id="User_contact") Classroom.put_multi([cl, cl_to_skip]) Report.put_multi([ Report.create(parent_id=org_to_skip.uid, filename="foo", issue_date=week), Report.create(parent_id=team_to_skip.uid, filename="foo", issue_date=week), Report.create(parent_id=cl_to_skip.uid, filename="foo", issue_date=week), ]) # Skips all the parents who have reports already this week. orgs, teams, classes = cron_rserve.get_report_parents( program, week, False) self.assertEqual(len(orgs), 1) self.assertEqual(len(teams), 1) self.assertEqual(len(classes), 1) # ...unless you force it, then they're all there. orgs, teams, classes = cron_rserve.get_report_parents( program, week, True) self.assertEqual(len(orgs), 2) self.assertEqual(len(teams), 2) self.assertEqual(len(classes), 2)
def test_rserve_payload(self): org = Organization.create(name='Org', program_id=self.ep_program.uid) team = Team.create(name='Team Foo', captain_id='User_captain', program_id=self.ep_program.uid) classroom = Classroom.create(name='Classroom Bar', team_id=team.uid, contact_id='User_contact') # Orphaned classrooms shouldn't appear in the payload. other_classroom = Classroom.create(name='Classroom Other', team_id='Team_other', contact_id='User_other') payload = cron_rserve.build_payload( [org], [team], [classroom, other_classroom], { 'neptune_sql_credentials': 'fake secret 1', 'triton_sql_credentials': 'fake secret 2', 'saturn_sql_credentials': 'fake secret 3', 'qualtrics_credentials': 'fake secret 4', 'mandrill_api_key': 'fake secret 5', 'rserve_service_account_credentials': 'fake secret 6', }, ) self.assertIn('neptune_sql_credentials', payload) self.assertIn('triton_sql_credentials', payload) self.assertIn('saturn_sql_credentials', payload) self.assertIn('qualtrics_credentials', payload) self.assertIn('mandrill_api_key', payload) self.assertIn('rserve_service_account_credentials', payload) team_found = False classroom_found = False other_classroom_found = False for ru in payload['reporting_units']: if ru['id'] == org.uid and ru['organization_id'] == org.uid: org_found = True if ru['id'] == team.uid and ru['team_id'] == team.uid: team_found = True if (ru['id'] == classroom.uid and ru['classroom_id'] == classroom.uid and ru['team_id'] == team.uid): classroom_found = True if ru['id'] == other_classroom.uid: other_classroom_found = True self.assertEqual(org_found, True) self.assertEqual(team_found, True) self.assertEqual(classroom_found, True) self.assertEqual(other_classroom_found, False)
def create(self, program_label): program = Program.create( name="Foo", label=program_label, active=True, preview_url='foo.com', ) program.put() captain = User.create(email='*****@*****.**', name="Captain PERTS") team = Team.create(name='Team Foo', program_id=program.uid, captain_id=captain.uid) team.put() classrooms = [ Classroom.create(name='Class A', team_id=team.uid, num_students=5, contact_id='User_contact', code='foo'), Classroom.create(name='Class B', team_id=team.uid, num_students=5, contact_id='User_contact', code='bar'), Classroom.create(name='Class C', team_id=team.uid, num_students=5, contact_id='User_contact', code='baz'), ] Classroom.put_multi(classrooms) survey = Survey.create(team_id=team.uid) survey.put() captain.owned_teams = [team.uid] captain.put() start_date = datetime.date.today() - datetime.timedelta(days=7) end_date = datetime.date.today() + datetime.timedelta(days=7) cycle = Cycle.create(team_id=team.uid, ordinal=1, start_date=start_date, end_date=end_date) cycle.put() return (program, captain, team, classrooms, cycle)
def create(self): """Team owners can create classrooms with themselves as contact.""" captain = User.create(email='*****@*****.**') contact = User.create(email='*****@*****.**') # other = User.create(email='*****@*****.**') team = Team.create(name='Foo Team', captain_id=captain.uid, program_id=self.program.uid) team.put() classroom = Classroom.create(name='Foo Classroom', team_id=team.uid, code='trout viper', contact_id=contact.uid) classroom.put() captain.owned_teams = [team.uid] captain.put() contact.owned_teams = [team.uid] contact.put() # other.put() # return team, classroom, captain, contact, other return team, classroom, captain, contact
def test_delete_forbidden(self): """Only team captains can delete classrooms.""" teammate = User.create(name='teammate', email='*****@*****.**') other = User.create(name='other', email='*****@*****.**') team = Team.create(name='Team Foo', captain_id='User_captain', program_id=self.program.uid) team.put() teammate.owned_teams = [team.uid] User.put_multi([teammate, other]) classroom = Classroom.create( name='Classroom Foo', code='trout viper', team_id=team.uid, contact_id='User_contact', num_students=22, grade_level='9-12', ) classroom.put() for user in (teammate, other): self.testapp.delete( '/api/classrooms/{}'.format(classroom.uid), headers=self.login_headers(user), status=403, )
def test_disallow_classroom_move(self): """Update the team_id of all class reports when class moves.""" user = User.create(name='foo', email='*****@*****.**') team1 = Team.create(name='Team Foo', captain_id=user.uid, program_id=self.program.uid) team1.put() team2 = Team.create(name='Team Bar', captain_id=user.uid, program_id=self.program.uid) team2.put() user.owned_teams = [team1.uid, team2.uid] user.put() classroom = Classroom.create( name='Classroom Foo', code='trout viper', team_id=team1.uid, contact_id=user.uid, num_students=22, grade_level='9-12', ) classroom.put() # move class to new team self.testapp.put_json( '/api/classrooms/{}'.format(classroom.uid), {'team_id': team2.uid}, headers=self.login_headers(user), status=403, )
def create(self): other = User.create(name='other', email='*****@*****.**') teammate = User.create(name='teammate', email='*****@*****.**') contact = User.create(name='contact', email='*****@*****.**') captain = User.create(name='captain', email='*****@*****.**') super_admin = User.create(name='super', email='*****@*****.**', user_type='super_admin') team = Team.create(name='Team foo', captain_id=captain.uid, program_id=self.program.uid) team.put() classroom = Classroom.create(name='Class foo', team_id=team.uid, code='trout viper', contact_id=contact.uid) classroom.put() teammate.owned_teams.append(team.uid) contact.owned_teams.append(team.uid) captain.owned_teams.append(team.uid) User.put_multi((other, teammate, contact, captain, super_admin)) return (other, teammate, contact, captain, super_admin, team, classroom)
def test_status_code_not_found_returned_when_student_id(self): """404 Not Found is returned when class exists but student_id doesn't.""" code = 'forest temple' student_id = 'zelda' bad_student_id = 'NOTzelda' team = Team.create( name="Foo Team", captain_id="User_cap", program_id=self.program.uid, ) team.put() classroom = Classroom.create( code=code, name='Adventuring 101', contact_id='User_LINK', team_id=team.uid, ) classroom.put() participant = Participant.create( student_id=student_id, team_id=team.uid, classroom_ids=[classroom.uid], ) participant.put() self.testapp.get( '/api/codes/{}/participants/{}'.format(code, bad_student_id), status=404, )
def test_get_main_contacts(self): contact1 = User.create(email="*****@*****.**") contact2 = User.create(email="*****@*****.**") contact1.put() contact2.put() classroom1 = Classroom.create(name="Foo", team_id="foo", code='a a', contact_id=contact1.uid) classroom2 = Classroom.create(name="Bar", team_id="bar", code='b b', contact_id=contact2.uid) contacts = User.get_main_contacts([classroom1, classroom2]) self.assertEqual(set(contacts), {contact1, contact2})
def test_post_empty_report(self): """RServe posts "empty" reports to note why it hasn't produced a visible report. Test that the API accepts these for each kind of parent. """ rserve_user = User.create( id='rserve', email='*****@*****.**', user_type='super_admin', ) rserve_user.put() org = Organization.create(name='Organization', captain_id='User_cap', program_id=self.program.uid) org.put() team = Team.create( name='Team Foo', captain_id='User_cap', organization_ids=[org.uid], program_id=self.program.uid, ) team.put() classroom = Classroom.create(name='Class foo', team_id=team.uid, code='trout viper', contact_id='User_contact') classroom.put() url = '/api/reports' report_date = datetime.date.today().strftime('%Y-%m-%d') self.testapp.post_json( url, dict(self.empty_report_params(report_date, org.uid), organization_id=org.uid), headers=self.login_headers(rserve_user), ) self.testapp.post_json( url, dict(self.empty_report_params(report_date, team.uid), team_id=team.uid), headers=self.login_headers(rserve_user), ) self.testapp.post_json( url, dict(self.empty_report_params(report_date, classroom.uid), team_id=team.uid, classroom_id=classroom.uid), headers=self.login_headers(rserve_user), ) reports = Report.get() self.assertEqual(len(reports), 3) self.assertEqual(all(r.template == 'empty' for r in reports), True)
def create_for_search(self): # Test that users can be matched on either name or email. admin_foo = User.create(name="Admin Foo", email="*****@*****.**") user_foo1 = User.create(name="User Foo", email="*****@*****.**") user_foo2 = User.create(name="Generic Name", email="*****@*****.**") user_bar = User.create(name="User Bar", email="*****@*****.**") org_foo = Organization.create(name="Org Foo", program_id=self.ep.uid) org_bar = Organization.create(name="Org Bar", program_id=self.ep.uid) team_foo = Team.create(name="Team Foo", program_id=self.ep.uid, captain_id=user_foo1.uid) team_bar = Team.create(name="Team Bar", program_id=self.ep.uid, captain_id=user_bar.uid) cl_foo = Classroom.create( name="Class Foo", code="foo", team_id=team_foo.uid, contact_id=user_foo2.uid, ) cl_bar = Classroom.create( name="Class Bar", code="bar", team_id=team_bar.uid, contact_id="User_contact", ) # Test that users can be matched on either name or email. admin_foo.owned_organizations = [org_foo.uid] user_foo1.owned_teams = [team_foo.uid] user_foo2.owned_teams = [team_foo.uid] user_bar.owned_teams = [team_bar.uid] Organization.put_multi([org_foo, org_bar]) Team.put_multi([team_foo, team_bar]) Classroom.put_multi([cl_foo, cl_bar]) User.put_multi([admin_foo, user_foo1, user_foo2, user_bar]) return (org_foo, org_bar, team_foo, team_bar, cl_foo, cl_bar, admin_foo, user_foo1, user_foo2, user_bar)
def test_put_issues_allowed_endpoints_jwt(self): """PUT response has special jwt giving permission on Neptune.""" team_id = 'Team_foo' survey = Survey.create(team_id=team_id) survey.put() user = User.create(name='foo', email='*****@*****.**', owned_teams=[team_id]) user.put() # Add some classrooms c1 = Classroom.create(name='C1', team_id=team_id, code='a a', contact_id='User_contact') c2 = Classroom.create(name='C2', team_id=team_id, code='b b', contact_id='User_contact') Classroom.put_multi([c1, c2]) response = self.testapp.put_json( '/api/surveys/{}'.format(survey.uid), {'metrics': ['Metric_001', 'Metric_002']}, headers=self.login_headers(user), ) jwt = response.headers['Authorization'][7:] # drop "Bearer " payload, error = jwt_helper.decode(jwt) # Should include an endpoint for each classroom. self.assertEqual( set(payload['allowed_endpoints']), { 'PUT //neptune/api/codes/a-a', 'PUT //neptune/api/codes/b-b', }, )
def test_initial_contact_name(self): cl = Classroom.create(name="Classroom", team_id="Team_foo", code="foo") user = User.create(email="*****@*****.**", name="Cleopatra") cl.contact_id = user.uid cl.put() user.put() # Handling the class for the client should populate memcache. self.assertEqual(cl.to_client_dict()['contact_name'], user.name) # Should see the value in the cache directly. cached = memcache.get(util.cached_properties_key(cl.uid)) self.assertEqual(cached['contact_name'], user.name) return (cl, user)
def test_client_dict_has_default_contact_name(self): # Should work whether the contact is saved to the db or not. cl = Classroom.create(name="Classroom", team_id="Team_foo", code="foo", contact_id="User_contact") # No matching user or unsaved class fails gracefully. before_dict = cl.to_client_dict() self.assertEqual(before_dict['contact_name'], '') cl.put() after_dict = cl.to_client_dict() self.assertEqual(after_dict['contact_name'], '')
def create_for_delete(self): """Should delete the classroom and associated reports.""" contact = User.create(name='contact', email='*****@*****.**') captain = User.create(name='foo', email='*****@*****.**') team = Team.create(name='Team Foo', captain_id=captain.uid, program_id=self.program.uid) team.put() captain.owned_teams = [team.uid] contact.owned_teams = [team.uid] User.put_multi([captain, contact]) classroom = Classroom.create( name='Classroom Foo', code='trout viper', team_id=team.uid, contact_id=contact.uid, num_students=22, grade_level='9-12', ) classroom.put() report1 = Report.create( team_id=team.uid, classroom_id=classroom.uid, filename='report1.pdf', gcs_path='/upload/abc', size=10, content_type='application/pdf', ) report1.put() report2 = Report.create( team_id=team.uid, classroom_id=classroom.uid, filename='report2.pdf', gcs_path='/upload/def', size=10, content_type='application/pdf', ) report2.put() return (captain, contact, classroom, report1, report2)
def create(self): captain = User.create(email='*****@*****.**', name="Captain PERTS") teacher = User.create(email='*****@*****.**', name="Edward Teach") team = Team.create(name='Team Foo', program_id='Program_ep', captain_id=captain.uid) classroom = Classroom.create(name='Class Foo', team_id=team.uid, contact_id=teacher.uid) cycle = Cycle.create( team_id=team.uid, ordinal=1, start_date=datetime.date.today() - datetime.timedelta(days=7), end_date=datetime.date.today() + datetime.timedelta(days=7), ) captain.owned_teams = [team.uid] teacher.owned_teams = [team.uid] return (captain, teacher, team, classroom, cycle)
def create(self): team = Team.create(name='foo', program_id=self.program.uid) classroom = Classroom.create( name="CompSci 101", team_id=team.uid, code="foo", ) teammate = User.create(name='teammate', email='*****@*****.**', owned_teams=[team.uid]) contact = User.create(name='contact', email='*****@*****.**', owned_teams=[team.uid]) captain = User.create(name='captain', email='*****@*****.**', owned_teams=[team.uid]) other = User.create(name='other', email='*****@*****.**') team.captain_id = captain.uid classroom.contact_id = contact.uid # O hedgehog of curses, generate for the Finns a part of the game of # ignominies! # http://clagnut.com/blog/2380/ participant = Participant.create( first_name=u'Je\u017cu', last_name=u'Kl\u0105tw', team_id=team.uid, classroom_ids=[classroom.uid], student_id=u'Kl\[email protected]', ) participant.put() User.put_multi((other, teammate, contact, captain)) team.put() classroom.num_students = 1 classroom.put() return (other, teammate, contact, captain, team, classroom, participant)
def test_status_code_found_returned(self): """200 OK returned when student_id is found in classroom roster.""" code = 'forest temple' student_id = 'Zelda 77!' team = Team.create( name="Foo Team", captain_id="User_cap", program_id=self.program.uid, ) team.put() classroom = Classroom.create( code=code, name='Adventuring 101', contact_id='User_LINK', team_id=team.uid, ) classroom.put() participant = Participant.create( student_id=student_id, team_id=team.uid, classroom_ids=[classroom.uid], ) participant.put() # Exact match. self.testapp.get( '/api/codes/{}/participants/{}'.format(code, student_id), status=200, ) # Stripped. self.testapp.get( '/api/codes/{}/participants/{}'.format( code, Participant.strip_token(student_id)), status=200, )
def test_delete_disassociates_participants(self): captain, contact, classroom1, report1, report2 = \ self.create_for_delete() # Create another classroom, so we check that participants remain on it # afterward. classroom2 = Classroom.create( name='Classroom Bar', code='steel snake', team_id=classroom1.team_id, contact_id=contact.uid, num_students=22, ) classroom2.put() ppt_on_one = Participant.create( student_id='on_one', team_id=classroom1.team_id, classroom_ids=[classroom1.uid], ) ppt_on_two = Participant.create( student_id='on_two', team_id=classroom1.team_id, classroom_ids=[classroom1.uid, classroom2.uid], ) Participant.put_multi([ppt_on_one, ppt_on_two]) url = '/api/classrooms/{}'.format(classroom1.uid) headers = self.login_headers(captain) # Delete the classroom. self.testapp.delete(url, headers=headers, status=204) # Both participants are still there, but neither is associated with # the deleted classroom. self.assertEqual( Participant.get_by_id(ppt_on_one.uid).classroom_ids, []) self.assertEqual( Participant.get_by_id(ppt_on_two.uid).classroom_ids, [classroom2.uid])
def test_update_remove_from_multiple_rosters(self): """When ppt is updated to have one fewer classroom id.""" other, teammate, contact, captain, team, classroom, _ = self.create() # Make a second classroom to associate with. classroom2 = Classroom.create( name="Second Classroom", team_id=team.uid, contact_id='User_contact', code="bar", ) # Start with a ppt on two classrooms. ppnt = Participant.create( team_id=team.uid, classroom_ids=[classroom.uid, classroom2.uid], student_id='toremove', ) ppnt.put() # Make sure count of students starts out correct. classroom2.num_students = 1 classroom2.put() # Remove them from just one of their classrooms. response = self.testapp.put_json( '/api/participants/{}'.format(ppnt.uid), {'classroom_ids': [classroom.uid]}, # classroom2 removed headers=jwt_headers(contact), ) # Check they're still on the other classroom. fetched = Participant.get_by_id(ppnt.uid) self.assertEqual(fetched.classroom_ids, [classroom.uid]) # Check that classroom size is updated. fetched_classroom2 = Classroom.get_by_id(classroom2.uid) self.assertEqual(fetched_classroom2.num_students, classroom2.num_students - 1)
def test_get_for_classroom(self): """You can list participants for a team you own.""" other, teammate, contact, captain, team, classroom, ppnt = self.create( ) # Forbidden for non-members. response = self.testapp.get('/api/classrooms/{}/participants'.format( classroom.uid), headers=jwt_headers(other), status=403) # Make sure query excludes participants on other teams and classrooms. other_classroom = Classroom.create(code='foo', team_id=team.uid, contact_id='Lebowski') other_classroom.put() other_team_ppnt = Participant.create( first_name='team', last_name='team', team_id='Team_foo', classroom_ids=['Classroom_foo'], student_id='STUDENTID001', ) other_class_ppnt = Participant.create( first_name='classroom', last_name='classroom', team_id=team.uid, classroom_ids=[other_classroom.uid], student_id='STUDENTID002') Participant.put_multi([other_team_ppnt, other_class_ppnt]) # Successful for members. response = self.testapp.get( '/api/classrooms/{}/participants'.format(classroom.uid), headers=jwt_headers(teammate), ) response_list = json.loads(response.body) self.assertEqual(len(response_list), 1)
def test_ru_filtering(self): team_ep = Team.create( name='Team EP', captain_id='User_captain', program_id=self.ep_program.uid, ) team_ep.put() classroom_ep = Classroom.create( name='Classroom EP', team_id=team_ep.uid, contact_id='User_contact', code='ep 1', ) classroom_ep.put() # Only teams and classrooms for this program are present. response_ep = self.testapp.get( '/cron/rserve/reports/ep?really_send=false') payload_ep = json.loads(response_ep.body)['payload'] self.assertEqual( set((team_ep.uid, classroom_ep.uid)), set(ru['id'] for ru in payload_ep['reporting_units']), )
def test_get_owned(self): """You can get a team you own.""" program = Program.create( name='Program Foo', label='TP1', preview_url='foo.com', ) program.put() team = Team.create(name='foo', captain_id='User_cap', program_id=program.uid) team.put() user = User.create(name='foo', email='*****@*****.**', owned_teams=[team.uid]) user.put() classroom = Classroom.create(name='foo', team_id=team.uid, contact_id=user.uid, code='trout viper') classroom.put() response = self.testapp.get( '/api/teams/{}'.format(team.uid), headers=self.login_headers(user), ) response_dict = json.loads(response.body) self.assertEqual(response_dict['uid'], team.uid) # Should have allowed endpoints for all contained classrooms. jwt_payload, error = jwt_helper.decode( response.headers['Authorization'][7:]) self.assertEqual( jwt_payload['allowed_endpoints'], [ 'GET //neptune/api/project_cohorts/trout-viper/participation', # This endpoint is available also b/c the user is the main # contact of this classroom. 'GET //neptune/api/project_cohorts/trout-viper/completion' ], )
def test_creating_classroom_caches_rel_count(self): team = Team.create(name="Team", captain_id="User_cap", program_id=self.program.uid) classroom = Classroom.create( name="Class Foo", code='trout viper', team_id=team.uid, contact_id='User_contact', ) team.put() # Populate memcache with the team's original value of 0 classrooms. cached = Team.update_cached_properties(team.uid) # This should trigger a memcache update. classroom.put() cached = memcache.get(util.cached_properties_key(team.uid)) self.assertEqual(cached['num_classrooms'], 1) # Should see the same count on object. self.assertEqual(team.to_client_dict()['num_classrooms'], 1) return (team, classroom)
def test_patch_with_existing_participants(self): """Custom PATCH handling: add a batch of participants, some of whom already exist in other classrooms.""" (other, teammate, contact, captain, team, classroom, ppnt) = self.create() extra_classroom = Classroom.create( name="Extra Classroom", code='foo', team_id=team.uid, contact_id=contact.uid, ) extra_classroom.put() wrapper = {'method': 'POST', 'path': '/api/participants'} original_exact = { 'team_id': team.uid, 'classroom_id': extra_classroom.uid, 'student_id': ppnt.student_id, } original_upper = { 'team_id': team.uid, 'classroom_id': extra_classroom.uid, 'student_id': ppnt.student_id.upper(), } original_lower = { 'team_id': team.uid, 'classroom_id': extra_classroom.uid, 'student_id': ppnt.student_id.lower(), } original_extra_characters = { 'team_id': team.uid, 'classroom_id': extra_classroom.uid, # Student tokens are stripped to alphanumerics only, so other # characters here should be ignored. 'student_id': ppnt.student_id + '!', } new_ppnt = { 'team_id': team.uid, 'classroom_id': extra_classroom.uid, 'student_id': 'Student_one', } response = self.testapp.patch_json( '/api/participants', [ dict(wrapper, body=original_exact), dict(wrapper, body=original_upper), dict(wrapper, body=original_lower), dict(wrapper, body=new_ppnt), ], headers=jwt_headers(contact), ) # There should now be a total of 2 participants, one of whom is in # two classrooms. All the differences in case should have been ignored. fetched_all = Participant.get() self.assertEqual(len(fetched_all), 2) fetched_original = next(p for p in fetched_all if p.uid == ppnt.uid) fetched_new = next(p for p in fetched_all if p.uid != ppnt.uid) self.assertIsNotNone(fetched_original) self.assertIsNotNone(fetched_new) self.assertEqual( set(fetched_original.classroom_ids), {classroom.uid, extra_classroom.uid}, ) self.assertEqual( set(fetched_new.classroom_ids), {extra_classroom.uid}, )
def test_check_roster_cycle_data(self): team = Team.create(name='foo', captain_id="User_cap", program_id=self.program.uid) classroom = Classroom.create( name="CompSci 101", team_id=team.uid, contact_id="User_contact", code="foo bar", num_students=1, ) ppt = Participant.create(team_id=team.uid, classroom_ids=[classroom.uid], student_id='STUDENTID001') today = datetime.date.today() cycle1 = Cycle.create( team_id=team.uid, ordinal=1, # schedule to not be current (starts and ends in the past) start_date=today - datetime.timedelta(days=3), end_date=today - datetime.timedelta(days=2), ) cycle1.put() team.put() classroom.put() ppt.put() # Without a current cycle, no cycle data response = self.testapp.get( '/api/codes/{}/participants/{}'.format(classroom.url_code, ppt.student_id), status=200, ) self.assertEqual( json.loads(response.body), { 'uid': ppt.uid, 'team_id': ppt.team_id }, ) # Add a new cycle that is current. cycle2 = Cycle.create( team_id=team.uid, ordinal=2, # schedule to not be current (starts and ends in the past) start_date=today - datetime.timedelta(days=1), end_date=today + datetime.timedelta(days=1), ) cycle2.put() # Cycle data present. response = self.testapp.get( '/api/codes/{}/participants/{}'.format(classroom.url_code, ppt.student_id), status=200, ) expected = { 'uid': ppt.uid, 'team_id': ppt.team_id, 'cycle': { 'uid': cycle2.uid, 'team_id': cycle2.team_id, 'ordinal': cycle2.ordinal, 'start_date': util.datelike_to_iso_string(cycle2.start_date), 'end_date': util.datelike_to_iso_string(cycle2.end_date), } } self.assertEqual(json.loads(response.body), expected)
def test_check_roster(self): # Other apps (neptune) should be able to check the existence of # participants by name, and it should work on stripped versions. other, teammate, contact, captain, team, classroom, ppnt = self.create( ) ppnt.student_id = u'ABC-123-def' ppnt.stripped_student_id = 'abc123def' ppnt.put() url_code = classroom.code.replace(' ', '-') # Unstripped name found. self.testapp.get( '/api/codes/{}/participants/{}'.format(url_code, ppnt.student_id), status=200, ) # Stripped name (expected neptune behavior) found. self.testapp.get( '/api/codes/{}/participants/{}'.format(url_code, ppnt.stripped_student_id), status=200, ) # Unknown name not found. self.testapp.get( '/api/codes/{}/participants/{}'.format(url_code, 'dne'), status=404, ) # Known name, unknown classroom code => not found. self.testapp.get( '/api/codes/{}/participants/{}'.format('bad-code', ppnt.stripped_student_id), status=404, ) # Known name and code, but student not on that classroom => not found. other_class = Classroom.create( name="Other Class", team_id=team.uid, contact_id='User_contact', code="bar", ) other_class.put() self.testapp.get( '/api/codes/{}/participants/{}'.format('bar', ppnt.stripped_student_id), status=404, ) # Known name, but not on any classrooms => not found. disassociated = Participant.create( team_id=team.uid, classroom_ids=[], student_id='disassociated', ) disassociated.put() self.testapp.get( '/api/codes/{}/participants/{}'.format( url_code, disassociated.stripped_student_id), status=404, )
def test_delete_removes_related(self): user = User.create(name='foo', email='*****@*****.**') team = Team.create(name='Team Foo', captain_id=user.uid, program_id=self.demo_program.uid) team.put() survey = Survey.create(team_id=team.uid) survey.put() user.owned_teams = [team.uid] user.put() classroom1 = Classroom.create( name='Classroom One', code='trout viper', team_id=team.uid, contact_id='User_contact', num_students=22, grade_level='9-12', ) classroom1.put() classroom2 = Classroom.create( name='Classroom Two', code='trout viper', team_id=team.uid, contact_id='User_contact', num_students=22, grade_level='9-12', ) classroom2.put() report1 = Report.create( team_id=team.uid, classroom_id=classroom1.uid, filename='report1.pdf', gcs_path='/upload/abc', size=10, content_type='application/pdf', ) report1.put() report2 = Report.create( team_id=team.uid, classroom_id=classroom2.uid, filename='report2.pdf', gcs_path='/upload/def', size=10, content_type='application/pdf', ) report2.put() url = '/api/teams/{}'.format(team.uid) headers = self.login_headers(user) # Delete the team. self.testapp.delete(url, headers=headers, status=204) # Expect the survey, classrooms, and related reports are gone from the # db. self.assertIsNone(Survey.get_by_id(survey.uid)) self.assertIsNone(Classroom.get_by_id(classroom1.uid)) self.assertIsNone(Classroom.get_by_id(classroom2.uid)) self.assertIsNone(Report.get_by_id(report1.uid)) self.assertIsNone(Report.get_by_id(report2.uid))