Fix namespaces

This commit is contained in:
Tim Van Baak 2020-01-23 15:13:34 -08:00
parent 125de90a18
commit 9be848e5e2
16 changed files with 203 additions and 197 deletions

View File

@ -4,8 +4,8 @@ import os
import traceback import traceback
# Module imports # Module imports
import cli import amanuensis.cli as cli
import config import amanuensis.config as config
def repl(args): def repl(args):

View File

@ -10,8 +10,8 @@
def server_commands(commands={}): def server_commands(commands={}):
if commands: return commands if commands: return commands
import cli.server import amanuensis.cli.server
for name, func in vars(cli.server).items(): for name, func in vars(amanuensis.cli.server).items():
if name.startswith("command_"): if name.startswith("command_"):
name = name[8:].replace("_", "-") name = name[8:].replace("_", "-")
commands[name] = func commands[name] = func
@ -19,8 +19,8 @@ def server_commands(commands={}):
def lexicon_commands(commands={}): def lexicon_commands(commands={}):
if commands: return commands if commands: return commands
import cli.lexicon import amanuensis.cli.lexicon
for name, func in vars(cli.lexicon).items(): for name, func in vars(amanuensis.cli.lexicon).items():
if name.startswith("command_"): if name.startswith("command_"):
name = name[8:].replace("_", "-") name = name[8:].replace("_", "-")
commands["lexicon-" + name] = func commands["lexicon-" + name] = func
@ -28,8 +28,8 @@ def lexicon_commands(commands={}):
def user_commands(commands={}): def user_commands(commands={}):
if commands: return commands if commands: return commands
import cli.user import amanuensis.cli.user
for name, func in vars(cli.user).items(): for name, func in vars(amanuensis.cli.user).items():
if name.startswith("command_"): if name.startswith("command_"):
name = name[8:].replace("_", "-") name = name[8:].replace("_", "-")
commands["user-" + name] = func commands["user-" + name] = func

View File

@ -43,10 +43,10 @@ def requires_lexicon(command):
subp_val = hasattr(cmd_args, "lexicon") and getattr(cmd_args, "lexicon") subp_val = hasattr(cmd_args, "lexicon") and getattr(cmd_args, "lexicon")
val = subp_val or base_val or None val = subp_val or base_val or None
if not val: if not val:
import config from amanuensis.config import logger
config.logger.error("This command requires specifying a lexicon") logger.error("This command requires specifying a lexicon")
return -1 return -1
from lexicon import LexiconModel from amanuensis.lexicon import LexiconModel
cmd_args.lexicon = val#LexiconModel.by(name=val).name cmd_args.lexicon = val#LexiconModel.by(name=val).name
command(cmd_args) command(cmd_args)
augmented_command.__dict__['wrapper'] = True augmented_command.__dict__['wrapper'] = True
@ -64,10 +64,10 @@ def requires_username(command):
subp_val = hasattr(cmd_args, "username") and getattr(cmd_args, "username") subp_val = hasattr(cmd_args, "username") and getattr(cmd_args, "username")
val = subp_val or base_val or None val = subp_val or base_val or None
if not val: if not val:
import config from amanuensis.config import logger
config.logger.error("This command requires specifying a user") logger.error("This command requires specifying a user")
return -1 return -1
from user import UserModel from amanuensis.user import UserModel
cmd_args.username = val#UserModel.by(name=val).name cmd_args.username = val#UserModel.by(name=val).name
command(cmd_args) command(cmd_args)
augmented_command.__dict__['wrapper'] = True augmented_command.__dict__['wrapper'] = True
@ -84,7 +84,7 @@ def config_get(cfg, pathspec):
path is the full pathspec, unsplit path is the full pathspec, unsplit
""" """
import json import json
from config import logger from amanuensis.config import logger
if pathspec is CONFIG_GET_ROOT_VALUE: if pathspec is CONFIG_GET_ROOT_VALUE:
path = [] path = []
@ -105,7 +105,7 @@ def config_set(obj_id, cfg, set_tuple):
set_tuple is a tuple of the pathspec and the value set_tuple is a tuple of the pathspec and the value
""" """
import json import json
from config import logger from amanuensis.config import logger
pathspec, value = set_tuple pathspec, value = set_tuple
if not pathspec: if not pathspec:
logger.error("Path must be non-empty") logger.error("Path must be non-empty")

View File

