diff --git a/dailyClassReminder.py b/dailyClassReminder.py index 096df4a..0f085a4 100644 --- a/dailyClassReminder.py +++ b/dailyClassReminder.py @@ -17,6 +17,7 @@ import json import datetime import logging +from collections import defaultdict from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText @@ -78,27 +79,28 @@ def get_teacher_contact_info(): def main(): TEACHER_EMAILS = get_teacher_contact_info() RESPONSE_EVENTS = get_response_events(SEARCH_FIELDS, OUTPUT_FIELDS) + CLASSES = defaultdict(list) + for item in RESPONSE_EVENTS["searchResults"]: + teacher = item["Event Topic"] or "Unassigned" + CLASSES[teacher].append(item) - # Remove duplicates in the list of teachers - TEACHERS = {item.get("Event Topic") for item in RESPONSE_EVENTS["searchResults"]} - - for teacher in TEACHERS: + for teacher, events in CLASSES.items(): try: - if not teacher: - logging.info("WARNING: No teacher assigned!") + # Handle events with no teacher assigned + if not teacher or teacher == "Unassigned": + teacher_display = "Unassigned Teacher" + class_names = ', '.join([event['Event Name'] for event in events]) + logging.info("WARNING: No teacher assigned for classes: %s", class_names) TEACHER_EMAILS[teacher] = "classes@asmbly.org" + else: + teacher_display = teacher + if teacher in ALREADY_SENT: - logging.info("Already emailed %s", teacher) + logging.info("Already emailed %s", teacher_display) continue # Find all events for each teacher - events = list( - filter( - lambda x, teach=teacher: x["Event Topic"] == teach, - RESPONSE_EVENTS["searchResults"], - ) - ) - logging.info("\n\n_____\n\nEmailing %s about %s event(s)...", teacher, len(events)) + logging.info("\n\n_____\n\nEmailing %s about %s event(s)...", teacher_display, len(events)) sorted_events = sorted( events, key=lambda x: datetime.datetime.fromisoformat(x["Event Start Date"]) ) diff --git a/tests/test_dailyClassReminders.py b/tests/test_dailyClassReminders.py index 188f13a..24f9f6a 100644 --- a/tests/test_dailyClassReminders.py +++ b/tests/test_dailyClassReminders.py @@ -156,6 +156,7 @@ def test_email_includes_registrant_details( # Verify event search API was called assert search_mock.called + assert self.mock_smtp.send_message.call_count == 1 email_message = self.mock_smtp.send_message.call_args[0][0] email_body = email_message.as_string() @@ -187,3 +188,27 @@ def test_canceled_registrants_not_included( assert f"{good_student.firstName} {good_student.lastName}" in email_body assert f"{canceled_student.firstName} {canceled_student.lastName}" not in email_body + + def test_none_teacher_sends_to_classes_email( + self, requests_mock, mock_teachers_file + ): + """Test that events with None as teacher are handled properly""" + student = NeonUserMock() + event = NeonEventMock(event_name="Orphaned Class", teacher=None).add_registrant(student) + + search_mock, _ = NeonEventMock.mock_events(requests_mock, [event]) + + import dailyClassReminder + dailyClassReminder.main() + + # Verify event search API was called + assert search_mock.called + + # Should still send email + assert self.mock_smtp.send_message.call_count == 1 + + # Email should go to classes@asmbly.org + email_message = self.mock_smtp.send_message.call_args[0][0] + assert email_message["To"] == "classes@asmbly.org" + +