Update user cli commands

This commit is contained in:
Tim Van Baak 2020-04-23 21:07:07 -07:00
parent 773e6a23e0
commit dcf039c9de
3 changed files with 67 additions and 123 deletions

View File

@ -1,12 +1,20 @@
# Standard library imports # Standard library imports
import getpass import getpass
import os import logging
import shutil # import shutil
# Module imports # Module imports
from amanuensis.cli.helpers import ( from amanuensis.cli.helpers import (
add_argument, no_argument, requires_user, alias, add_argument,
config_get, config_set, CONFIG_GET_ROOT_VALUE) no_argument,
requires_user,
alias,
config_get,
config_set,
CONFIG_GET_ROOT_VALUE)
from amanuensis.models import UserModel
logger = logging.getLogger(__name__)
@alias('uc') @alias('uc')
@ -18,26 +26,34 @@ def command_create(args):
Create a user Create a user
""" """
# Module imports # Module imports
from amanuensis.config import logger
from amanuensis.user import ( from amanuensis.user import (
UserModel, valid_username, valid_email, create_user) valid_username, valid_email, create_user)
# Verify arguments # Verify arguments
if not valid_username(args.username): if not valid_username(args.username):
logger.error("Invalid username: usernames may only contain alphanumer" logger.error("Invalid username: usernames may only contain alphanumer"
"ic characters, dashes, and underscores") "ic characters, dashes, and underscores")
return -1 return -1
if UserModel.by(name=args.username) is not None:
logger.error("Invalid username: username is already taken")
return -1
if not args.displayname: if not args.displayname:
args.displayname = args.username args.displayname = args.username
if args.email and not valid_email(args.email): if args.email and not valid_email(args.email):
logger.error("Invalid email") logger.error("Invalid email")
return -1 return -1
try:
existing_user = args.model_factory.user(args.username)
if existing_user is not None:
logger.error("Invalid username: username is already taken")
return -1
except Exception:
pass # User doesn't already exist, good to go
# Perform command # Perform command
new_user, tmp_pw = create_user(args.username, args.displayname, args.email) new_user, tmp_pw = create_user(
args.root,
args.model_factory,
args.username,
args.displayname,
args.email)
# Output # Output
print(tmp_pw) print(tmp_pw)
@ -50,41 +66,43 @@ def command_delete(args):
""" """
Delete a user Delete a user
""" """
# Module imports raise NotImplementedError()
from amanuensis.config import logger, prepend, json_rw # # Module imports
# from amanuensis.config import logger, prepend, json_rw
# Perform command # # Perform command
user_path = prepend('user', args.user.id) # user_path = prepend('user', args.user.id)
shutil.rmtree(user_path) # shutil.rmtree(user_path)
with json_rw('user', 'index.json') as index: # with json_rw('user', 'index.json') as index:
del index[args.user.username] # del index[args.user.username]
# TODO resolve user id references in all games # # TODO resolve user id references in all games
# Output # # Output
logger.info("Deleted user {0.username} ({0.id})".format(args.user)) # logger.info("Deleted user {0.username} ({0.id})".format(args.user))
return 0 # return 0
@alias('ul') @alias('ul')
@no_argument @no_argument
def command_list(args): def command_list(args):
"""List all users""" """List all users"""
# Module imports raise NotImplementedError()
from amanuensis.config import prepend, json_ro # # Module imports
from amanuensis.user import UserModel # from amanuensis.config import prepend, json_ro
# from amanuensis.user import UserModel
# Perform command # # Perform command
users = [] # users = []
with json_ro('user', 'index.json') as index: # with json_ro('user', 'index.json') as index:
for username, uid in index.items(): # for username, uid in index.items():
users.append(UserModel.by(uid=uid)) # users.append(UserModel.by(uid=uid))
# Output # # Output
users.sort(key=lambda u: u.username) # users.sort(key=lambda u: u.username)
for user in users: # for user in users:
print("{0.id} {0.displayname} ({0.username})".format(user)) # print("{0.id} {0.displayname} ({0.username})".format(user))
return 0 # return 0
@alias('un') @alias('un')
@ -99,8 +117,7 @@ def command_config(args):
""" """
Interact with a user's config Interact with a user's config
""" """
# Module imports user: UserModel = args.user
from amanuensis.config import logger, json_rw
# Verify arguments # Verify arguments
if args.get and args.set: if args.get and args.set:
@ -109,11 +126,11 @@ def command_config(args):
# Perform command # Perform command
if args.get: if args.get:
config_get(args.user.config, args.get) config_get(user.cfg, args.get)
if args.set: if args.set:
with json_rw(args.user.config_path) as cfg: with user.ctx.edit_config() as cfg:
config_set(args.user.id, cfg, args.set) config_set(user.uid, cfg, args.set)
# Output # Output
return 0 return 0
@ -127,15 +144,14 @@ def command_passwd(args):
""" """
Set a user's password Set a user's password
""" """
# Module imports user: UserModel = args.user
from amanuensis.config import logger
# Verify arguments # Verify arguments
pw = args.password or getpass.getpass("Password: ") password: str = args.password or getpass.getpass("Password: ")
# Perform command # Perform command
args.user.set_password(pw) user.set_password(password)
# Output # Output
logger.info('Updated password for {}'.format(args.user.username)) logger.info('Updated password for {}'.format(user.cfg.username))
return 0 return 0

