Rname User to UserModel, revamp factory function
This commit is contained in:
parent
5972a309f1
commit
8e99788fcd
|
@ -17,11 +17,10 @@ def command_create(args):
|
||||||
settings are as desired before opening the lexicon for player joins.
|
settings are as desired before opening the lexicon for player joins.
|
||||||
"""
|
"""
|
||||||
from lexicon.manage import create_lexicon
|
from lexicon.manage import create_lexicon
|
||||||
import user
|
from user import UserModel
|
||||||
# TODO verify args
|
# TODO verify args
|
||||||
uid = user.uid_from_username(args.editor)
|
editor = UserModel.by(name=args.editor)
|
||||||
u = user.user_from_uid(uid)
|
create_lexicon(args.name, editor)
|
||||||
create_lexicon(args.name, u)
|
|
||||||
|
|
||||||
@requires_lexicon
|
@requires_lexicon
|
||||||
def command_delete(args):
|
def command_delete(args):
|
||||||
|
|
|
@ -2,9 +2,9 @@ from cli.helpers import (
|
||||||
add_argument, no_argument, requires_username,
|
add_argument, no_argument, requires_username,
|
||||||
config_get, config_set, CONFIG_GET_ROOT_VALUE)
|
config_get, config_set, CONFIG_GET_ROOT_VALUE)
|
||||||
|
|
||||||
@add_argument("--username", help="User's login handle")
|
@requires_username
|
||||||
|
@add_argument("--email", required=True, help="User's email")
|
||||||
@add_argument("--displayname", help="User's publicly displayed name")
|
@add_argument("--displayname", help="User's publicly displayed name")
|
||||||
@add_argument("--email", help="User's email")
|
|
||||||
def command_create(args):
|
def command_create(args):
|
||||||
"""
|
"""
|
||||||
Create a user
|
Create a user
|
||||||
|
@ -15,18 +15,14 @@ def command_create(args):
|
||||||
import config
|
import config
|
||||||
|
|
||||||
# Verify or query parameters
|
# Verify or query parameters
|
||||||
if not args.username:
|
|
||||||
args.username = input("username: ").strip()
|
|
||||||
if not user.valid_username(args.username):
|
if not user.valid_username(args.username):
|
||||||
config.logger.error("Invalid username: usernames may only contain alphanumeric characters, dashes, and underscores")
|
config.logger.error("Invalid username: usernames may only contain alphanumeric characters, dashes, and underscores")
|
||||||
return -1
|
return -1
|
||||||
if user.uid_from_username(args.username) is not None:
|
if user.UserModel.by(name=args.username) is not None:
|
||||||
config.logger.error("Invalid username: username is already taken")
|
config.logger.error("Invalid username: username is already taken")
|
||||||
return -1
|
return -1
|
||||||
if not args.displayname:
|
if not args.displayname:
|
||||||
args.displayname = args.username
|
args.displayname = args.username
|
||||||
if not args.email:
|
|
||||||
args.email = input("email: ").strip()
|
|
||||||
if not user.valid_email(args.email):
|
if not user.valid_email(args.email):
|
||||||
config.logger.error("Invalid email")
|
config.logger.error("Invalid email")
|
||||||
return -1
|
return -1
|
||||||
|
@ -37,7 +33,7 @@ def command_create(args):
|
||||||
print(json.dumps(js, indent=2))
|
print(json.dumps(js, indent=2))
|
||||||
print("Username: {}\nUser ID: {}\nPassword: {}".format(args.username, new_user.uid, tmp_pw))
|
print("Username: {}\nUser ID: {}\nPassword: {}".format(args.username, new_user.uid, tmp_pw))
|
||||||
|
|
||||||
@add_argument("--id", help="id of user to delete")
|
@add_argument("--id", required=True, help="id of user to delete")
|
||||||
def command_delete(args):
|
def command_delete(args):
|
||||||
"""
|
"""
|
||||||
Delete a user
|
Delete a user
|
||||||
|
@ -84,23 +80,23 @@ def command_config(args):
|
||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
import config
|
import config
|
||||||
import user
|
from user import UserModel
|
||||||
|
|
||||||
if args.get and args.set:
|
if args.get and args.set:
|
||||||
config.logger.error("Specify one of --get and --set")
|
config.logger.error("Specify one of --get and --set")
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
uid = user.uid_from_username(args.username)
|
u = UserModel.by(name=args.username)
|
||||||
if not uid:
|
if not u:
|
||||||
config.logger.error("User not found")
|
config.logger.error("User not found")
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
if args.get:
|
if args.get:
|
||||||
with config.json_ro('user', uid, 'config.json') as cfg:
|
with config.json_ro('user', u.id, 'config.json') as cfg:
|
||||||
config_get(cfg, args.get)
|
config_get(cfg, args.get)
|
||||||
|
|
||||||
if args.set:
|
if args.set:
|
||||||
with config.json_rw('user', uid, 'config.json') as cfg:
|
with config.json_rw('user', u.id, 'config.json') as cfg:
|
||||||
config_set(cfg, args.set)
|
config_set(cfg, args.set)
|
||||||
|
|
||||||
@add_argument("--username", help="The user to change password for")
|
@add_argument("--username", help="The user to change password for")
|
||||||
|
@ -112,14 +108,13 @@ def command_passwd(args):
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import config
|
import config
|
||||||
import user
|
from user import UserModel
|
||||||
|
|
||||||
if not args.username:
|
if not args.username:
|
||||||
args.username = input("Username: ")
|
args.username = input("Username: ")
|
||||||
uid = user.uid_from_username(args.username)
|
u = UserModel.by(name=args.username)
|
||||||
if uid is None:
|
if u is None:
|
||||||
config.logger.error("No user with username '{}'".format(args.username))
|
config.logger.error("No user with username '{}'".format(args.username))
|
||||||
return -1
|
return -1
|
||||||
u = user.user_from_uid(uid)
|
|
||||||
pw = getpass.getpass("Password: ")
|
pw = getpass.getpass("Password: ")
|
||||||
u.set_password(pw)
|
u.set_password(pw)
|
||||||
|
|
|
@ -5,7 +5,7 @@ from wtforms.validators import DataRequired
|
||||||
from flask_login import current_user, login_user, logout_user, login_required
|
from flask_login import current_user, login_user, logout_user, login_required
|
||||||
|
|
||||||
import config
|
import config
|
||||||
import user
|
from user import UserModel
|
||||||
|
|
||||||
class LoginForm(FlaskForm):
|
class LoginForm(FlaskForm):
|
||||||
username = StringField('Username', validators=[DataRequired()])
|
username = StringField('Username', validators=[DataRequired()])
|
||||||
|
@ -19,25 +19,21 @@ def get_bp(login_manager):
|
||||||
|
|
||||||
@login_manager.user_loader
|
@login_manager.user_loader
|
||||||
def load_user(uid):
|
def load_user(uid):
|
||||||
return user.user_from_uid(str(uid))
|
return UserModel.by(uid=str(uid))
|
||||||
|
|
||||||
@bp.route('/login/', methods=['GET', 'POST'])
|
@bp.route('/login/', methods=['GET', 'POST'])
|
||||||
def login():
|
def login():
|
||||||
form = LoginForm()
|
form = LoginForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
username = form.username.data
|
username = form.username.data
|
||||||
uid = user.uid_from_username(username)
|
u = UserModel.by(name=username)
|
||||||
if uid is not None:
|
if u is not None and u.check_password(form.password.data):
|
||||||
u = user.user_from_uid(uid)
|
|
||||||
if u.check_password(form.password.data):
|
|
||||||
remember_me = form.remember.data
|
remember_me = form.remember.data
|
||||||
login_user(u, remember=remember_me)
|
login_user(u, remember=remember_me)
|
||||||
config.logger.info("Logged in user '{}' ({})".format(
|
config.logger.info("Logged in user '{}' ({})".format(
|
||||||
u.username, u.uid))
|
u.username, u.uid))
|
||||||
return redirect(url_for('home.home'))
|
return redirect(url_for('home.home'))
|
||||||
flash("Login not recognized")
|
flash("Login not recognized")
|
||||||
else:
|
|
||||||
pass
|
|
||||||
return render_template('auth/login.html', form=form)
|
return render_template('auth/login.html', form=form)
|
||||||
|
|
||||||
@bp.route("/logout/", methods=['GET'])
|
@bp.route("/logout/", methods=['GET'])
|
||||||
|
|
|
@ -6,15 +6,37 @@ import uuid
|
||||||
from flask_login import UserMixin
|
from flask_login import UserMixin
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
|
|
||||||
|
from errors import InternalMisuseError, MissingConfigError, IndexMismatchError
|
||||||
import config
|
import config
|
||||||
import resources
|
import resources
|
||||||
|
|
||||||
class User(UserMixin):
|
class UserModel(UserMixin):
|
||||||
def __init__(self, uid):
|
@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 InternalMisuseError("uid and name both specified to UserModel.by()")
|
||||||
|
if not uid and not name:
|
||||||
|
raise ValueError("One of uid or name must be not None")
|
||||||
|
if not uid:
|
||||||
|
with config.json_ro('user', 'index.json') as index:
|
||||||
|
uid = index.get(name)
|
||||||
|
if not uid:
|
||||||
|
return None
|
||||||
if not os.path.isdir(config.prepend('user', uid)):
|
if not os.path.isdir(config.prepend('user', uid)):
|
||||||
raise ValueError("No user with uid {}".format(uid))
|
raise IndexMismatchError("username={} uid={}".format(name, uid))
|
||||||
if not os.path.isfile(config.prepend('user', uid, 'config.json')):
|
if not os.path.isfile(config.prepend('user', uid, 'config.json')):
|
||||||
raise FileNotFoundError("User {} missing config.json".format(uid))
|
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.id = str(uid) # Flask-Login checks for this
|
||||||
self.config_path = config.prepend('user', uid, 'config.json')
|
self.config_path = config.prepend('user', uid, 'config.json')
|
||||||
with config.json_ro(self.config_path) as j:
|
with config.json_ro(self.config_path) as j:
|
||||||
|
@ -76,25 +98,7 @@ def create_user(username, displayname, email):
|
||||||
|
|
||||||
# Set a temporary password
|
# Set a temporary password
|
||||||
temp_pw = os.urandom(32).hex()
|
temp_pw = os.urandom(32).hex()
|
||||||
u = User(uid)
|
u = UserModel.by(uid=uid)
|
||||||
u.set_password(temp_pw)
|
u.set_password(temp_pw)
|
||||||
|
|
||||||
return u, temp_pw
|
return u, temp_pw
|
||||||
|
|
||||||
def uid_from_username(username):
|
|
||||||
"""Gets the internal uid of a user given a username"""
|
|
||||||
if username is None:
|
|
||||||
raise ValueError("username must not be None")
|
|
||||||
if not username:
|
|
||||||
raise ValueError("username must not be empty")
|
|
||||||
with config.json_ro('user', 'index.json') as index:
|
|
||||||
uid = index.get(username)
|
|
||||||
if uid is None:
|
|
||||||
config.logger.debug("uid_from_username('{}') returned None".format(username))
|
|
||||||
return uid
|
|
||||||
|
|
||||||
def user_from_uid(uid):
|
|
||||||
if not os.path.isdir(config.prepend('user', uid)):
|
|
||||||
config.logger.debug("No user with uid '{}'".format(uid))
|
|
||||||
return None
|
|
||||||
return User(uid)
|
|
||||||
|
|
Loading…
Reference in New Issue