Allow addmember and removemember to accept multiple usernames (#67)
continuous-integration/drone/push Build is passing Details

Closes #57.

Reviewed-on: #67
This commit is contained in:
Max Erenberg 2022-07-02 11:26:38 -04:00
parent dc412ef5cb
commit 32b2dbb307
2 changed files with 86 additions and 67 deletions

View File

@ -68,75 +68,78 @@ def get(group_name):
print_group_lines(result) print_group_lines(result)
@groups.command(short_help='Add a member to a group') @groups.command(short_help='Add one or more members to a group')
@click.argument('group_name') @click.argument('group_name')
@click.argument('username') @click.argument('username')
@click.argument('usernames', nargs=-1)
@click.option('--no-subscribe', is_flag=True, default=False, @click.option('--no-subscribe', is_flag=True, default=False,
help='Do not subscribe the member to any auxiliary mailing lists.') help='Do not subscribe the member(s) to any auxiliary mailing lists.')
def addmember(group_name, username, no_subscribe): def addmember(group_name, username, usernames, no_subscribe):
click.confirm(f'Are you sure you want to add {username} to {group_name}?', usernames = [username, *usernames]
abort=True) if len(usernames) == 1:
click.confirm(f'Are you sure you want to add {username} to {group_name}?',
abort=True)
else:
click.echo(f'The following users will be added to {group_name}:')
click.echo(', '.join(usernames))
click.confirm('Do you want to continue?', abort=True)
base_domain = component.getUtility(IConfig).get('base_domain') base_domain = component.getUtility(IConfig).get('base_domain')
url = f'/api/groups/{group_name}/members/{username}'
operations = AddMemberToGroupTransaction.operations operations = AddMemberToGroupTransaction.operations
if no_subscribe: if no_subscribe:
url += '?subscribe_to_lists=false'
operations.remove('subscribe_user_to_auxiliary_mailing_lists') operations.remove('subscribe_user_to_auxiliary_mailing_lists')
resp = http_post(url) for username in usernames:
data = handle_stream_response(resp, operations) url = f'/api/groups/{group_name}/members/{username}'
result = data[-1]['result'] if no_subscribe:
lines = [] url += '?subscribe_to_lists=false'
for i, group in enumerate(result['added_to_groups']): resp = http_post(url)
if i == 0: data = handle_stream_response(resp, operations)
prefix = 'Added to groups' result = data[-1]['result']
else: click.echo(f'Added {username} to ' + ', '.join(result['added_to_groups']))
prefix = '' if result.get('subscribed_to_lists'):
lines.append((prefix, group)) mailing_lists = [
for i, mailing_list in enumerate(result.get('subscribed_to_lists', [])): mailing_list + '@' + base_domain
if i == 0: if '@' not in mailing_list
prefix = 'Subscribed to lists' else mailing_list
else: for mailing_list in result['subscribed_to_lists']
prefix = '' ]
if '@' not in mailing_list: click.echo(f'Subscribed {username} to ' + ', '.join(mailing_lists))
mailing_list += '@' + base_domain
lines.append((prefix, mailing_list))
print_colon_kv(lines)
@groups.command(short_help='Remove a member from a group') @groups.command(short_help='Remove one or more members from a group')
@click.argument('group_name') @click.argument('group_name')
@click.argument('username') @click.argument('username')
@click.argument('usernames', nargs=-1)
@click.option('--no-unsubscribe', is_flag=True, default=False, @click.option('--no-unsubscribe', is_flag=True, default=False,
help='Do not unsubscribe the member from any auxiliary mailing lists.') help='Do not unsubscribe the member(s) from any auxiliary mailing lists.')
def removemember(group_name, username, no_unsubscribe): def removemember(group_name, username, usernames, no_unsubscribe):
click.confirm(f'Are you sure you want to remove {username} from {group_name}?', usernames = [username, *usernames]
abort=True) if len(usernames) == 1:
click.confirm(f'Are you sure you want to remove {username} from {group_name}?',
abort=True)
else:
click.echo(f'The following users will be removed from {group_name}:')
click.echo(', '.join(usernames))
click.confirm('Do you want to continue?', abort=True)
base_domain = component.getUtility(IConfig).get('base_domain') base_domain = component.getUtility(IConfig).get('base_domain')
url = f'/api/groups/{group_name}/members/{username}'
operations = RemoveMemberFromGroupTransaction.operations operations = RemoveMemberFromGroupTransaction.operations
if no_unsubscribe: if no_unsubscribe:
url += '?unsubscribe_from_lists=false'
operations.remove('unsubscribe_user_from_auxiliary_mailing_lists') operations.remove('unsubscribe_user_from_auxiliary_mailing_lists')
resp = http_delete(url) for username in usernames:
data = handle_stream_response(resp, operations) url = f'/api/groups/{group_name}/members/{username}'
result = data[-1]['result'] if no_unsubscribe:
lines = [] url += '?unsubscribe_from_lists=false'
for i, group in enumerate(result['removed_from_groups']): resp = http_delete(url)
if i == 0: data = handle_stream_response(resp, operations)
prefix = 'Removed from groups' result = data[-1]['result']
else: click.echo(f'Removed {username} from ' + ', '.join(result['removed_from_groups']))
prefix = '' if result.get('unsubscribed_from_lists'):
lines.append((prefix, group)) mailing_lists = [
for i, mailing_list in enumerate(result.get('unsubscribed_from_lists', [])): mailing_list + '@' + base_domain
if i == 0: if '@' not in mailing_list
prefix = 'Unsubscribed from lists' else mailing_list
else: for mailing_list in result['unsubscribed_from_lists']
prefix = '' ]
if '@' not in mailing_list: click.echo(f'Unsubscribed {username} from ' + ', '.join(mailing_lists))
mailing_list += '@' + base_domain
lines.append((prefix, mailing_list))
print_colon_kv(lines)
@groups.command(short_help='Delete a group') @groups.command(short_help='Delete a group')

View File

@ -47,7 +47,7 @@ def test_groups(cli_setup, ldap_user):
"Add user to auxiliary groups... Skipped\n" "Add user to auxiliary groups... Skipped\n"
"Subscribe user to auxiliary mailing lists... Skipped\n" "Subscribe user to auxiliary mailing lists... Skipped\n"
"Transaction successfully completed.\n" "Transaction successfully completed.\n"
"Added to groups: test_group_1\n" f"Added {ldap_user.uid} to test_group_1\n"
) )
assert result.exit_code == 0 assert result.exit_code == 0
assert result.output == expected assert result.output == expected
@ -68,7 +68,7 @@ def test_groups(cli_setup, ldap_user):
"Remove user from auxiliary groups... Skipped\n" "Remove user from auxiliary groups... Skipped\n"
"Unsubscribe user from auxiliary mailing lists... Skipped\n" "Unsubscribe user from auxiliary mailing lists... Skipped\n"
"Transaction successfully completed.\n" "Transaction successfully completed.\n"
"Removed from groups: test_group_1\n" f"Removed {ldap_user.uid} from test_group_1\n"
) )
assert result.exit_code == 0 assert result.exit_code == 0
assert result.output == expected assert result.output == expected
@ -92,6 +92,28 @@ def delete_group(group_name):
assert result.exit_code == 0 assert result.exit_code == 0
def test_groups_multiple_members(cli_setup, new_user_gen):
runner = CliRunner()
create_group('test_group_1', 'Test Group 1')
with new_user_gen() as user1, new_user_gen() as user2:
result = runner.invoke(cli, [
'groups', 'addmember', 'test_group_1', user1.uid, user2.uid
], input='y\n')
assert result.exit_code == 0
lines = result.output.splitlines()
assert f'Added {user1.uid} to test_group_1' in lines
assert f'Added {user2.uid} to test_group_1' in lines
result = runner.invoke(cli, [
'groups', 'removemember', 'test_group_1', user1.uid, user2.uid
], input='y\n')
assert result.exit_code == 0
lines = result.output.splitlines()
assert f'Removed {user1.uid} from test_group_1' in lines
assert f'Removed {user2.uid} from test_group_1' in lines
delete_group('test_group_1')
def test_groups_with_auxiliary_groups_and_mailing_lists(cli_setup, ldap_user): def test_groups_with_auxiliary_groups_and_mailing_lists(cli_setup, ldap_user):
runner = CliRunner() runner = CliRunner()
# make sure auxiliary groups + mailing lists exist in ceod_test_local.ini # make sure auxiliary groups + mailing lists exist in ceod_test_local.ini
@ -109,11 +131,8 @@ def test_groups_with_auxiliary_groups_and_mailing_lists(cli_setup, ldap_user):
"Add user to auxiliary groups... Done\n" "Add user to auxiliary groups... Done\n"
"Subscribe user to auxiliary mailing lists... Done\n" "Subscribe user to auxiliary mailing lists... Done\n"
"Transaction successfully completed.\n" "Transaction successfully completed.\n"
"Added to groups: syscom\n" f"Added {ldap_user.uid} to syscom, office, staff\n"
" office\n" f"Subscribed {ldap_user.uid} to syscom@csclub.internal, syscom-alerts@csclub.internal\n"
" staff\n"
"Subscribed to lists: syscom@csclub.internal\n"
" syscom-alerts@csclub.internal\n"
) )
assert result.exit_code == 0 assert result.exit_code == 0
assert result.output == expected assert result.output == expected
@ -128,11 +147,8 @@ def test_groups_with_auxiliary_groups_and_mailing_lists(cli_setup, ldap_user):
"Remove user from auxiliary groups... Done\n" "Remove user from auxiliary groups... Done\n"
"Unsubscribe user from auxiliary mailing lists... Done\n" "Unsubscribe user from auxiliary mailing lists... Done\n"
"Transaction successfully completed.\n" "Transaction successfully completed.\n"
"Removed from groups: syscom\n" f"Removed {ldap_user.uid} from syscom, office, staff\n"
" office\n" f"Unsubscribed {ldap_user.uid} from syscom@csclub.internal, syscom-alerts@csclub.internal\n"
" staff\n"
"Unsubscribed from lists: syscom@csclub.internal\n"
" syscom-alerts@csclub.internal\n"
) )
assert result.exit_code == 0 assert result.exit_code == 0
assert result.output == expected assert result.output == expected
@ -142,14 +158,14 @@ def test_groups_with_auxiliary_groups_and_mailing_lists(cli_setup, ldap_user):
'groups', 'addmember', 'syscom', ldap_user.uid, '--no-subscribe', 'groups', 'addmember', 'syscom', ldap_user.uid, '--no-subscribe',
], input='y\n') ], input='y\n')
assert result.exit_code == 0 assert result.exit_code == 0
assert 'Subscribed to lists' not in result.output assert 'Subscribed' not in result.output
runner = CliRunner() runner = CliRunner()
result = runner.invoke(cli, [ result = runner.invoke(cli, [
'groups', 'removemember', 'syscom', ldap_user.uid, '--no-unsubscribe', 'groups', 'removemember', 'syscom', ldap_user.uid, '--no-unsubscribe',
], input='y\n') ], input='y\n')
assert result.exit_code == 0 assert result.exit_code == 0
assert 'Unsubscribed from lists' not in result.output assert 'Unsubscribed' not in result.output
delete_group('syscom') delete_group('syscom')
delete_group('office') delete_group('office')