@ -1,4 +1,4 @@
from cli.helpers import ( from amanuensis.cli.helpers import (
add_argument, no_argument, requires_lexicon, requires_username, add_argument, no_argument, requires_lexicon, requires_username,
config_get, config_set, CONFIG_GET_ROOT_VALUE) config_get, config_set, CONFIG_GET_ROOT_VALUE)
@ -17,9 +17,9 @@ 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.
""" """
# Module imports # Module imports
from config import logger from amanuensis.config import logger
from lexicon.manage import valid_name, create_lexicon from amanuensis.lexicon.manage import valid_name, create_lexicon
from user import UserModel from amanuensis.user import UserModel
# Verify arguments # Verify arguments
if not valid_name(args.lexicon): if not valid_name(args.lexicon):
@ -42,9 +42,9 @@ def command_delete(args):
Delete a lexicon and optionally its data Delete a lexicon and optionally its data
""" """
# Module imports # Module imports
from config import logger from amanuensis.config import logger
from lexicon import LexiconModel from amanuensis.lexicon import LexiconModel
from lexicon.manage import delete_lexicon from amanuensis.lexicon.manage import delete_lexicon
# Verify arguments # Verify arguments
lex = LexiconModel.by(name=args.lexicon) lex = LexiconModel.by(name=args.lexicon)
@ -63,7 +63,7 @@ def command_list(args):
List all lexicons and their statuses List all lexicons and their statuses
""" """
# Module imports # Module imports
from lexicon.manage import get_all_lexicons from amanuensis.lexicon.manage import get_all_lexicons
# Internal call # Internal call
lexicons = get_all_lexicons() lexicons = get_all_lexicons()
@ -91,8 +91,8 @@ def command_config(args):
Interact with a lexicon's config Interact with a lexicon's config
""" """
# Module imports # Module imports
from config import logger, json_ro, json_rw from amanuensis.config import logger, json_ro, json_rw
from lexicon import LexiconModel from amanuensis.lexicon import LexiconModel
# Verify arguments # Verify arguments
if args.get and args.set: if args.get and args.set:
@ -123,10 +123,10 @@ def command_player_add(args):
Add a player to a lexicon Add a player to a lexicon
""" """
# Module imports # Module imports
from config import logger from amanuensis.config import logger
from lexicon import LexiconModel from amanuensis.lexicon import LexiconModel
from lexicon.manage import add_player from amanuensis.lexicon.manage import add_player
from user import UserModel from amanuensis.user import UserModel
# Verify arguments # Verify arguments
u = UserModel.by(name=args.username) u = UserModel.by(name=args.username)
@ -152,10 +152,10 @@ def command_player_remove(args):
they control but does not delete any character data. they control but does not delete any character data.
""" """
# Module imports # Module imports
from config import logger from amanuensis.config import logger
from lexicon import LexiconModel from amanuensis.lexicon import LexiconModel
from lexicon.manage import remove_player from amanuensis.lexicon.manage import remove_player
from user import UserModel from amanuensis.user import UserModel
# Verify arguments # Verify arguments
u = UserModel.by(name=args.username) u = UserModel.by(name=args.username)
@ -181,8 +181,8 @@ def command_player_list(args):
""" """
import json import json
# Module imports # Module imports
from lexicon import LexiconModel from amanuensis.lexicon import LexiconModel
from user import UserModel from amanuensis.user import UserModel
# Verify arguments # Verify arguments
lex = LexiconModel.by(name=args.lexicon) lex = LexiconModel.by(name=args.lexicon)
@ -209,10 +209,10 @@ def command_char_create(args):
The specified player will be set as the character's player. The specified player will be set as the character's player.
""" """
# Module imports # Module imports
from config import logger from amanuensis.config import logger
from lexicon import LexiconModel from amanuensis.lexicon import LexiconModel
from lexicon.manage import add_character from amanuensis.lexicon.manage import add_character
from user import UserModel from amanuensis.user import UserModel
# Verify arguments # Verify arguments
u = UserModel.by(name=args.username) u = UserModel.by(name=args.username)
@ -223,7 +223,7 @@ def command_char_create(args):
if lex is None: if lex is None:
logger.error("Could not find lexicon '{}'".format(args.lexicon)) logger.error("Could not find lexicon '{}'".format(args.lexicon))
return -1 return -1
# u in lx # u in lx TODO
# Internal call # Internal call
add_character(lex, u, {"name": args.charname}) add_character(lex, u, {"name": args.charname})
@ -239,9 +239,9 @@ def command_char_delete(args):
they have contributed rather than deleting it. they have contributed rather than deleting it.
""" """
# Module imports # Module imports
from config import logger from amanuensis.config import logger
from lexicon import LexiconModel from amanuensis.lexicon import LexiconModel
from lexicon.manage import delete_character from amanuensis.lexicon.manage import delete_character
# Verify arguments # Verify arguments
lex = LexiconModel.by(name=args.lexicon) lex = LexiconModel.by(name=args.lexicon)
@ -259,7 +259,7 @@ def command_char_list(args):
""" """
import json import json
# Module imports # Module imports
from lexicon import LexiconModel from amanuensis.lexicon import LexiconModel
# Verify arguments # Verify arguments
lex = LexiconModel.by(name=args.lexicon) lex = LexiconModel.by(name=args.lexicon)
@ -291,4 +291,7 @@ def command_publish_turn(args):
The --force flag bypasses the publish.quorum and publish.block_on_ready The --force flag bypasses the publish.quorum and publish.block_on_ready
settings. settings.
""" """
# Module imports
from amanuensis.config import logger
raise NotImplementedError() # TODO raise NotImplementedError() # TODO

View File

@ -1,6 +1,6 @@
import os import os
from cli.helpers import ( from amanuensis.cli.helpers import (
add_argument, no_argument, add_argument, no_argument,
config_get, config_set, CONFIG_GET_ROOT_VALUE) config_get, config_set, CONFIG_GET_ROOT_VALUE)
@ -20,7 +20,7 @@ def command_init(args):
from the indexes will be deleted, and stale index entries will be removed. from the indexes will be deleted, and stale index entries will be removed.
""" """
# Module imports # Module imports
from config.init import create_config_dir from amanuensis.config.init import create_config_dir
# Verify arguments # Verify arguments
if args.refresh and not os.path.isdir(args.config_dir): if args.refresh and not os.path.isdir(args.config_dir):
@ -39,13 +39,13 @@ def command_generate_secret(args):
been generated. been generated.
""" """
import os import os
# Module imports
import config from amanuensis.config import json_rw, logger
secret_key = os.urandom(32) secret_key = os.urandom(32)
with config.json_rw("config.json") as cfg: with json_rw("config.json") as cfg:
cfg['secret_key'] = secret_key.hex() cfg['secret_key'] = secret_key.hex()
config.logger.info("Regenerated Flask secret key") logger.info("Regenerated Flask secret key")
@add_argument("-a", "--address", default="127.0.0.1") @add_argument("-a", "--address", default="127.0.0.1")
@ -57,13 +57,13 @@ def command_run(args):
The default Flask server is not secure, and should The default Flask server is not secure, and should
only be used for development. only be used for development.
""" """
import server from amanuensis.server import app
import config from amanuensis.config import get, logger
if config.get("secret_key") is None: if get("secret_key") is None:
config.logger.error("Can't run server without a secret_key. Run generate-secret first") logger.error("Can't run server without a secret_key. Run generate-secret first")
return -1 return -1
server.app.run(host=args.address, port=args.port) app.run(host=args.address, port=args.port)
@add_argument("--get", metavar="PATHSPEC", dest="get", @add_argument("--get", metavar="PATHSPEC", dest="get",
@ -78,16 +78,17 @@ def command_config(args):
a dot-separated sequence of keys. a dot-separated sequence of keys.
""" """
import json import json
import config # Module imports
from amanuensis.config import json_ro, json_rw, logger
if args.get and args.set: if args.get and args.set:
config.logger.error("Specify one of --get and --set") logger.error("Specify one of --get and --set")
return -1 return -1
if args.get: if args.get:
with config.json_ro('config.json') as cfg: with json_ro('config.json') as cfg:
config_get(cfg, args.get) config_get(cfg, args.get)
if args.set: if args.set:
with config.json_rw('config.json') as cfg: with json_rw('config.json') as cfg:
config_set("config", cfg, args.set) config_set("config", cfg, args.set)

View File

@ -1,6 +1,6 @@
import shutil import shutil
from cli.helpers import ( from amanuensis.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)
@ -12,26 +12,26 @@ def command_create(args):
Create a user Create a user
""" """
import json import json
# Module imports
import user from amanuensis.config import logger, json_ro
import config from amanuensis.user import UserModel, valid_username, valid_email, create_user
# Verify or query parameters # Verify or query parameters
if not user.valid_username(args.username): if not valid_username(args.username):
config.logger.error("Invalid username: usernames may only contain alphanumeric characters, dashes, and underscores") logger.error("Invalid username: usernames may only contain alphanumeric characters, dashes, and underscores")
return -1 return -1
if user.UserModel.by(name=args.username) is not None: if UserModel.by(name=args.username) is not None:
config.logger.error("Invalid username: username is already taken") 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 user.valid_email(args.email): if not valid_email(args.email):
config.logger.error("Invalid email") logger.error("Invalid email")
return -1 return -1
# Create user # Create user
new_user, tmp_pw = user.create_user(args.username, args.displayname, args.email) new_user, tmp_pw = create_user(args.username, args.displayname, args.email)
with config.json_ro(new_user.config_path) as js: with json_ro(new_user.config_path) as js:
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))
@ -41,31 +41,33 @@ def command_delete(args):
Delete a user Delete a user
""" """
import os import os
# Module imports
from amanuensis.config import logger, prepend
import config user_path = prepend('user', args.id)
user_path = config.prepend('user', args.id)
if not os.path.isdir(user_path): if not os.path.isdir(user_path):
config.logger.error("No user with that id") logger.error("No user with that id")
return -1 return -1
else: else:
shutil.rmtree(user_path) shutil.rmtree(user_path)
with config.json_rw('user', 'index.json') as j: with json_rw('user', 'index.json') as j:
if args.id in j: if args.id in j:
del j[uid] del j[uid]
# TODO
@no_argument @no_argument
def command_list(args): def command_list(args):
"""List all users""" """List all users"""
import os import os
# Module imports
from amanuensis.config import prepend, json_ro
import config user_dirs = os.listdir(prepend('user'))
user_dirs = os.listdir(config.prepend('user'))
users = [] users = []
for uid in user_dirs: for uid in user_dirs:
if uid == "index.json": continue if uid == "index.json": continue
with config.json_ro('user', uid, 'config.json') as user: with json_ro('user', uid, 'config.json') as user:
users.append(user) users.append(user)
users.sort(key=lambda u: u['username']) users.sort(key=lambda u: u['username'])
for user in users: for user in users:
@ -83,24 +85,25 @@ def command_config(args):
Interact with a user's config Interact with a user's config
""" """
import json import json
import config # Module imports
from user import UserModel from amanuensis.config import logger, json_ro, json_rw
from amanuensis.user import UserModel
if args.get and args.set: if args.get and args.set:
config.logger.error("Specify one of --get and --set") logger.error("Specify one of --get and --set")
return -1 return -1
u = UserModel.by(name=args.username) u = UserModel.by(name=args.username)
if not u: if not u:
config.logger.error("User not found") logger.error("User not found")
return -1 return -1
if args.get: if args.get:
with config.json_ro('user', u.id, 'config.json') as cfg: with 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', u.id, 'config.json') as cfg: with json_rw('user', u.id, 'config.json') as cfg:
config_set(u.id, cfg, args.set) config_set(u.id, cfg, args.set)
@add_argument("--username", help="The user to change password for") @add_argument("--username", help="The user to change password for")
@ -110,15 +113,15 @@ def command_passwd(args):
""" """
import getpass import getpass
import os import os
# Module imports
import config from amanuensis.config import logger
from user import UserModel from amanuensis.user import UserModel
if not args.username: if not args.username:
args.username = input("Username: ") args.username = input("Username: ")
u = UserModel.by(name=args.username) u = UserModel.by(name=args.username)
if u is None: if u is None:
config.logger.error("No user with username '{}'".format(args.username)) logger.error("No user with username '{}'".format(args.username))
return -1 return -1
pw = getpass.getpass("Password: ") pw = getpass.getpass("Password: ")
u.set_password(pw) u.set_password(pw)

