From c49f3c76350edb10576068da1dfe0b492b713114 Mon Sep 17 00:00:00 2001 From: Adam Goldsmith Date: Mon, 9 Jan 2023 21:37:27 -0500 Subject: [PATCH] Create lists if they don't already exist --- mailman_sync.py | 64 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/mailman_sync.py b/mailman_sync.py index d1db2c5..a172e69 100755 --- a/mailman_sync.py +++ b/mailman_sync.py @@ -7,11 +7,36 @@ Update Mailman 2 lists via a json API of the form {"LIST": ["ADDRESS", ...]} import argparse import os from pathlib import Path +import secrets +import string import subprocess import tempfile import requests +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)) + + 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 config_list(mailman_bin: Path, mailing_list: str, dry_run: bool): config_changes = """ @@ -85,7 +110,15 @@ def sync_members( print(f"[Syncing {mailing_list}] {line}") -def main(mailman_bin: Path, api: str, api_auth: str, list_suffix: str, dry_run: bool): +def main( + mailman_bin: Path, + api: str, + api_auth: str, + list_suffix: str, + dry_run: bool, + urlhost: str, + admin: str, +): r = requests.get(api, headers={"Authorization": api_auth}) if not r.ok: print(f"Failed to get mailing list data from api: {r.status_code} {r.text}") @@ -100,13 +133,16 @@ def main(mailman_bin: Path, api: str, api_auth: str, list_suffix: str, dry_run: certification_lists = r.json() for name, members in certification_lists.items(): list_name = name + list_suffix - if list_name in existing_lists: - print(f"Configuring/syncing {list_name}...") - config_list(mailman_bin, list_name, dry_run) - sync_members(mailman_bin, list_name, members, dry_run) - else: - print(f"Skipping {list_name}, as it does not exist in Mailman") + 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) + print(f"Configuring/syncing {list_name}...") + config_list(mailman_bin, list_name, dry_run) + sync_members(mailman_bin, list_name, members, dry_run) def parse_arguments(): @@ -119,6 +155,10 @@ def parse_arguments(): ) argp.add_argument("--api", required=True, help="API endpoint to retrieve JSON from") argp.add_argument("--list-suffix", help="Suffix for mailing lists") + argp.add_argument("--urlhost", help="Urlhost to use when creating new lists") + argp.add_argument( + "--admin", help="Admin email address to use when creating new lists" + ) argp.add_argument( "-n", "--dry-run", @@ -138,7 +178,15 @@ if __name__ == "__main__": exit(-1) try: - main(args.bin, args.api, api_auth, args.list_suffix, args.dry_run) + main( + args.bin, + args.api, + api_auth, + args.list_suffix, + args.dry_run, + args.urlhost, + args.admin, + ) except subprocess.CalledProcessError as e: print(e.stderr) raise