Ejemplo n.º 1
0
    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',
            },
        )
Ejemplo n.º 2
0
    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},
        )
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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,
            )
Ejemplo n.º 8
0
    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,
        )
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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,
        )
Ejemplo n.º 11
0
    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})
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
    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)
Ejemplo n.º 14
0
    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',
            },
        )
Ejemplo n.º 15
0
    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)
Ejemplo n.º 16
0
    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'], '')
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
0
    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)
Ejemplo n.º 19
0
    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)
Ejemplo n.º 20
0
    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,
        )
Ejemplo n.º 21
0
    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])
Ejemplo n.º 22
0
    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)
Ejemplo n.º 23
0
    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)
Ejemplo n.º 24
0
    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']),
        )
Ejemplo n.º 25
0
    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'
            ],
        )
Ejemplo n.º 26
0
    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)
Ejemplo n.º 27
0
    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},
        )
Ejemplo n.º 28
0
    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)
Ejemplo n.º 29
0
    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,
        )
Ejemplo n.º 30
0
    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))