diff --git a/app/email_content.py b/app/email_content.py index d018eef..100b629 100644 --- a/app/email_content.py +++ b/app/email_content.py @@ -103,7 +103,7 @@ def render_change_block(change: SimplifiedNotification, user_name: str) -> tuple def render_email(task: EmailTask, sub: SubEmailData, ids_to_contact: dict[int, UserContact]) -> tuple[str, str]: sub_text, sub_html = render_submission_block(sub) change_texts, change_htmls = [], [] - for change in sorted(task.notifications.changes, key=lambda c: c.time, reverse=True): + for change in sorted(task.notifications.changes, key=lambda c: c.time): contact = ids_to_contact.get(change.user_id) name = contact.display_name if contact else f"user {change.user_id}" ct, ch = render_change_block(change, name) diff --git a/app/templates/email_body.py b/app/templates/email_body.py index 44a548d..a863369 100644 --- a/app/templates/email_body.py +++ b/app/templates/email_body.py @@ -6,7 +6,7 @@ MOD_HUB_TITLE = "Moderator Hub" _FOOTER_LINE1 = "This email was generated by the moderator email system version 2.0" -_FOOTER_LINE2 = "Some of your arXiv moderation emails may look different. We are in the process of transitioning email systems." +_FOOTER_LINE2 = "Some of your arXiv moderation emails may look different. Throughout 2026, we will be transitioning email systems." def render_body( diff --git a/app/templates/submission.py b/app/templates/submission.py index 12b5a85..dabdf01 100644 --- a/app/templates/submission.py +++ b/app/templates/submission.py @@ -8,6 +8,14 @@ CHECK_SUBMISSION_URL = "https://check.arxiv.org/submit/{submission_id}" _ET = ZoneInfo(arxiv_settings.ARXIV_BUSINESS_TZ) +MAX_AUTHORS = 15 + + +def truncate_authors(authors_str: str) -> str: + parts = [a.strip() for a in authors_str.split(",")] + if len(parts) > MAX_AUTHORS: + return ", ".join(parts[:MAX_AUTHORS]) + ", ..." + return ", ".join(parts) def render_submission_block(sub: SubEmailData) -> tuple[str, str]: @@ -15,7 +23,7 @@ def render_submission_block(sub: SubEmailData) -> tuple[str, str]: cat_list = sub.submission_categories or "(none)" check_url = CHECK_SUBMISSION_URL.format(submission_id=sub.submission_id) title = sub.title or "(no title)" - authors = sub.authors or "(no authors)" + authors = truncate_authors(sub.authors) if sub.authors else "(no authors)" submit_time_str = ( sub.submit_time.astimezone(_ET).strftime("%Y-%m-%d %H:%M %Z") diff --git a/cicd/cloudbuild.yaml b/cicd/cloudbuild.yaml index cddc7a2..01ac957 100644 --- a/cicd/cloudbuild.yaml +++ b/cicd/cloudbuild.yaml @@ -1,3 +1,6 @@ +# this can be used to update the cloud run job +# for the initial creation use the same template but switch update command with create + options: logging: CLOUD_LOGGING_ONLY diff --git a/tests/test_email_content.py b/tests/test_email_content.py index 893cd61..530c5ce 100644 --- a/tests/test_email_content.py +++ b/tests/test_email_content.py @@ -5,12 +5,13 @@ from app.schema import SimplifiedNotification, CommentData, PromoteData, NewPropData, PropRespData from app.schema import SubEmailData -from app.email_content import get_submission_info, _build_category_string, render_change_block +from app.email_content import get_submission_info, _build_category_string, render_change_block, render_email +from app.schema import EmailTask, ConsolidatedNotifications from app.templates.comment import render_comment_block from app.templates.promote import render_promote_block from app.templates.new_prop import render_new_prop_block from app.templates.prop_resp import render_prop_resp_block -from app.templates.submission import render_submission_block +from app.templates.submission import render_submission_block, truncate_authors, MAX_AUTHORS from app.templates.email_body import render_body, CHECK_GUIDE_URL, HOW_TO_MOD_URL, MOD_HUB_URL _TIME = datetime(2024, 6, 15, 14, 30, tzinfo=timezone.utc) @@ -110,6 +111,21 @@ def _mock_submission(submission_id=123, title="ML Paper", authors="Alice, Bob", submit_time=submit_time, ) +def test_truncate_authors_under_limit(): + authors = ", ".join(f"Author {i}" for i in range(MAX_AUTHORS - 1)) + assert truncate_authors(authors) == authors + +def test_truncate_authors_at_limit(): + authors = ", ".join(f"Author {i}" for i in range(MAX_AUTHORS)) + assert truncate_authors(authors) == authors + assert "..." not in truncate_authors(authors) + +def test_truncate_authors_over_limit(): + parts = [f"Author {i}" for i in range(MAX_AUTHORS + 5)] + result = truncate_authors(", ".join(parts)) + assert result.endswith(", ...") + assert result.count(",") == MAX_AUTHORS # 14 between names + 1 before ellipsis + def test_render_submission_block(): sub = _mock_submission() text, html_out = render_submission_block(sub) @@ -161,6 +177,17 @@ def test_render_email_contains_all_sections_and_footer(): assert url in body_html, f"missing {url} in html" +def test_render_email_changes_oldest_first(): + t_old = datetime(2024, 6, 15, 14, 30, tzinfo=timezone.utc) + t_new = datetime(2024, 6, 15, 14, 32, tzinfo=timezone.utc) + older = SimplifiedNotification(time=t_old, user_id=1, data=CommentData(comment="older comment")) + newer = SimplifiedNotification(time=t_new, user_id=1, data=CommentData(comment="newer comment")) + notifications = ConsolidatedNotifications(submission_id=123, changes=[newer, older]) + task = EmailTask(submission_id=123, to_emails=[], notifications=notifications) + text, _ = render_email(task, _mock_submission(), {}) + assert text.index("older comment") < text.index("newer comment") + + # ── exact output tests ──────────────────────────────────────────────────────── #will need to be updated whenever format changes #feel free to delete if too annoying, but its kind of nice to see the whole output @@ -321,7 +348,7 @@ def test_full_email_exact_text(): f"Moderator Hub: {_HUB_URL} \n" "\n" "This email was generated by the moderator email system version 2.0\n" - "Some of your arXiv moderation emails may look different. We are in the process of transitioning email systems.\n" + "Some of your arXiv moderation emails may look different. Throughout 2026, we will be transitioning email systems.\n" ) @@ -352,7 +379,7 @@ def test_full_email_exact_html(): f"How to moderate | " f"Moderator Hub
\n" "This email was generated by the moderator email system version 2.0
\n"
- "Some of your arXiv moderation emails may look different. We are in the process of transitioning email systems.