diff --git a/amanuensis/__main__.py b/amanuensis/__main__.py index 92114d5..18734ee 100644 --- a/amanuensis/__main__.py +++ b/amanuensis/__main__.py @@ -5,6 +5,7 @@ import traceback # Module imports import amanuensis.cli as cli +from amanuensis.cli.helpers import USER_ARGS, USER_KWARGS import amanuensis.config as config @@ -83,10 +84,7 @@ def get_parser(valid_commands): metavar="LEXICON", dest="tl_lexicon", help="Specify a lexicon to operate on") - parser.add_argument("-u", - metavar="USERNAME", - dest="tl_username", - help="Specify a user to operate on") + parser.add_argument(*USER_ARGS, **USER_KWARGS) parser.set_defaults( func=lambda args: repl(args) if args.tl_lexicon diff --git a/amanuensis/cli/helpers.py b/amanuensis/cli/helpers.py index 652a54e..f4121c9 100644 --- a/amanuensis/cli/helpers.py +++ b/amanuensis/cli/helpers.py @@ -80,15 +80,19 @@ def requires_lexicon(command): augmented_command.__dict__['wrapper'] = True return augmented_command - -def requires_username(command): +USER_ARGS = ['--user'] +USER_KWARGS = {'metavar': 'USER', 'dest': 'user', + 'help': 'Specify a user to operate on'} +def requires_user(command): + """ + Performs all necessary setup and verification for passing a user to a CLI + command. + """ @wraps(command) def augmented_command(cmd_args): # Add user argument in parser pass if isinstance(cmd_args, ArgumentParser): - cmd_args.add_argument( - "-u", metavar="USERNAME", dest="username", - help="Specify a user to operate on") + cmd_args.add_argument(*USER_ARGS, **USER_KWARGS) # If there are more command wrappers, pass through to them if command.__dict__.get('wrapper', False): command(cmd_args) @@ -96,17 +100,18 @@ def requires_username(command): return None # Verify user argument in execute pass - base_val = (hasattr(cmd_args, "tl_username") - and getattr(cmd_args, "tl_lexicon")) - subp_val = (hasattr(cmd_args, "username") - and getattr(cmd_args, "username")) + base_val = (hasattr(cmd_args, "tl_user") + and getattr(cmd_args, "tl_user")) + subp_val = (hasattr(cmd_args, "user") + and getattr(cmd_args, "user")) val = subp_val or base_val or None if not val: from amanuensis.config import logger logger.error("This command requires specifying a user") return -1 - # from amanuensis.user import UserModel - cmd_args.username = val#UserModel.by(name=val).name TODO + from amanuensis.user import UserModel + cmd_args.user = UserModel.by(name=val) + # TODO more thorough verification of argument val return command(cmd_args) augmented_command.__dict__['wrapper'] = True diff --git a/amanuensis/cli/user.py b/amanuensis/cli/user.py index eff9dfd..f86e3b7 100644 --- a/amanuensis/cli/user.py +++ b/amanuensis/cli/user.py @@ -1,23 +1,28 @@ +# Standard imports +import getpass +import json +import os import shutil +# Module imports from amanuensis.cli.helpers import ( - add_argument, no_argument, requires_username, + add_argument, no_argument, requires_user, config_get, config_set, CONFIG_GET_ROOT_VALUE) -@requires_username -@add_argument("--email", required=True, help="User's email") + +@add_argument("--username", required=True, help="Name of user to create") +@add_argument("--email", help="User's email") @add_argument("--displayname", help="User's publicly displayed name") def command_create(args): """ Create a user """ - import json # Module imports from amanuensis.config import logger, json_ro from amanuensis.user import ( UserModel, valid_username, valid_email, create_user) - # Verify or query parameters + # Verify arguments if not valid_username(args.username): logger.error("Invalid username: usernames may only contain alphanumer" "ic characters, dashes, and underscores") @@ -27,48 +32,46 @@ def command_create(args): return -1 if not args.displayname: args.displayname = args.username - if not valid_email(args.email): + if args.email and not valid_email(args.email): logger.error("Invalid email") return -1 - # Create user + # Perform command new_user, tmp_pw = create_user(args.username, args.displayname, args.email) - with json_ro(new_user.config_path) as js: - print(json.dumps(js, indent=2)) - print("Username: {}\nUser ID: {}\nPassword: {}".format( - args.username, new_user.uid, tmp_pw)) + # Output + print(tmp_pw) return 0 -@add_argument("--id", required=True, help="id of user to delete") + +@requires_user def command_delete(args): """ Delete a user """ - import os # Module imports from amanuensis.config import logger, prepend, json_rw - user_path = prepend('user', args.id) - if not os.path.isdir(user_path): - logger.error("No user with that id") - return -1 + # Perform command + user_path = prepend('user', args.user.id) shutil.rmtree(user_path) - with json_rw('user', 'index.json') as j: - if args.id in j: # TODO this is wrong - del j[args.id] + with json_rw('user', 'index.json') as index: + del index[args.user.username] - # TODO + # TODO resolve user id references in all games + # Output + logger.info("Deleted user {0.username} ({0.id})".format(args.user)) return 0 + @no_argument def command_list(args): """List all users""" - import os # Module imports from amanuensis.config import prepend, json_ro + # Perform command user_dirs = os.listdir(prepend('user')) users = [] for uid in user_dirs: @@ -76,14 +79,16 @@ def command_list(args): continue with json_ro('user', uid, 'config.json') as user: users.append(user) + + # Output users.sort(key=lambda u: u['username']) for user in users: print("{0} {1} ({2})".format( user['uid'], user['displayname'], user['username'])) - return 0 -@requires_username + +@requires_user @add_argument( "--get", metavar="PATHSPEC", dest="get", nargs="?", const=CONFIG_GET_ROOT_VALUE, help="Get the value of a config key") @@ -98,43 +103,39 @@ def command_config(args): from amanuensis.config import logger, json_ro, json_rw from amanuensis.user import UserModel + # Verify arguments if args.get and args.set: logger.error("Specify one of --get and --set") return -1 - u = UserModel.by(name=args.username) - if not u: - logger.error("User not found") - return -1 - + # Perform command if args.get: - with json_ro('user', u.id, 'config.json') as cfg: - config_get(cfg, args.get) + config_get(args.user.config, args.get) if args.set: - with json_rw('user', u.id, 'config.json') as cfg: - config_set(u.id, cfg, args.set) + with json_rw(args.user.config_path) as cfg: + config_set(args.user.id, cfg, args.set) + # Output return 0 -@add_argument("--username", help="The user to change password for") -@add_argument("--password", help="The password to set. Not recommended") + +@requires_user +@add_argument("--password", help="The password to set. Used for scripting; " + "not recommended for general use") def command_passwd(args): """ Set a user's password """ - import getpass # Module imports from amanuensis.config import logger from amanuensis.user import UserModel - if not args.username: - args.username = input("Username: ") - u = UserModel.by(name=args.username) - if u is None: - logger.error("No user with username '{}'".format(args.username)) - return -1 + # Verify arguments pw = args.password or getpass.getpass("Password: ") - u.set_password(pw) + # Perform commands + args.user.set_password(pw) + + # Output return 0