View File

@ -4,9 +4,9 @@ import logging
import os import os
# Module imports # Module imports
from errors import MissingConfigError, MalformedConfigError from amanuensis.errors import MissingConfigError, MalformedConfigError
import config.init import amanuensis.config.init
import config.loader import amanuensis.config.loader
# Environment variable name constants # Environment variable name constants
@ -31,10 +31,10 @@ def init_config(args):
""" """
global CONFIG_DIR, GLOBAL_CONFIG, logger global CONFIG_DIR, GLOBAL_CONFIG, logger
CONFIG_DIR = args.config_dir CONFIG_DIR = args.config_dir
config.init.verify_config_dir(CONFIG_DIR) amanuensis.config.init.verify_config_dir(CONFIG_DIR)
with config.loader.json_ro(os.path.join(CONFIG_DIR, "config.json")) as cfg: with amanuensis.config.loader.json_ro(os.path.join(CONFIG_DIR, "config.json")) as cfg:
GLOBAL_CONFIG = cfg GLOBAL_CONFIG = cfg
config.init.init_logging(args, GLOBAL_CONFIG['logging']) amanuensis.config.init.init_logging(args, GLOBAL_CONFIG['logging'])
logger = logging.getLogger("amanuensis") logger = logging.getLogger("amanuensis")
def get(key): def get(key):
@ -47,13 +47,13 @@ def prepend(*path):
return joined return joined
def open_sh(*path, mode): def open_sh(*path, mode):
return config.loader.open_sh(prepend(*path), mode) return amanuensis.config.loader.open_sh(prepend(*path), mode)
def open_ex(*path, mode): def open_ex(*path, mode):
return config.loader.open_ex(prepend(*path), mode) return amanuensis.config.loader.open_ex(prepend(*path), mode)
def json_ro(*path): def json_ro(*path):
return config.loader.json_ro(prepend(*path)) return amanuensis.config.loader.json_ro(prepend(*path))
def json_rw(*path): def json_rw(*path):
return config.loader.json_rw(prepend(*path)) return amanuensis.config.loader.json_rw(prepend(*path))

View File

@ -6,10 +6,10 @@ import os
import shutil import shutil
# Module imports # Module imports
from errors import MissingConfigError, MalformedConfigError from amanuensis.errors import MissingConfigError, MalformedConfigError
import config from amanuensis.config.loader import json_ro, json_rw
from config.loader import json_ro from amanuensis.resources import get_stream
import resources
def create_config_dir(config_dir, refresh=False): def create_config_dir(config_dir, refresh=False):
""" """
@ -18,23 +18,24 @@ def create_config_dir(config_dir, refresh=False):
from collections import OrderedDict from collections import OrderedDict
import fcntl import fcntl
path = config.prepend def prepend(*path):
joined = os.path.join(*path)
if not joined.startswith(config_dir):
joined = os.path.join(config_dir, joined)
return joined
# Create the directory if it doesn't exist. # Create the directory if it doesn't exist.
if not os.path.isdir(config_dir): if not os.path.isdir(config_dir):
os.mkdir(config_dir) os.mkdir(config_dir)
# Initialize the config dir without verification
config.CONFIG_DIR = config_dir
# The directory should be empty if we're not updating an existing one. # The directory should be empty if we're not updating an existing one.
if len(os.listdir(config_dir)) > 0 and not refresh: if len(os.listdir(config_dir)) > 0 and not refresh:
print("Directory {} is not empty".format(config_dir)) print("Directory {} is not empty".format(config_dir))
return -1 return -1
# Update or create global config. # Update or create global config.
def_cfg = resources.get_stream("global.json") def_cfg = get_stream("global.json")
global_config_path = path("config.json") global_config_path = prepend("config.json")
if refresh and os.path.isfile(global_config_path): if refresh and os.path.isfile(global_config_path):
# We need to write an entirely different ordereddict to the config # We need to write an entirely different ordereddict to the config
# file, so we mimic the config.loader functionality manually. # file, so we mimic the config.loader functionality manually.
@ -56,34 +57,34 @@ def create_config_dir(config_dir, refresh=False):
cfg_file.truncate() cfg_file.truncate()
fcntl.lockf(cfg_file, fcntl.LOCK_UN) fcntl.lockf(cfg_file, fcntl.LOCK_UN)
else: else:
with open(path("config.json"), 'wb') as f: with open(prepend("config.json"), 'wb') as f:
f.write(def_cfg.read()) f.write(def_cfg.read())
# Ensure pidfile exists. # Ensure pidfile exists.
if not os.path.isfile(path("pid")): if not os.path.isfile(prepend("pid")):
with open(path("pid"), 'w') as f: with open(prepend("pid"), 'w') as f:
f.write(str(os.getpid())) f.write(str(os.getpid()))
# Ensure lexicon subdir exists. # Ensure lexicon subdir exists.
if not os.path.isdir(path("lexicon")): if not os.path.isdir(prepend("lexicon")):
os.mkdir(path("lexicon")) os.mkdir(prepend("lexicon"))
if not os.path.isfile(path("lexicon", "index.json")): if not os.path.isfile(prepend("lexicon", "index.json")):
with open(path("lexicon", "index.json"), 'w') as f: with open(prepend("lexicon", "index.json"), 'w') as f:
json.dump({}, f) json.dump({}, f)
# Ensure user subdir exists. # Ensure user subdir exists.
if not os.path.isdir(path("user")): if not os.path.isdir(prepend("user")):
os.mkdir(path("user")) os.mkdir(prepend("user"))
if not os.path.isfile(path('user', 'index.json')): if not os.path.isfile(prepend('user', 'index.json')):
with open(path('user', 'index.json'), 'w') as f: with open(prepend('user', 'index.json'), 'w') as f:
json.dump({}, f) json.dump({}, f)
if refresh: if refresh:
for dir_name in ('lexicon', 'user'): for dir_name in ('lexicon', 'user'):
# Clean up unindexed folders # Clean up unindexed folders
with config.json_ro(dir_name, 'index.json') as index: with json_ro(prepend(dir_name, 'index.json')) as index:
known = list(index.values()) known = list(index.values())
entries = os.listdir(path(dir_name)) entries = os.listdir(prepend(dir_name))
for dir_entry in entries: for dir_entry in entries:
if dir_entry == "index.json": if dir_entry == "index.json":
continue continue
@ -91,12 +92,12 @@ def create_config_dir(config_dir, refresh=False):
continue continue
print("Removing unindexed folder: '{}/{}'" print("Removing unindexed folder: '{}/{}'"
.format(dir_name, dir_entry)) .format(dir_name, dir_entry))
shutil.rmtree(path(dir_name, dir_entry)) shutil.rmtree(prepend(dir_name, dir_entry))
# Remove orphaned index listings # Remove orphaned index listings
with config.json_rw(dir_name, 'index.json') as index: with json_rw(prepend(dir_name, 'index.json')) as index:
for name, entry in index.items(): for name, entry in index.items():
if not os.path.isdir(path(dir_name, entry)): if not os.path.isdir(prepend(dir_name, entry)):
print("Removing stale {} index entry '{}: {}'" print("Removing stale {} index entry '{}: {}'"
.format(dir_name, name, entry)) .format(dir_name, name, entry))
del index[name] del index[name]
@ -115,7 +116,7 @@ def verify_config_dir(config_dir):
if not os.path.isfile(global_config_path): if not os.path.isfile(global_config_path):
raise MissingConfigError("Config directory missing global config file: {}".format(config_dir)) raise MissingConfigError("Config directory missing global config file: {}".format(config_dir))
# Check that global config file has all the default settings # Check that global config file has all the default settings
def_cfg_s = resources.get_stream("global.json") def_cfg_s = get_stream("global.json")
def_cfg = json.load(def_cfg_s) def_cfg = json.load(def_cfg_s)
with json_ro(global_config_path) as global_config_file: with json_ro(global_config_path) as global_config_file:
for key in def_cfg.keys(): for key in def_cfg.keys():

View File

@ -5,7 +5,7 @@ import json
import os import os
# Module imports # Module imports
from errors import ReadOnlyError from amanuensis.errors import ReadOnlyError
class AttrOrderedDict(OrderedDict): class AttrOrderedDict(OrderedDict):

View File

@ -1,8 +1,8 @@
import os import os
import time import time
from errors import InternalMisuseError, IndexMismatchError, MissingConfigError from amanuensis.errors import InternalMisuseError, IndexMismatchError, MissingConfigError
import config from amanuensis.config import prepend, json_ro, json_rw
class LexiconModel(): class LexiconModel():
def by(lid=None, name=None): def by(lid=None, name=None):
@ -18,24 +18,24 @@ class LexiconModel():
if not lid and not name: if not lid and not name:
raise ValueError("One of lid or name must be not None") raise ValueError("One of lid or name must be not None")
if not lid: if not lid:
with config.json_ro('lexicon', 'index.json') as index: with json_ro('lexicon', 'index.json') as index:
lid = index.get(name) lid = index.get(name)
if not lid: if not lid:
return None return None
if not os.path.isdir(config.prepend('lexicon', lid)): if not os.path.isdir(prepend('lexicon', lid)):
raise IndexMismatchError("lexicon={} lid={}".format(name, lid)) raise IndexMismatchError("lexicon={} lid={}".format(name, lid))
if not os.path.isfile(config.prepend('lexicon', lid, 'config.json')): if not os.path.isfile(prepend('lexicon', lid, 'config.json')):
raise MissingConfigError("lid={}".format(lid)) raise MissingConfigError("lid={}".format(lid))
return LexiconModel(lid) return LexiconModel(lid)
def __init__(self, lid): def __init__(self, lid):
if not os.path.isdir(config.prepend('lexicon', lid)): if not os.path.isdir(prepend('lexicon', lid)):
raise ValueError("No lexicon with lid {}".format(lid)) raise ValueError("No lexicon with lid {}".format(lid))
if not os.path.isfile(config.prepend('lexicon', lid, 'config.json')): if not os.path.isfile(prepend('lexicon', lid, 'config.json')):
raise FileNotFoundError("Lexicon {} missing config.json".format(lid)) raise FileNotFoundError("Lexicon {} missing config.json".format(lid))
self.id = str(lid) self.id = str(lid)
self.config_path = config.prepend('lexicon', lid, 'config.json') self.config_path = prepend('lexicon', lid, 'config.json')
with config.json_ro(self.config_path) as j: with json_ro(self.config_path) as j:
self.config = j self.config = j
def __getattr__(self, key): def __getattr__(self, key):
@ -45,7 +45,7 @@ class LexiconModel():
def log(self, message): def log(self, message):
now = int(time.time()) now = int(time.time())
with config.json_rw(self.config_path) as j: with json_rw(self.config_path) as j:
j['log'].append([now, message]) j['log'].append([now, message])
def status(self): def status(self):

View File

@ -9,10 +9,10 @@ import shutil
import time import time
import uuid import uuid
import config from amanuensis.config import prepend, json_rw, json_ro, logger
from config.loader import AttrOrderedDict from amanuensis.config.loader import AttrOrderedDict
import lexicon from amanuensis.lexicon import LexiconModel
import resources from amanuensis.resources import get_stream
def valid_name(name): def valid_name(name):
""" """
@ -34,28 +34,28 @@ def create_lexicon(name, editor):
# Create the lexicon directory and initialize it with a blank lexicon # Create the lexicon directory and initialize it with a blank lexicon
lid = uuid.uuid4().hex lid = uuid.uuid4().hex
lex_dir = config.prepend("lexicon", lid) lex_dir = prepend("lexicon", lid)
os.mkdir(lex_dir) os.mkdir(lex_dir)
with resources.get_stream("lexicon.json") as s: with get_stream("lexicon.json") as s:
with open(config.prepend(lex_dir, 'config.json'), 'wb') as f: with open(prepend(lex_dir, 'config.json'), 'wb') as f:
f.write(s.read()) f.write(s.read())
# Fill out the new lexicon # Fill out the new lexicon
with config.json_rw(lex_dir, 'config.json') as cfg: with json_rw(lex_dir, 'config.json') as cfg:
cfg['lid'] = lid cfg['lid'] = lid
cfg['name'] = name cfg['name'] = name
cfg['editor'] = editor.uid cfg['editor'] = editor.uid
cfg['time']['created'] = int(time.time()) cfg['time']['created'] = int(time.time())
# Update the index with the new lexicon # Update the index with the new lexicon
with config.json_rw('lexicon', 'index.json') as index: with json_rw('lexicon', 'index.json') as index:
index[name] = lid index[name] = lid
# Load the Lexicon and log creation # Load the Lexicon and log creation
l = lexicon.LexiconModel(lid) l = LexiconModel(lid)
l.log("Lexicon created") l.log("Lexicon created")
config.logger.info("Created Lexicon {0.name}, ed. {1.displayname} ({0.id})".format( logger.info("Created Lexicon {0.name}, ed. {1.displayname} ({0.id})".format(
l, editor)) l, editor))
# Add the editor # Add the editor
@ -82,7 +82,7 @@ def delete_lexicon(lex, purge=False):
raise ValueError("Invalid lexicon: '{}'".format(lex)) raise ValueError("Invalid lexicon: '{}'".format(lex))
# Delete the lexicon from the index # Delete the lexicon from the index
with config.json_rw('lexicon', 'index.json') as j: with json_rw('lexicon', 'index.json') as j:
if lex.id in j: if lex.id in j:
del j[lex.id] del j[lex.id]
@ -91,7 +91,7 @@ def delete_lexicon(lex, purge=False):
raise NotImplementedError() raise NotImplementedError()
# Delete the lexicon config # Delete the lexicon config
lex_path = config.prepend('lexicon', lex.id) lex_path = prepend('lexicon', lex.id)
shutil.rmtree(lex_path) shutil.rmtree(lex_path)
@ -100,11 +100,11 @@ def get_all_lexicons():
Loads each lexicon in the lexicon index Loads each lexicon in the lexicon index
""" """
# Get all the lexicon ids in the index # Get all the lexicon ids in the index
with config.json_ro('lexicon', 'index.json') as index: with json_ro('lexicon', 'index.json') as index:
lids = list(index.values()) lids = list(index.values())
# Load all of the lexicons # Load all of the lexicons
lexes = list(map(lambda id: lexicon.LexiconModel.by(lid=id), lids)) lexes = list(map(lambda id: LexiconModel.by(lid=id), lids))
return lexes return lexes
@ -145,7 +145,7 @@ def add_player(lex, player):
raise ValueError("Invalid player: '{}'".format(player)) raise ValueError("Invalid player: '{}'".format(player))
# Idempotently add player # Idempotently add player
with config.json_rw(lex.config_path) as cfg: with json_rw(lex.config_path) as cfg:
if player.id not in cfg.join.joined: if player.id not in cfg.join.joined:
cfg.join.joined.append(player.id) cfg.join.joined.append(player.id)
# Log to the lexicon's log # Log to the lexicon's log
@ -165,7 +165,7 @@ def remove_player(lex, player):
raise ValueError("Can't remove the editor '{}' from lexicon '{}'".format(player.username, lex.name)) raise ValueError("Can't remove the editor '{}' from lexicon '{}'".format(player.username, lex.name))
# Idempotently remove player # Idempotently remove player
with config.json_rw(lex.config_path) as cfg: with json_rw(lex.config_path) as cfg:
if player.id in cfg.join.joined: if player.id in cfg.join.joined:
cfg.join.joined.remove(player.id) cfg.join.joined.remove(player.id)
@ -190,7 +190,7 @@ def add_character(lex, player, charinfo={}):
raise ValueError("Duplicate character name: '{}'".format(charinfo)) raise ValueError("Duplicate character name: '{}'".format(charinfo))
# Load the character template # Load the character template
with resources.get_stream('character.json') as template: with get_stream('character.json') as template:
character = json.load(template, object_pairs_hook=AttrOrderedDict) character = json.load(template, object_pairs_hook=AttrOrderedDict)
# Fill out the character's information # Fill out the character's information
@ -200,7 +200,7 @@ def add_character(lex, player, charinfo={}):
character.signature = charinfo.get("signature") or ("~" + character.name) character.signature = charinfo.get("signature") or ("~" + character.name)
# Add the character to the lexicon # Add the character to the lexicon
with config.json_rw(lex.config_path) as cfg: with json_rw(lex.config_path) as cfg:
cfg.character.new(character.cid, character) cfg.character.new(character.cid, character)
@ -221,5 +221,5 @@ def delete_character(lex, charname):
char = matches[0] char = matches[0]
# Remove character from character list # Remove character from character list
with config.json_rw(lex.config_path) as cfg: with json_rw(lex.config_path) as cfg:
del cfg.character[char.cid] del cfg.character[char.cid]

View File

@ -3,15 +3,15 @@ import os
from flask import Flask, render_template from flask import Flask, render_template
from flask_login import LoginManager from flask_login import LoginManager
import config from amanuensis.config import get
from server.auth import get_bp as get_auth_bp from amanuensis.server.auth import get_bp as get_auth_bp
from server.home import get_bp as get_home_bp from amanuensis.server.home import get_bp as get_home_bp
from server.lexicon import get_bp as get_lex_bp from amanuensis.server.lexicon import get_bp as get_lex_bp
# Flask app init # Flask app init
static_root = os.path.abspath(config.get("static_root")) static_root = os.path.abspath(get("static_root"))
app = Flask(__name__, template_folder="../templates", static_folder=static_root) app = Flask(__name__, template_folder="../templates", static_folder=static_root)
app.secret_key = bytes.fromhex(config.get('secret_key')) app.secret_key = bytes.fromhex(get('secret_key'))
app.jinja_options['trim_blocks'] = True app.jinja_options['trim_blocks'] = True
app.jinja_options['lstrip_blocks'] = True app.jinja_options['lstrip_blocks'] = True

View File

@ -4,8 +4,8 @@ from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired 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 from amanuensis.config import logger
from user import UserModel from amanuensis.user import UserModel
class LoginForm(FlaskForm): class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()]) username = StringField('Username', validators=[DataRequired()])
@ -30,7 +30,7 @@ def get_bp(login_manager):
if u is not None and u.check_password(form.password.data): if u is not None and 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( 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")

View File

@ -6,9 +6,7 @@ from flask_login import login_required, current_user
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import TextAreaField, SubmitField, StringField from wtforms import TextAreaField, SubmitField, StringField
import config from amanuensis.config import json_ro
import user
import lexicon
class AdminDashboardForm(FlaskForm): class AdminDashboardForm(FlaskForm):
lexiconName = StringField("Lexicon name") lexiconName = StringField("Lexicon name")
@ -42,10 +40,10 @@ def get_bp():
if form.lexiconName.data: if form.lexiconName.data:
lid = None lid = None
with config.json_ro('lexicon', 'index.json') as index: with json_ro('lexicon', 'index.json') as index:
lid = index.get(form.lexiconName.data) lid = index.get(form.lexiconName.data)
if lid is not None: if lid is not None:
with config.json_ro('lexicon', lid, 'config.json') as cfg: with json_ro('lexicon', lid, 'config.json') as cfg:
form.configText.data = json.dumps(cfg, indent=2) form.configText.data = json.dumps(cfg, indent=2)
form.lexiconName.data = "" form.lexiconName.data = ""
elif form.configText.data: elif form.configText.data:

View File

@ -6,16 +6,16 @@ from flask_login import login_required, current_user
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import TextAreaField, SubmitField from wtforms import TextAreaField, SubmitField
import config from amanuensis.config import json_ro, open_ex
from config.loader import ReadOnlyOrderedDict from amanuensis.config.loader import ReadOnlyOrderedDict
import user from amanuensis.lexicon import LexiconModel
import lexicon from amanuensis.user import UserModel
def lexicon_param(route): def lexicon_param(route):
@wraps(route) @wraps(route)
def with_lexicon(name): def with_lexicon(name):
g.lexicon = lexicon.LexiconModel.by(name=name) g.lexicon = LexiconModel.by(name=name)
if g.lexicon is None: if g.lexicon is None:
flash("Couldn't find a lexicon with the name '{}'".format(name)) flash("Couldn't find a lexicon with the name '{}'".format(name))
return redirect(url_for("home.home")) return redirect(url_for("home.home"))
@ -63,7 +63,7 @@ def get_bp():
# Load the config for the lexicon on load # Load the config for the lexicon on load
if not form.is_submitted(): if not form.is_submitted():
with config.json_ro(g.lexicon.config_path) as cfg: with json_ro(g.lexicon.config_path) as cfg:
form.configText.data = json.dumps(cfg, indent=2) form.configText.data = json.dumps(cfg, indent=2)
return render_template("lexicon/session_edit.html", form=form) return render_template("lexicon/session_edit.html", form=form)
@ -78,7 +78,7 @@ def get_bp():
# TODO # TODO
# Write the new config # Write the new config
form.submit.submitted = False form.submit.submitted = False
with config.open_ex(g.lexicon.config_path, mode='w') as f: with open_ex(g.lexicon.config_path, mode='w') as f:
json.dump(cfg, f, indent='\t') json.dump(cfg, f, indent='\t')
flash("Config updated") flash("Config updated")
return redirect(url_for('lexicon.session_edit', name=name)) return redirect(url_for('lexicon.session_edit', name=name))

View File

@ -6,10 +6,10 @@ 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 from amanuensis.errors import InternalMisuseError, MissingConfigError, IndexMismatchError
import config from amanuensis.config import prepend, json_ro, json_rw
import resources from amanuensis.resources import get_stream
import lexicon.manage from amanuensis.lexicon.manage import get_all_lexicons
class UserModel(UserMixin): class UserModel(UserMixin):
@staticmethod @staticmethod
@ -26,21 +26,21 @@ class UserModel(UserMixin):
if not uid and not name: if not uid and not name:
raise ValueError("One of uid or name must be not None") raise ValueError("One of uid or name must be not None")
if not uid: if not uid:
with config.json_ro('user', 'index.json') as index: with json_ro('user', 'index.json') as index:
uid = index.get(name) uid = index.get(name)
if not uid: if not uid:
return None return None
if not os.path.isdir(config.prepend('user', uid)): if not os.path.isdir(prepend('user', uid)):
raise IndexMismatchError("username={} uid={}".format(name, uid)) raise IndexMismatchError("username={} uid={}".format(name, uid))
if not os.path.isfile(config.prepend('user', uid, 'config.json')): if not os.path.isfile(prepend('user', uid, 'config.json')):
raise MissingConfigError("uid={}".format(uid)) raise MissingConfigError("uid={}".format(uid))
return UserModel(uid) return UserModel(uid)
def __init__(self, uid): def __init__(self, uid):
"""User model initializer, assume all checks were done by by()""" """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 = prepend('user', uid, 'config.json')
with config.json_ro(self.config_path) as j: with json_ro(self.config_path) as j:
self.config = j self.config = j
def __getattr__(self, key): def __getattr__(self, key):
@ -50,17 +50,17 @@ class UserModel(UserMixin):
def set_password(self, pw): def set_password(self, pw):
h = generate_password_hash(pw) h = generate_password_hash(pw)
with config.json_rw(self.config_path) as j: with json_rw(self.config_path) as j:
j['password'] = h j['password'] = h
def check_password(self, pw): def check_password(self, pw):
with config.json_ro(self.config_path) as j: with json_ro(self.config_path) as j:
return check_password_hash(j['password'], pw) return check_password_hash(j['password'], pw)
def lexicons_in(self): def lexicons_in(self):
return [ return [
lex lex
for lex in lexicon.manage.get_all_lexicons() for lex in get_all_lexicons()
if self.id in lex.join.joined if self.id in lex.join.joined
] ]
@ -87,14 +87,14 @@ def create_user(username, displayname, email):
# Create the user directory and initialize it with a blank user # Create the user directory and initialize it with a blank user
uid = uuid.uuid4().hex uid = uuid.uuid4().hex
user_dir = config.prepend("user", uid) user_dir = prepend("user", uid)
os.mkdir(user_dir) os.mkdir(user_dir)
with resources.get_stream("user.json") as s: with get_stream("user.json") as s:
with open(config.prepend(user_dir, 'config.json'), 'wb') as f: with open(prepend(user_dir, 'config.json'), 'wb') as f:
f.write(s.read()) f.write(s.read())
# Fill out the new user # Fill out the new user
with config.json_rw(user_dir, 'config.json') as cfg: with json_rw(user_dir, 'config.json') as cfg:
cfg.uid = uid cfg.uid = uid
cfg.username = username cfg.username = username
cfg.displayname = displayname cfg.displayname = displayname
@ -102,7 +102,7 @@ def create_user(username, displayname, email):
cfg.created = int(time.time()) cfg.created = int(time.time())
# Update the index with the new user # Update the index with the new user
with config.json_rw('user', 'index.json') as index: with json_rw('user', 'index.json') as index:
index[username] = uid index[username] = uid
# Set a temporary password # Set a temporary password