positions cli

This commit is contained in:
Rio6 2021-08-27 22:57:50 -04:00
parent d8e5b1f1d4
commit 7b289cda56
5 changed files with 65 additions and 3 deletions

View File

@ -8,6 +8,7 @@ from zope import component
from ..krb_check import krb_check from ..krb_check import krb_check
from .members import members from .members import members
from .groups import groups from .groups import groups
from .positions import positions
from .updateprograms import updateprograms from .updateprograms import updateprograms
from ceo_common.interfaces import IConfig, IHTTPClient from ceo_common.interfaces import IConfig, IHTTPClient
from ceo_common.model import Config, HTTPClient from ceo_common.model import Config, HTTPClient
@ -29,10 +30,14 @@ def cli(ctx):
cli.add_command(members) cli.add_command(members)
cli.add_command(groups) cli.add_command(groups)
cli.add_command(positions)
cli.add_command(updateprograms) cli.add_command(updateprograms)
def register_services(): def register_services():
# Using base component directly so events get triggered
baseComponent = component.getGlobalSiteManager()
# Config # Config
# This is a hack to determine if we're in the dev env or not # This is a hack to determine if we're in the dev env or not
if socket.getfqdn().endswith('.csclub.internal'): if socket.getfqdn().endswith('.csclub.internal'):
@ -41,8 +46,8 @@ def register_services():
else: else:
config_file = os.environ.get('CEO_CONFIG', '/etc/csc/ceo.ini') config_file = os.environ.get('CEO_CONFIG', '/etc/csc/ceo.ini')
cfg = Config(config_file) cfg = Config(config_file)
component.provideUtility(cfg, IConfig) baseComponent.registerUtility(cfg, IConfig)
# HTTPService # HTTPService
http_client = HTTPClient() http_client = HTTPClient()
component.provideUtility(http_client, IHTTPClient) baseComponent.registerUtility(http_client, IHTTPClient)

48
ceo/cli/positions.py Normal file
View File

@ -0,0 +1,48 @@
import click
from zope import component
from zope.interface.interfaces import IRegistered, IUtilityRegistration
import zope.component.event
from ceo_common.interfaces import IConfig
from ceod.transactions.members import UpdateMemberPositionsTransaction
from .utils import handle_sync_response, handle_stream_response, print_colon_kv
from ..utils import http_get, http_post
@click.group(short_help='List or change exec positions')
def positions():
pass
@positions.command(short_help='Get current positions')
def get():
resp = http_get('/api/positions')
result = handle_sync_response(resp)
print_colon_kv(result.items())
@positions.command(short_help='Update positions')
def update(**kwargs):
click.echo('The positions will be updated:')
print_colon_kv(kwargs.items())
click.confirm('Do you want to continue?', abort=True)
resp = http_post('/api/positions', json={k.replace('_', '-'): v for k, v in kwargs.items()})
handle_stream_response(resp, UpdateMemberPositionsTransaction.operations)
# Provides dynamic parameter for update command using config file
@component.provideHandler
@component.adapter(IRegistered)
def _handler(event):
global update
if not (IUtilityRegistration.providedBy(event.object) and IConfig.providedBy(event.object.component)):
return
cfg = event.object.component
avail = cfg.get('positions_available')
required = cfg.get('positions_required')
for pos in avail:
update = click.option(f'--{pos}', metavar='USER', required=(pos in required))(update)

View File

@ -24,4 +24,7 @@ descriptions = {
'remove_user_from_auxiliary_groups': 'Remove user from auxiliary groups', 'remove_user_from_auxiliary_groups': 'Remove user from auxiliary groups',
'unsubscribe_user_from_auxiliary_mailing_lists': 'Unsubscribe user from auxiliary mailing lists', 'unsubscribe_user_from_auxiliary_mailing_lists': 'Unsubscribe user from auxiliary mailing lists',
'remove_sudo_role': 'Remove sudo role from LDAP', 'remove_sudo_role': 'Remove sudo role from LDAP',
'update_positions_ldap': 'Update positions in LDAP',
'update_exec_group_ldap': 'Update executive group in LDAP',
'subscribe_to_mailing_lists': 'Subscribe to mailing lists',
} }

View File

@ -28,7 +28,8 @@ class UpdateMemberPositionsTransaction(AbstractTransaction):
# Reverse the dict so it's easier to use (username -> positions) # Reverse the dict so it's easier to use (username -> positions)
self.positions = defaultdict(list) self.positions = defaultdict(list)
for position, username in positions_reversed.items(): for position, username in positions_reversed.items():
self.positions[username].append(position) if username is not None:
self.positions[username].append(position)
# a cached Dict of the Users who need to be modified (username -> User) # a cached Dict of the Users who need to be modified (username -> User)
self.users: Dict[str, IUser] = {} self.users: Dict[str, IUser] = {}

View File

@ -7,3 +7,8 @@ uw_domain = uwaterloo.internal
admin_host = phosphoric-acid admin_host = phosphoric-acid
use_https = false use_https = false
port = 9987 port = 9987
[positions]
required = president,vice-president,sysadmin
available = president,vice-president,treasurer,secretary,
sysadmin,cro,librarian,imapd,webmaster,offsck