Ejemplo n.º 1
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.º 2
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.º 3
0
    def resolve_id_mismatch(klass, user, new_id):
        """Change all references to user's id to a new id.

        N.B. this is obviously brittle; when the relationship schema changes,
        this will also have to change.
        """
        # The auth server has a different id for this user; defer to it.

        teams = Team.get(captain_id=user.uid)
        for t in teams:
            t.captain_id = new_id
        Team.put_multi(teams)

        classrooms = Classroom.get(contact_id=user.uid)
        for c in classrooms:
            c.contact_id = new_id
        Classroom.put_multi(classrooms)

        params = {'uid': new_id, 'short_uid': SqlModel.convert_uid(new_id)}
        with mysql_connection.connect() as sql:
            sql.update_row(klass.table, 'uid', user.uid, **params)

        for k, v in params.items():
            setattr(user, k, v)

        return user
Ejemplo n.º 4
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.º 5
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.º 6
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.º 7
0
    def test_resolve_mismatch(self):
        team, classroom, captain, contact = self.create()

        old_captain_id = captain.uid
        old_contact_id = contact.uid
        new_captain_id = 'User_newcaptain'
        new_contact_id = 'User_newcontact'

        captain = User.resolve_id_mismatch(captain, new_captain_id)
        contact = User.resolve_id_mismatch(contact, new_contact_id)

        self.assertEqual(captain.uid, new_captain_id)
        self.assertEqual(contact.uid, new_contact_id)

        fetched_captain = User.get_by_id(new_captain_id)
        fetched_contact = User.get_by_id(new_contact_id)

        self.assertIsNotNone(fetched_captain)
        self.assertIsNotNone(fetched_contact)

        fetched_team = Team.get_by_id(team.uid)
        self.assertEqual(fetched_team.captain_id, new_captain_id)

        fetched_classroom = Classroom.get_by_id(classroom.uid)
        self.assertEqual(fetched_classroom.contact_id, new_contact_id)
Ejemplo n.º 8
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.º 9
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.º 10
0
    def get_team_reports(self, team_id):
        user = self.get_current_user()
        team = Team.get_by_id(team_id)

        if not team:
            return self.http_not_found()

        if not owns(user, team) and not has_captain_permission(user, team):
            return self.http_forbidden("Only team members can list reports.")

        # Limit access to preview reports, super admin only.
        show_preview_reports = True if user.super_admin else False
        # Returns both team- and class-level reports.
        all_reports = Report.get_for_team(team.uid, show_preview_reports)

        # Any team member can see the team reports...
        allowed_reports = [r for r in all_reports if not r.classroom_id]

        # ...but limit access to classroom reports.
        classroom_reports = [r for r in all_reports if r.classroom_id]
        classroom_ids = [r.classroom_id for r in classroom_reports]
        classrooms = {c.uid: c for c in Classroom.get_by_id(classroom_ids)}

        for report in classroom_reports:
            if has_contact_permission(user, classrooms[report.classroom_id]):
                allowed_reports.append(report)

        # Add a custom link for users to access each report.
        self.write([
            dict(r.to_client_dict(), link=self.report_link(r))
            for r in allowed_reports
        ])
Ejemplo n.º 11
0
    def get(self, program_id_or_label):
        user = self.get_current_user()
        if not user.super_admin:
            return self.http_forbidden()

        program = Program.get_by_id(program_id_or_label)
        if not program:
            program = Program.get_by_label(program_id_or_label)
        if not program:
            return self.http_not_found()

        search_str = self.get_param('q', unicode, None)

        if not search_str:
            return self.write([])

        if search_str.startswith('user:'******'t have team r
        orgs = Organization.query_by_name(search_str, program.uid)
        teams = Team.query_by_name(search_str, program.uid)
        classrooms = Classroom.query_by_name(search_str, program.uid)
        users = User.query_by_name_or_email(search_str)

        self.write({
            'organizations': [e.to_client_dict() for e in orgs],
            'teams': [e.to_client_dict() for e in teams],
            'classrooms': [e.to_client_dict() for e in classrooms],
            'users': [e.to_client_dict() for e in users],
        })
Ejemplo n.º 12
0
    def test_create(self):
        """Team owners can create classrooms with themselves as contact."""
        team = Team.create(name='Team Foo',
                           captain_id='User_cap',
                           program_id=self.program.uid)
        team.put()
        user = User.create(name='User Foo',
                           email='*****@*****.**',
                           owned_teams=[team.uid])
        user.put()
        response = self.testapp.post_json(
            '/api/classrooms',
            {
                'name': 'Classroom Foo',
                'team_id': team.uid,
                'code': 'a a',
                'contact_id': user.uid
            },
            headers=self.login_headers(user),
        )
        # Make sure the response is right.
        response_dict = json.loads(response.body)
        classroom = Classroom.get_by_id(response_dict['uid'])
        self.assertEqual(
            response.body,
            json.dumps(classroom.to_client_dict(),
                       default=util.json_dumps_default),
        )
        # Make sure the contact is set.
        self.assertEqual(classroom.contact_id, user.uid)

        # Clear the user's cookie so we can use the app as other people.
        self.testapp.reset()
        return user, classroom
Ejemplo n.º 13
0
    def set_up(self):
        # Let ConsistencyTestCase set up the datastore testing stub.
        super(TestApiParticipants, self).set_up()

        application = self.patch_webapp(webapp2.WSGIApplication)(
            api_routes,
            config={
                'webapp2_extras.sessions': {
                    'secret_key': self.cookie_key
                }
            },
            debug=True)
        self.testapp = webtest.TestApp(application)

        with mysql_connection.connect() as sql:
            sql.reset({
                'classroom': Classroom.get_table_definition(),
                'cycle': Cycle.get_table_definition(),
                'participant': Participant.get_table_definition(),
                'program': Program.get_table_definition(),
                'team': Team.get_table_definition(),
                'user': User.get_table_definition(),
            })

        self.program = Program.create(
            name="Engagement Project",
            label='ep18',
            min_cycles=3,
            active=True,
            preview_url='foo.com',
        )
        self.program.put()
Ejemplo n.º 14
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.º 15
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.º 16
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.º 17
0
    def set_up(self):
        # Let ConsistencyTestCase set up the datastore testing stub.
        super(TestApiSurveys, self).set_up()

        application = webapp2.WSGIApplication(api_routes,
                                              config={
                                                  'webapp2_extras.sessions': {
                                                      'secret_key':
                                                      self.cookie_key
                                                  }
                                              },
                                              debug=True)
        self.testapp = webtest.TestApp(application)

        with mysql_connection.connect() as sql:
            sql.reset({
                'classroom': Classroom.get_table_definition(),
                'metric': Metric.get_table_definition(),
                'program': Program.get_table_definition(),
                'survey': Survey.get_table_definition(),
                'team': Team.get_table_definition(),
                'user': User.get_table_definition(),
            })

        self.ep_program = Program.create(
            name="Engagement Project",
            label='ep18',
            active=True,
            preview_url='foo.com',
        )
        self.ep_program.put()
Ejemplo n.º 18
0
    def post(self, team_id, date_str=None):
        if date_str:
            today = datetime.strptime(date_str, config.iso_date_format).date()
        else:
            today = date.today()

        # Guaranteed to have start and end dates.
        cycle = Cycle.get_current_for_team(team_id, today)
        if not cycle:
            logging.info(
                "Either the team doesn't exist, or they don't have a cycle "
                "matching the current date. Doing nothing.")
            return

        team = Team.get_by_id(team_id)
        classrooms = Classroom.get(team_id=team_id)

        if len(classrooms) == 0:
            logging.info("No classrooms, setting participation to 0.")
            cycle.students_completed = 0
        else:
            ppn = get_participation(cycle, classrooms)
            num_complete = 0
            for code, counts in ppn.items():
                complete_count = next(
                    (c for c in counts if c['value'] == '100'), None)
                num_complete += complete_count['n'] if complete_count else 0
            cycle.students_completed = num_complete

        cycle.put()
Ejemplo n.º 19
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.º 20
0
    def set_up(self):
        # Let ConsistencyTestCase set up the datastore testing stub.
        super(TestClassrooms, self).set_up()

        with mysql_connection.connect() as sql:
            sql.reset({
                'user': User.get_table_definition(),
                'classroom': Classroom.get_table_definition(),
            })
Ejemplo n.º 21
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.º 22
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.º 23
0
def classroom_manager():
    classrooms = list(map(lambda c: Classroom(c[0], c[1]), sorted_classrooms))

    def get_minimum_essential_classroom(slot, capacity):
        nonlocal classrooms
        current_classrooms = list(map(lambda c: c.classroom.name, slot))
        for classroom in classrooms:
            if classroom.capacity >= capacity and classroom.name not in current_classrooms:
                return classroom
        return None

    return get_minimum_essential_classroom
Ejemplo n.º 24
0
    def get_membership(self, email, program_id):
        user = User.get_by_auth('email', email)
        orgs = Organization.query_by_user(user, program_id)
        teams = Team.query_by_user(user, program_id)
        classrooms = Classroom.query_by_contact(user, program_id)

        return {
            'organizations': [e.to_client_dict() for e in orgs],
            'teams': [e.to_client_dict() for e in teams],
            'classrooms': [e.to_client_dict() for e in classrooms],
            'users': [user.to_client_dict()],
        }
Ejemplo n.º 25
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.º 26
0
    def post(self, team_id, date_str=None):
        survey = Survey.get(team_id=team_id)[0]
        if date_str:
            today = datetime.strptime(date_str, config.iso_date_format).date()
        else:
            today = date.today()

        # Cycle ultimately comes from Cycle.get_current_for_team() and so is
        # guaranteed to have start and end dates.
        cycle = survey.should_notify(today)
        if not cycle:
            # This task is run every week, but only actually send notifications
            # if the date matches the survey interval.
            return

        team = Team.get_by_id(survey.team_id)
        program = Program.get_by_id(team.program_id)
        classrooms = Classroom.get(team_id=team_id)
        users = User.query_by_team(team_id)

        if len(classrooms) == 0:
            pct_complete_by_id = {}
        else:
            ppn = get_participation(cycle, classrooms)
            pct_complete_by_id = self.participation_to_pct(ppn, classrooms)

        # Get all the responses once to save trips to the db. Redact them later
        # according to the relevate user.
        unsafe_responses = Response.get_for_teams_unsafe([team_id],
                                                         parent_id=cycle.uid)

        to_put = []
        for user in users:
            if user.receive_email:
                safe_responses = Response.redact_private_responses(
                    unsafe_responses, user)
                email = cycle_emailers.create_cycle_email(
                    program.label,
                    user,  # recipient
                    users,
                    team,
                    classrooms,
                    safe_responses,
                    cycle,
                    pct_complete_by_id,
                )

                to_put.append(email)

        ndb.put_multi(to_put)
Ejemplo n.º 27
0
    def test_patch_with_disassociated_participant(self):
        """If a participant exists with no classrooms, they are found."""
        other, teammate, contact, captain, team, classroom, _ = self.create()

        student_id = 'disassociated'

        # Add an participant who is disassociated from all classrooms.
        ppt = Participant.create(
            team_id=team.uid,
            classroom_ids=[],
            student_id=student_id,
        )
        ppt.put()

        def postBody(ppt, id_modifier=''):
            ppt = ppt.copy()
            ppt['student_id'] += id_modifier
            return {'method': 'POST', 'path': '/api/participants', 'body': ppt}

        response = self.testapp.patch_json(
            '/api/participants',
            [{
                'method': 'POST',
                'path': '/api/participants',
                'body': {
                    'team_id': team.uid,
                    'classroom_id': classroom.uid,
                    'student_id': student_id,
                },
            }],
            headers=jwt_headers(contact),
        )
        response_list = json.loads(response.body)

        # The provided student id matched the disassociated user and the
        # db used that uid.
        self.assertEqual(len(response_list), 1)
        self.assertEqual(response_list[0]['uid'], ppt.uid)
        self.assertEqual(
            Participant.get_by_id(ppt.uid).classroom_ids,
            [classroom.uid],
        )

        # `num_students` has incremented after adding new participant to
        # classroom.
        updated_classroom = Classroom.get_by_id(classroom.uid)
        self.assertEqual(
            updated_classroom.num_students,
            classroom.num_students + 1,
        )
Ejemplo n.º 28
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.º 29
0
    def set_up(self):
        # Let ConsistencyTestCase set up the datastore testing stub.
        super(TestTasks, self).set_up()

        with mysql_connection.connect() as sql:
            sql.reset({
                'classroom': Classroom.get_table_definition(),
                'cycle': Cycle.get_table_definition(),
                'metric': Metric.get_table_definition(),
                'program': Program.get_table_definition(),
                'response': Response.get_table_definition(),
                'survey': Survey.get_table_definition(),
                'team': Team.get_table_definition(),
                'user': User.get_table_definition(),
            })
Ejemplo n.º 30
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)