def test_show_lunchmates_of_external_lunch(reset_mock): # Current decision: show private students in another lunch # Can be blocked in frontend viewer = Student('hpeng2021', 'Michael Peng') viewer.schedules = {1: {'C': 'Smith', 'F': 'Shea'}} smith = Class('Smith', 'C', 1, lunch=2) shea = Class('Shea', 'F', 1, lunch=None) class_repo.load.side_effect = switch({ ('Smith', 'C', 1): smith, ('Shea', 'F', 1): shea }) class_repo.names_of_teachers_in_lunch.side_effect = switch({ (1, 'C', 2): ['Messina', 'Smith', 'Caveney'], (1, 'C', 4): ['Emery', 'Gonzalez', 'Parsons'] }) lunchmates = [ Student('divanovich2021', 'Daniel', is_public=False), Student('azenith2021', 'Ayush', is_public=True) ] student_repo.students_in_class.side_effect = switch({ (1, 'C', 'Emery'): [lunchmates[1]], (1, 'C', 'Parsons'): [lunchmates[0]], (1, 'C', 'Gonzalez'): [] }) output = case.show_lunchmates(viewer, 1, 'C', 4) assert set(output) == set(lunchmates)
def test_show_lunch_number(reset_mock): viewer = Student('hpeng2021', 'Michael Peng') viewer.schedules = { 1: { 'C': 'Ream', 'D': 'DiBenedetto', 'E': 'Emery' }, 2: { 'C': 'Ream', 'D': 'DiBenedetto', 'E': 'Messina' } } emery = Class('Emery', 'E', 1, lunch=2) messina = Class('Messina', 'E', 2, lunch=None) class_repo.load.side_effect = switch({ ('Emery', 'E', 1): emery, ('Messina', 'E', 2): messina }) e1_out = case.show_lunch_number(viewer, 1, 'E') e2_out = case.show_lunch_number(viewer, 2, 'E') assert e1_out == 2 assert e2_out is None
def test_own_schedule_exists(): student = Student('hpeng2021', 'Michael') student.schedules = {1: {'D': 'Yes'}} output = case.own_schedule(student, 1) assert output == {'D': 'Yes'}
def test_read_schedule_of_private_without_reader_schedule(): reader = Student('hpeng2021', 'Michael') student = Student('divanovich2021', 'Daniel') student.schedules = {2: {'D': 'Givens'}} assert case.show_schedule(reader, student, 2) == {}
def test_semester_schedule_with_schedule(): student = Student('hpeng2021', 'Michael') student.schedules = {1: {'A': 'glee', 'B': '', 'C': 'see', 'D': 'dee'}} output = student.semester_schedule(1) assert output == student.schedules[1] assert student.semester_schedule(2) is None
def test_read_no_schedule_student(): reader = Student('a', 'A') student = Student('b', 'B') student.is_public = True student.schedules = None with pytest.raises(MissingScheduleError, match='B'): case.show_schedule(reader, student, 1)
def test_read_schedule_of_public(): reader = Student('hpeng2021', 'Michael') student = Student('divanovich2021', 'Daniel') student.is_public = True student.schedules = {1: {'G': 'Ream'}} result = case.show_schedule(reader, student, 1) assert result == {'G': 'Ream'}
def test_pass_query_to_repo(): student_repo.search.return_value = [ Student('qry', 'Que Ry'), Student('mquery', 'Myq Uery') ] results = case.perform_search('my query') student_repo.search.assert_called_once_with('my query') assert list(results) == student_repo.search.return_value
def show_schedule(viewer: Student, target: Student, semester: Semester) -> SemesterSchedule: """ Missing blocks means 'Private'; MissingScheduleError means not available """ schedule = target.semester_schedule(semester) if schedule is None: raise MissingScheduleError(target) if target.is_public: return schedule viewer_schedule = viewer.semester_schedule(semester) if viewer_schedule is None: return {} return dict(set(schedule.items()) & set(viewer_schedule.items()))
def do_login(): if request.method == 'GET': if logged_handle() is not None: flash('You are already logged in') return redirect(request.args.get('redirect', DEFAULT_HOME)) return render_template('login.html', redirect=request.args.get('redirect', '')) # expected form argument: id_token, redirect (optional) if missing_form_field('id_token'): return error(422, 'Missing token from Google sign-in') try: (handle, name) = adapt.google.verify(request.form['id_token']) session_log_in(handle) have_user = adapt.student_repo.exists(handle) flash('Successfully logged in as ' + name) default = DEFAULT_HOME if not have_user: session['name'] = name default = '/update' new = Student(handle, name) adapt.student_repo.save(new) # Fact: if user is logged in, then the user must have a database entry if missing_form_field('redirect'): return redirect(default) return redirect(request.form.get('redirect', default)) except ValueError as e: return error(403, 'Authentication failed: ' + str(e))
def test_load_student_without_discord(reset_mock): db_entry = { 'name': 'Michael Peng', 'semesters': { '1': { 'A': 'Holm-Andersen', 'B': 'Gonzalez', 'C': 'Ream', 'D': 'Givens' }, '2': { 'E': 'Messina', 'F': 'Parsons', 'G': 'Reidy' } }, 'is_public': True, 'cohort': 'blue' } mock_db.collection('students').document( 'hpeng2021').get().to_dict.return_value = db_entry mock_db.collection('students').document('hpeng2021').get().id = 'hpeng2021' student = student_repo.load('hpeng2021') assert student == Student(handle='hpeng2021', name='Michael Peng', schedules={ 1: db_entry['semesters']['1'], 2: db_entry['semesters']['2'] }, is_public=True, discord_id=None, cohort=Cohort.blue)
def test_set_student_without_discord(reset_mock): student = Student('hpeng2021', 'Michael Peng', schedules={ 1: { 'C': 'Messina' }, 2: { 'F': 'Parsons' } }, cohort=Cohort.blue) student_repo.save(student) mock_db.collection('students').document( 'hpeng2021').set.assert_called_once_with({ 'name': 'Michael Peng', 'semesters': { '1': { 'C': 'Messina' }, '2': { 'F': 'Parsons' } }, 'is_public': student.is_public, 'cohort': 'blue' })
def _generate_day_events(student: Student, day: datetime.date) -> List[Event]: output = [] time = arrow.get(datetime.datetime.combine(day, START_TIME, TIMEZONE)) for block in BLOCK_SEQ[time.weekday()]: output.append(IcsCalendarCase._generate_event( block, teacher=student.semester_schedule(2)[block], begin=time)) time += BLOCK_LEN + BLOCK_SPACING return output
def test_add_existing_user(reset_mock): mock_db.collection('students').document('hpeng2021').get().exists = True mock_db.document('counters/user').get().get.side_effect = require( ('value', ), 412) student_repo.save(Student('hpeng2021', 'Michael')) mock_db.document.assert_called_with('counters/user')
def test_read_schedule_of_private(): reader = Student('hpeng2021', 'Michael') reader.schedules = { 1: { 'A': 'Holm-Andersen', 'D': 'Givens', 'E': 'Messina', 'F': 'Parsons', 'G': 'Hibino, Krista' } } student = Student('divanovich2021', 'Daniel') student.schedules = { 1: { 'A': 'Holm-Andersen', 'D': 'Givens', 'E': 'Reusch', 'F': 'Scarfo', 'G': 'Ream' } } student.is_public = False result = case.show_schedule(reader, student, 1) assert result == {'A': 'Holm-Andersen', 'D': 'Givens'}
def show_classmates(self, viewer: Student, semester: Semester, block: Block) -> Iterable[Student]: schedule = viewer.semester_schedule(semester) if schedule is None: raise MissingScheduleError(viewer) roster = self.student_repo.students_in_class(semester, block, schedule[block]) return roster
def test_add_new_user(reset_mock): mock_db.collection('students').document('hpeng2021').get().exists = False mock_db.document('counters/user').get().get.side_effect = require( ('value', ), 412) student_repo.save(Student('hpeng2021', 'Michael')) mock_db.document.assert_called_with('counters/user') mock_db.document('counters/user').update.assert_called_once_with( {'value': 413})
def integrate_discord(self, student: Student, code: str, state: str) -> DiscordUser: if student.schedules is None: raise MissingScheduleError(student) user = self.discord_verifier.verify(code, state) student.discord_id = user.id self.student_repo.save(student) return user
def test_students_in_class(reset_mock): classmates = [Student('a', 'A'), Student('b', 'B'), Student('c', 'C')] def mock_student_doc_snapshot(student): snapshot = Mock(id=student.handle) snapshot.to_dict.return_value = { 'name': student.name, 'semesters': None, 'is_public': False, 'discord_id': None, 'cohort': None } return snapshot mock_db.collection('students').where('semesters.1.D', '==', 'Caveney')\ .stream.return_value = map(mock_student_doc_snapshot, classmates) results = student_repo.students_in_class(1, 'D', 'Caveney') assert set(results) == set(classmates)
def show_lunch_number(self, target: Student, semester: Semester, block: Block) -> Optional[LunchNumber]: """ None: teacher does not have this lunch recorded MissingScheduleError: viewer has no schedule """ schedule = target.semester_schedule(semester) if schedule is None: raise MissingScheduleError(target) klass = self.class_repo.load(schedule[block], block, semester) if klass is None: return None return klass.lunch
def match_score(a: Student, b: Student): name_score = ((name_hash(a.name) + name_hash(b.name)) % 117) / 117 shared_classes = 0 for semester in [1, 2]: schedule_a = a.semester_schedule(semester) schedule_b = b.semester_schedule(semester) if schedule_a is None or schedule_b is None: break for block in BLOCKS: if schedule_a[block] == schedule_b[block]: shared_classes += 1 # max theoretical shared classes: BLOCKS*2 # use a sqrt curve classes_score = -4 / (0.8 * shared_classes * shared_classes + 4) + 1 # same grade? grade_score = (3 - abs(a.graduating_year() - b.graduating_year())) / 3 print(f"match score query between {a.handle} and {b.handle}: name_score={name_score:.3f} classes_score={classes_score:.3f} grade_score={grade_score:.3f}") return name_score * 0.4 + classes_score * 0.4 + grade_score * 0.2
def update_lunches(self, student: Student, update: Dict[Semester, SemesterLunches]): batch_update: List[Class] = [] for (semester, lunches) in update.items(): schedule = student.semester_schedule(semester) if schedule is None: raise MissingScheduleError(student) for (block, number) in lunches.items(): batch_update.append( Class(schedule[block], block, semester, lunch=number)) self.class_repo.update_batch(batch_update)
def _read_doc(entry: firestore.DocumentSnapshot) -> Optional[Student]: data = entry.to_dict() if data is None: return None return Student( handle=entry.id, name=data['name'], schedules=None if data.get('semesters') is None else key_transform(data['semesters'], int), is_public=data['is_public'], discord_id=data.get('discord_id'), cohort=Cohort[data.get('cohort')] if data.get('cohort') is not None else None )
def show_lunchmates(self, viewer: Student, semester: Semester, block: Block, number: LunchNumber) -> Iterable[Student]: schedule = viewer.semester_schedule(semester) if schedule is None: raise MissingScheduleError(viewer) # TODO restrict teachers = self.class_repo.names_of_teachers_in_lunch( semester, block, number) for teacher in teachers: yield from self.student_repo.students_in_class( semester, block, teacher)
def test_show_classmates(reset_mock): classmates = [Student('a', 'A'), Student('b', 'B'), Student('c', 'C')] student_repo.students_in_class.return_value = classmates student = Student('hpeng2021', 'Michael') student.schedules = {1: {'D': 'Givens'}} output = case.show_classmates(student, 1, 'D') assert output == classmates student_repo.students_in_class.assert_called_once_with(1, 'D', 'Givens')
def test_set_student_with_discord(reset_mock): student = Student('hpeng2021', 'Michael Peng', schedules=None, discord_id='1040293723984713431') student_repo.save(student) mock_db.collection('students').document( 'hpeng2021').set.assert_called_once_with({ 'name': 'Michael Peng', 'semesters': None, 'is_public': student.is_public, 'discord_id': student.discord_id, 'cohort': None })
def test_load_student_with_discord_without_schedule(reset_mock): db_entry = { 'name': 'Michael Peng', 'semesters': None, 'accepts_terms': True, 'accepts_privacy': True, 'is_public': True, 'discord_id': '100923842098207349', 'cohort': 'remote' } mock_db.collection('students').document( 'hpeng2021').get().to_dict.return_value = db_entry student = student_repo.load('hpeng2021') assert student == Student(handle='hpeng2021', name='Michael Peng', schedules=None, is_public=True, discord_id=db_entry['discord_id'], cohort=Cohort.remote)
def test_show_lunchmates_of_own_lunch(reset_mock): viewer = Student('hpeng2021', 'Michael Peng') viewer.schedules = {1: {'D': 'Smith'}} lunchmates = [ Student('pcess', 'Pro Cess'), Student('azenith', 'Ayush Zenith'), Student('jmann', 'Jordan Mann') ] klass = Class('Smith', 'D', 1, lunch=3) class_repo.load.side_effect = require(('Smith', 'D', 1), klass) class_repo.names_of_teachers_in_lunch.side_effect = require((1, 'D', 3), ['Smith']) student_repo.students_in_class.side_effect = require((1, 'D', 'Smith'), lunchmates) output = case.show_lunchmates(viewer, 1, 'D', 3) assert list(output) == list(lunchmates)
from entities.student import Student from entities.types import SemesterSchedule from use_cases.calendar import IcsCalendarCase student_schedule: SemesterSchedule = { 'A': 'Aubrey', 'B': 'Bach', 'C': 'Conrad', 'D': 'Donovan', 'E': 'Emery', 'F': 'Frisk', 'G': 'Gonzalez' } student: Student = Student('hpeng2021', 'Michael Peng', schedules={2: student_schedule}) case = IcsCalendarCase() ahs_timezone = 'America/New_York' expected_events = { Event(name='A Block with Aubrey', begin=Arrow(2020, 4, 6, 8, 30, tzinfo=ahs_timezone), end=Arrow(2020, 4, 6, 9, 15, tzinfo=ahs_timezone), categories=['AHS at home', 'AHS at home: A Block'], alarms=[AudioAlarm(-datetime.timedelta(minutes=5))]), Event(name='C Block with Conrad', begin=Arrow(2020, 4, 6, 9, 30, tzinfo=ahs_timezone), end=Arrow(2020, 4, 6, 10, 15, tzinfo=ahs_timezone), categories=['AHS at home', 'AHS at home: C Block'], alarms=[AudioAlarm(-datetime.timedelta(minutes=5))]),
'is_public': False, 'discord_id': None, 'cohort': None } return snapshot mock_db.collection('students').where('semesters.1.D', '==', 'Caveney')\ .stream.return_value = map(mock_student_doc_snapshot, classmates) results = student_repo.students_in_class(1, 'D', 'Caveney') assert set(results) == set(classmates) search_students = [ Student('tbowlin', 'Tamekia Bowlin'), Student('blanterman', 'Brock Lanterman'), Student('hmateo', 'Hedwig Mateo'), Student('skrzeminski', 'Sadye Krzeminski'), Student('choltz', 'Clayton Holtz'), Student('mmchaney', 'Maryam Mchaney'), Student('lcuen', 'Liane Cuen'), Student('calbrecht', 'Cristobal Albrecht'), Student('dhohman', 'Dianna Hohman'), Student('ksecrist', 'Katelynn Secrist') ] def populate_search_students(): ret_val = [] for student in search_students: