From 2a5d903eba78217bf8ac03b150b50f00ddd20d29 Mon Sep 17 00:00:00 2001 From: Max Erenberg <> Date: Sat, 25 Sep 2021 15:16:22 -0400 Subject: [PATCH] add mailman CLI command --- ceo/cli/entrypoint.py | 2 ++ ceo/cli/mailman.py | 29 +++++++++++++++++++++++++++++ ceo/utils.py | 2 ++ ceod/api/utils.py | 2 +- tests/ceo/cli/test_mailman.py | 23 +++++++++++++++++++++++ tests/ceo_dev.ini | 1 + 6 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 ceo/cli/mailman.py create mode 100644 tests/ceo/cli/test_mailman.py diff --git a/ceo/cli/entrypoint.py b/ceo/cli/entrypoint.py index b0edd59..c44cda5 100644 --- a/ceo/cli/entrypoint.py +++ b/ceo/cli/entrypoint.py @@ -6,6 +6,7 @@ from .positions import positions from .updateprograms import updateprograms from .mysql import mysql from .postgresql import postgresql +from .mailman import mailman @click.group() @@ -19,3 +20,4 @@ cli.add_command(positions) cli.add_command(updateprograms) cli.add_command(mysql) cli.add_command(postgresql) +cli.add_command(mailman) diff --git a/ceo/cli/mailman.py b/ceo/cli/mailman.py new file mode 100644 index 0000000..8d4a732 --- /dev/null +++ b/ceo/cli/mailman.py @@ -0,0 +1,29 @@ +import click + +from ..utils import http_post, http_delete +from .utils import handle_sync_response + + +@click.group(short_help='Manage mailing list subscriptions') +def mailman(): + pass + + +@mailman.command(short_help='Subscribe a member to a mailing list') +@click.argument('username') +@click.argument('mailing_list') +def subscribe(username, mailing_list): + click.confirm(f'Are you sure you want to subscribe {username} to {mailing_list}?', abort=True) + resp = http_post(f'/api/mailman/{mailing_list}/{username}') + handle_sync_response(resp) + click.echo('Done.') + + +@mailman.command(short_help='Unsubscribe a member from a mailing list') +@click.argument('username') +@click.argument('mailing_list') +def unsubscribe(username, mailing_list): + click.confirm(f'Are you sure you want to unsubscribe {username} from {mailing_list}?', abort=True) + resp = http_delete(f'/api/mailman/{mailing_list}/{username}') + handle_sync_response(resp) + click.echo('Done.') diff --git a/ceo/utils.py b/ceo/utils.py index a23ecd5..bb47669 100644 --- a/ceo/utils.py +++ b/ceo/utils.py @@ -16,6 +16,8 @@ def http_request(method: str, path: str, **kwargs) -> requests.Response: cfg = component.getUtility(IConfig) if path.startswith('/api/db'): host = cfg.get('ceod_database_host') + elif path.startswith('/api/mailman'): + host = cfg.get('ceod_mailman_host') else: host = cfg.get('ceod_admin_host') return client.request( diff --git a/ceod/api/utils.py b/ceod/api/utils.py index 3db9056..5b7c2da 100644 --- a/ceod/api/utils.py +++ b/ceod/api/utils.py @@ -67,7 +67,7 @@ def authz_restrict_to_groups(f: Callable, allowed_groups: List[str]) -> Callable def authz_restrict_to_staff(f: Callable) -> Callable: """A decorator to restrict an endpoint to staff members.""" - allowed_groups = ['office', 'staff', 'adm'] + allowed_groups = ['syscom', 'exec', 'office', 'staff', 'adm'] return authz_restrict_to_groups(f, allowed_groups) diff --git a/tests/ceo/cli/test_mailman.py b/tests/ceo/cli/test_mailman.py new file mode 100644 index 0000000..f8fe0f8 --- /dev/null +++ b/tests/ceo/cli/test_mailman.py @@ -0,0 +1,23 @@ +from click.testing import CliRunner + +from ceo.cli import cli + + +def test_mailman_subscribe(cli_setup, mock_mailman_server): + mock_mailman_server.clear() + runner = CliRunner() + result = runner.invoke(cli, ['mailman', 'subscribe', 'test_1', 'exec'], input='y\n') + expected = ( + "Are you sure you want to subscribe test_1 to exec? [y/N]: y\n" + "Done.\n" + ) + assert result.exit_code == 0 + assert result.output == expected + + result = runner.invoke(cli, ['mailman', 'unsubscribe', 'test_1', 'exec'], input='y\n') + expected = ( + "Are you sure you want to unsubscribe test_1 from exec? [y/N]: y\n" + "Done.\n" + ) + assert result.exit_code == 0 + assert result.output == expected diff --git a/tests/ceo_dev.ini b/tests/ceo_dev.ini index 08652dc..f2d11fa 100644 --- a/tests/ceo_dev.ini +++ b/tests/ceo_dev.ini @@ -6,6 +6,7 @@ uw_domain = uwaterloo.internal # this is the host with the ceod/admin Kerberos key admin_host = phosphoric-acid database_host = coffee +mailman_host = mail use_https = false port = 9987