View File

@ -1,77 +0,0 @@
import os
import re
import time
import uuid
from flask_login import UserMixin, AnonymousUserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from amanuensis.errors import (
ArgumentError, MissingConfigError, IndexMismatchError)
from amanuensis.config import prepend, json_rw, root
from amanuensis.resources import get_stream
class UserModel(UserMixin):
@staticmethod
def by(uid=None, name=None):
"""
Gets the UserModel with the given uid or username
If the uid or name simply does not match an existing user, returns
None. If the uid matches the index but there is something wrong with
the user's config, raises an error.
"""
if uid and name:
raise ArgumentError("uid and name both specified to UserModel.by()")
if not uid and not name:
raise ArgumentError("One of uid or name must be not None")
if not uid:
with root.user.index() as index:
uid = index.get(name)
if not uid:
return None
if not os.path.isdir(prepend('user', uid)):
raise IndexMismatchError("username={} uid={}".format(name, uid))
if not os.path.isfile(prepend('user', uid, 'config.json')):
raise MissingConfigError("uid={}".format(uid))
return UserModel(uid)
def __init__(self, uid):
"""User model initializer, assume all checks were done by by()"""
self.id = str(uid) # Flask-Login checks for this
self.config_path = prepend('user', uid, 'config.json')
self.ctx = root.user[self.id]
with self.ctx.config() as j:
self.config = j
def __getattr__(self, key):
if key not in self.config:
raise AttributeError(key)
return self.config.get(key)
def __str__(self):
return '<{0.username}>'.format(self)
def __repr__(self):
return '<UserModel uid={0.id} username={0.username}>'.format(self)
def set_password(self, pw):
h = generate_password_hash(pw)
with self.ctx.config(edit=True) as j:
j['password'] = h
def check_password(self, pw):
with self.ctx.config() as cfg:
return check_password_hash(cfg.password, pw)
def in_lexicon(self, lexicon):
return self.id in lexicon.join.joined
class AnonymousUserModel(AnonymousUserMixin):
is_admin = False
def in_lexicon(self, lexicon):
return False

View File

@ -1,5 +1,10 @@
from amanuensis.user.signup import create_user from amanuensis.user.signup import (
create_user,
valid_username,
valid_email)
__all__ = [member.__name__ for member in [ __all__ = [member.__name__ for member in [
create_user create_user,
valid_username,
valid_email,
]] ]]