From 7baf206911c487aa499975d2e9f10b0fea6ba748 Mon Sep 17 00:00:00 2001 From: kyokukou Date: Tue, 21 Jul 2026 09:39:01 -0700 Subject: [PATCH] also check for alias and alias archvie mods --- app/moderators.py | 42 +++++++++++++++++++++++++++++++++++----- tests/data.sql | 9 +++++++++ tests/test_moderators.py | 24 +++++++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/app/moderators.py b/app/moderators.py index 69b54e8..8066317 100644 --- a/app/moderators.py +++ b/app/moderators.py @@ -4,6 +4,7 @@ from sqlalchemy import select from arxiv.taxonomy.category import Category +from arxiv.taxonomy.definitions import CATEGORY_ALIASES, CATEGORIES_ACTIVE from arxiv.db import Session from arxiv.db.models import t_arXiv_moderators, TapirUser, TapirNickname @@ -76,22 +77,53 @@ def get_all_moderators() -> tuple [dict[str, ToEmail], dict[str, ToEmail]]: return all_archives, all_cats +_ALIAS_BY_CANONICAL = {v: k for k, v in CATEGORY_ALIASES.items()} + def who_to_email(category: Category, all_archives: dict[str, ToEmail], all_cats: dict[str, ToEmail])-> tuple[set[int], set[int]]: """determines who to include in an email for a given set of categories""" email: set[int] = set() reply_to: set[int] = set() + rolling_dont_email: set[int] = set() + rolling_dont_reply: set[int] = set() cat_entry = all_cats.get(category.id, ToEmail()) archive_entry = all_archives.get(category.in_archive, ToEmail()) - #add specific category moderators + #dont forget alaises + alias_id = _ALIAS_BY_CANONICAL.get(category.id) + if alias_id: + alias=CATEGORIES_ACTIVE[alias_id] + alias_cat_entry = all_cats.get(alias_id, ToEmail()) + alias_archive_entry = all_archives.get(alias.in_archive, ToEmail()) + + # factory in email preferences + #priority: named category > alias category > named archive > alias archive + #each lower-priority group excludes anyone who opted out at a higher-priority level + + #named category moderators email.update(cat_entry.send_to) reply_to.update(cat_entry.include_reply_to) - - #add archive mods unless they have specifically declined - email.update(archive_entry.send_to - cat_entry.dont_send_to) - reply_to.update(archive_entry.include_reply_to - cat_entry.dont_include_reply_to) + rolling_dont_email.update(cat_entry.dont_send_to) + rolling_dont_reply.update(cat_entry.dont_include_reply_to) + + #alias category moderators + if alias_id: + email.update(alias_cat_entry.send_to - rolling_dont_email) + reply_to.update(alias_cat_entry.include_reply_to - rolling_dont_reply) + rolling_dont_email.update(alias_cat_entry.dont_send_to) + rolling_dont_reply.update(alias_cat_entry.dont_include_reply_to) + + #named archive moderators + email.update(archive_entry.send_to - rolling_dont_email) + reply_to.update(archive_entry.include_reply_to - rolling_dont_reply) + rolling_dont_email.update(archive_entry.dont_send_to) + rolling_dont_reply.update(archive_entry.dont_include_reply_to) + + #alias archive moderators + if alias_id: + email.update(alias_archive_entry.send_to - rolling_dont_email) + reply_to.update(alias_archive_entry.include_reply_to - rolling_dont_reply) return email, reply_to diff --git a/tests/data.sql b/tests/data.sql index b268701..08b07be 100644 --- a/tests/data.sql +++ b/tests/data.sql @@ -44,6 +44,15 @@ INSERT INTO `tapir_users` VALUES (77777,'Archive','OptOut','',1,1,'archive-optou INSERT INTO `arXiv_moderators` VALUES (77777, 'astro-ph', '', 0, 0, 0, 0, 0); INSERT INTO `arXiv_moderators` VALUES (77777, 'astro-ph', 'HE', 0, 1, 0, 1, 0); +-- category alias tests: q-fin.EC is the alias of canonical category econ.GN +INSERT INTO `tapir_users` VALUES (60001,'Alias','CatMod','',1,1,'aliascat@example.com',8,0,2,1384185389,'dedicated','',0,0,0,1,1,0,0,0,0,'',0,0); +INSERT INTO `arXiv_moderators` VALUES (60001, 'q-fin', 'EC', 0, 0, 0, 0, 0); + +-- 60002 opts out of named category econ.GN and would otherwise qualify via the alias archive (q-fin) +INSERT INTO `tapir_users` VALUES (60002,'Cascade','OptOut','',1,1,'cascadeoptout@example.com',8,0,2,1384185389,'dedicated','',0,0,0,1,1,0,0,0,0,'',0,0); +INSERT INTO `arXiv_moderators` VALUES (60002, 'econ', 'GN', 0, 1, 0, 0, 0); +INSERT INTO `arXiv_moderators` VALUES (60002, 'q-fin', '', 0, 0, 0, 0, 0); + -- actor users referenced in test messages (user_id=1 and user_id=2) INSERT INTO `tapir_users` VALUES (1,'Test','Editor','',1,1,'editor-one@example.com',8,0,2,1384185389,'','',0,0,0,1,1,0,0,0,0,'',0,0); INSERT INTO `tapir_users` VALUES (2,'Jane','Smith','',1,1,'editor-two@example.com',8,0,2,1384185389,'','',0,0,0,1,1,0,0,0,0,'',0,0); diff --git a/tests/test_moderators.py b/tests/test_moderators.py index 8d42d79..d386f91 100644 --- a/tests/test_moderators.py +++ b/tests/test_moderators.py @@ -117,6 +117,30 @@ def test_who_to_email_category_optout_overrides_archive(): email, _ = who_to_email(CATEGORIES_ACTIVE['astro-ph.HE'], archives, cats) assert 77777 not in email +@pytest.mark.usefixtures("db_session") +def test_who_to_email_alias_category_mod(): + # 60001 mods q-fin.EC only, the alias of canonical econ.GN + archives, cats = get_all_moderators() + email, _ = who_to_email(CATEGORIES_ACTIVE['econ.GN'], archives, cats) + assert 60001 in email + +@pytest.mark.usefixtures("db_session") +def test_who_to_email_alias_archive_mod(): + # 246232 mods 'q-fin' archive-wide only -- not listed under econ, econ.GN, or q-fin.EC -- + # but 'q-fin' is the alias archive of econ.GN's alias category (q-fin.EC), so should still get emailed + archives, cats = get_all_moderators() + email, reply_to = who_to_email(CATEGORIES_ACTIVE['econ.GN'], archives, cats) + assert 246232 in email + assert 246232 in reply_to + +@pytest.mark.usefixtures("db_session") +def test_who_to_email_named_category_optout_cascades_to_alias_archive(): + # 60002 opts out at named category econ.GN and mods alias archive q-fin -- + # named-category opt-out should suppress the alias-archive inclusion too + archives, cats = get_all_moderators() + email, _ = who_to_email(CATEGORIES_ACTIVE['econ.GN'], archives, cats) + assert 60002 not in email + @pytest.mark.usefixtures("db_session") def test_who_to_email_no_mods_returns_empty(): archives, cats = get_all_moderators()