From 76a0f852abee96e27e8e7a74def131f186ab0b79 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Fri, 7 Feb 2025 00:20:22 -0800 Subject: [PATCH 1/3] try to fix the sorting on import courses --- server/services/canvas/__init__.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/server/services/canvas/__init__.py b/server/services/canvas/__init__.py index 3347850..d9601e3 100644 --- a/server/services/canvas/__init__.py +++ b/server/services/canvas/__init__.py @@ -7,7 +7,7 @@ from server.models import Offering from server.services.canvas.fake_canvas import FakeCanvas, FakeCourse, FakeUser from server.typings.exception import Redirect - +from datetime import datetime def is_mock_canvas() -> bool: return app.config['MOCK_CANVAS'] and \ @@ -91,12 +91,18 @@ def get_user_courses_categorized(user: FakeUser | User) \ student_courses: list[FakeCourse | Course] = list(student_courses) other: list[FakeCourse | Course] = list(other) + def _safe_to_date(date): + try: + return datetime.strptime(date, '%Y-%m-%dT%H:%M:%S%z') + except ValueError: + return None + # sorted by start_at_date DESC and then by name ASC def _sort_courses(courses: list[FakeCourse | Course]): # Cannot do courses.sort(key=lambda c: (c.start_at_date, c.name)) # String or Datetime object cannot be negated to reverse the order courses.sort(key=lambda c: c.name) - courses.sort(key=lambda c: c.start_at_date, reverse=True) + courses.sort(key=lambda c: _safe_to_date(c.start_at_date), reverse=True) _sort_courses(staff_courses) _sort_courses(student_courses) From ada3fac43a341a23209562c7ac433243e0590873 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Fri, 7 Feb 2025 00:49:12 -0800 Subject: [PATCH 2/3] safer function? --- server/services/canvas/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/services/canvas/__init__.py b/server/services/canvas/__init__.py index d9601e3..bbfb0fb 100644 --- a/server/services/canvas/__init__.py +++ b/server/services/canvas/__init__.py @@ -94,8 +94,8 @@ def get_user_courses_categorized(user: FakeUser | User) \ def _safe_to_date(date): try: return datetime.strptime(date, '%Y-%m-%dT%H:%M:%S%z') - except ValueError: - return None + except: + return date # sorted by start_at_date DESC and then by name ASC def _sort_courses(courses: list[FakeCourse | Course]): From 5254aafa157592e7fcb67b4c98a669e9969988a4 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Fri, 7 Feb 2025 00:56:54 -0800 Subject: [PATCH 3/3] Attempt to clean up email sending --- server/services/email/__init__.py | 2 +- server/services/email/smtp.py | 11 +++++++---- tests/unit/test_email.py | 6 +++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/server/services/email/__init__.py b/server/services/email/__init__.py index 55a0303..54d23cc 100644 --- a/server/services/email/__init__.py +++ b/server/services/email/__init__.py @@ -49,7 +49,7 @@ def email_about_assignment(exam, form, to_addrs): failure_addrs.add(to_addr) continue email_message = construct_email( - from_addr=form.from_addr.data, + reply_to=form.from_addr.data, to_addr=to_addr, subject=subject, body=body, diff --git a/server/services/email/smtp.py b/server/services/email/smtp.py index cf05026..aa23cf0 100644 --- a/server/services/email/smtp.py +++ b/server/services/email/smtp.py @@ -21,9 +21,12 @@ def __repr__(self) -> str: f'use_auth={self.use_auth})') -def construct_email(*, from_addr, to_addr, subject, body, body_html=None, bcc_addr=None, cc_addr=None): +# TODO: Due to email config, we hard code the FROM address +# What _users_ specify is the REPLY-TO address, but is labeled as FROM in the form. +def construct_email(*, reply_to, to_addr, subject, body, body_html=None, bcc_addr=None, cc_addr=None): msg = EmailMessage() - msg['From'], msg['To'], msg['Subject'] = from_addr, to_addr, subject + msg['From'] = 'seamless-learning@berkeley.edu' + msg['Reply-To'], msg['To'], msg['Subject'] = reply_to, to_addr, subject if bcc_addr: if isinstance(bcc_addr, str): bcc_addr = bcc_addr.split(',') @@ -110,9 +113,9 @@ def send_emails(*, smtp: SMTPConfig, messages=list[EmailMessage], return successful_emails, failed_emails -def send_single_email(*, smtp: SMTPConfig, from_addr, to_addr, subject, body, +def send_single_email(*, smtp: SMTPConfig, reply_to, to_addr, subject, body, body_html=None, bcc_addr=None, cc_addr=None): - msg = construct_email(from_addr=from_addr, to_addr=to_addr, subject=subject, body=body, + msg = construct_email(reply_to=reply_to, to_addr=to_addr, subject=subject, body=body, body_html=body_html, bcc_addr=bcc_addr, cc_addr=cc_addr) successful_emails, failed_emails = send_emails(smtp=smtp, messages=[msg]) if successful_emails: diff --git a/tests/unit/test_email.py b/tests/unit/test_email.py index 4a814f0..98736ee 100644 --- a/tests/unit/test_email.py +++ b/tests/unit/test_email.py @@ -34,7 +34,7 @@ def test_send_plain_text_email(mock_smtp): """ success = send_single_email(smtp=_email_config, - from_addr=TEST_FROM_EMAIL, + reply_to=TEST_FROM_EMAIL, to_addr=TEST_TO_EMAIL, subject=TEST_SUBJECT, body=TEST_BODY) @@ -86,7 +86,7 @@ def test_batch_send(mock_smtp): """ batch_size = 1000 email_messages = [ - construct_email(from_addr=TEST_FROM_EMAIL, + construct_email(reply_to=TEST_FROM_EMAIL, to_addr=TEST_TO_EMAIL, subject=TEST_SUBJECT, body=TEST_BODY) @@ -182,7 +182,7 @@ def test_batch_send_with_mock_smtp_server(smtp_server): batch_size = 1000 email_messages = [ - construct_email(from_addr=TEST_FROM_EMAIL, + construct_email(reply_to=TEST_FROM_EMAIL, to_addr=TEST_TO_EMAIL, subject=TEST_SUBJECT, body=TEST_BODY)