Move list management functions to a class to reuse shared arguments

This commit is contained in:
Adam Goldsmith 2023-01-09 21:48:02 -05:00
parent c49f3c7635
commit 9e3a042a58

View File

@ -5,6 +5,7 @@ Update Mailman 2 lists via a json API of the form {"LIST": ["ADDRESS", ...]}
"""
import argparse
from dataclasses import dataclass
import os
from pathlib import Path
import secrets
@ -18,28 +19,33 @@ PASSWORD_CHARS = string.ascii_letters + string.digits + string.punctuation
PASSWORD_LEN = 18
def newlist(mailman_bin: Path, listname: str, urlhost: str, admin: str):
password = "".join(secrets.choice(PASSWORD_CHARS) for i in range(PASSWORD_LEN))
@dataclass
class ListManager:
mailman_bin: Path
list_name: str
dry_run: bool
output = subprocess.run(
[
mailman_bin / "newlist",
"--quiet",
f"--urlhost={urlhost}",
listname,
admin,
password,
],
encoding="ascii",
capture_output=True,
check=True,
)
for line in output.stdout.splitlines():
print(f"[Creating {listname}] {line}")
def newlist(self, urlhost: str, admin: str):
password = "".join(secrets.choice(PASSWORD_CHARS) for i in range(PASSWORD_LEN))
output = subprocess.run(
[
self.mailman_bin / "newlist",
"--quiet",
f"--urlhost={urlhost}",
self.list_name,
admin,
password,
],
encoding="ascii",
capture_output=True,
check=True,
)
for line in output.stdout.splitlines():
print(f"[Creating {self.list_name}] {line}")
def config_list(mailman_bin: Path, mailing_list: str, dry_run: bool):
config_changes = """
def config_list(self):
config_changes = """
# TODO: set real_name, moderator, subject prefix, and reply-to address
from_is_list = 1
anonymous_list = 1
@ -60,54 +66,51 @@ generic_nonmember_action = 3 # discard non-member emails
forward_auto_discards = 0 # don't notify admin about discards
"""
with tempfile.NamedTemporaryFile("w", suffix=".py") as config_file:
config_file.write(config_changes)
config_file.flush()
with tempfile.NamedTemporaryFile("w", suffix=".py") as config_file:
config_file.write(config_changes)
config_file.flush()
command = [
self.mailman_bin / "config_list",
"--inputfile",
config_file.name,
self.list_name,
]
if self.dry_run:
command.append("--checkonly")
output = subprocess.run(
command,
encoding="ascii",
capture_output=True,
check=True,
)
for line in output.stdout.splitlines():
print(f"[Configuring {self.list_name}] {line}")
def sync_members(self, members: list[str]):
command = [
mailman_bin / "config_list",
"--inputfile",
config_file.name,
mailing_list,
self.mailman_bin / "sync_members",
"--welcome-msg=no",
"--goodbye-msg=no",
"--notifyadmin=no",
"--file",
"-",
self.list_name,
]
if dry_run:
command.append("--checkonly")
if self.dry_run:
command.append("--no-change")
members_data = "\n".join(members)
output = subprocess.run(
command,
input=members_data,
encoding="ascii",
capture_output=True,
check=True,
)
for line in output.stdout.splitlines():
print(f"[Configuring {mailing_list}] {line}")
def sync_members(
mailman_bin: Path, mailing_list: str, members: list[str], dry_run: bool
):
command = [
mailman_bin / "sync_members",
"--welcome-msg=no",
"--goodbye-msg=no",
"--notifyadmin=no",
"--file",
"-",
mailing_list,
]
if dry_run:
command.append("--no-change")
members_data = "\n".join(members)
output = subprocess.run(
command,
input=members_data,
encoding="ascii",
capture_output=True,
check=True,
)
for line in output.stdout.splitlines():
print(f"[Syncing {mailing_list}] {line}")
print(f"[Syncing {self.list_name}] {line}")
def main(
@ -133,16 +136,17 @@ def main(
certification_lists = r.json()
for name, members in certification_lists.items():
list_name = name + list_suffix
list_manager = ListManager(mailman_bin, list_name, dry_run)
if list_name not in existing_lists:
if dry_run:
print(f"Skipping non-existing list {list_name} in dry run mode")
continue
else:
newlist(mailman_bin, list_name, urlhost, admin)
list_manager.newlist(urlhost, admin)
print(f"Configuring/syncing {list_name}...")
config_list(mailman_bin, list_name, dry_run)
sync_members(mailman_bin, list_name, members, dry_run)
list_manager.config_list()
list_manager.sync_members(members)
def parse_arguments():