Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions app/moderators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
9 changes: 9 additions & 0 deletions tests/data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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,'[email protected]',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,'[email protected]',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,'[email protected]',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,'[email protected]',8,0,2,1384185389,'','',0,0,0,1,1,0,0,0,0,'',0,0);
Expand Down
24 changes: 24 additions & 0 deletions tests/test_moderators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading