Compare commits
No commits in common. "e097917633260623a7190159ec25a92df9bcba71" and "324788f9a15fd48e9f9a9e191594c5d51b834f31" have entirely different histories.
e097917633
...
324788f9a1
|
@ -3,8 +3,6 @@ import logging
|
|||
import logging.config
|
||||
|
||||
import amanuensis.cli.admin
|
||||
import amanuensis.cli.lexicon
|
||||
import amanuensis.cli.user
|
||||
|
||||
|
||||
LOGGING_CONFIG = {
|
||||
|
@ -16,7 +14,7 @@ LOGGING_CONFIG = {
|
|||
},
|
||||
"fmt_detailed": {
|
||||
"validate": True,
|
||||
"format": "%(asctime)s %(levelname)s %(message)s",
|
||||
"format": "%(asctime)s %(levelname)s %(message)s"
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
|
@ -29,8 +27,8 @@ LOGGING_CONFIG = {
|
|||
"loggers": {
|
||||
__name__: {
|
||||
"level": "DEBUG",
|
||||
"handlers": ["hnd_stderr"],
|
||||
},
|
||||
"handlers": ["hnd_stderr"]
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -69,7 +67,7 @@ def add_subcommand(subparsers, module) -> None:
|
|||
|
||||
def init_logger(args):
|
||||
"""Set up logging based on verbosity args"""
|
||||
if args.verbose:
|
||||
if (args.verbose):
|
||||
handler = LOGGING_CONFIG["handlers"]["hnd_stderr"]
|
||||
handler["formatter"] = "fmt_detailed"
|
||||
handler["level"] = "DEBUG"
|
||||
|
@ -89,8 +87,6 @@ def main():
|
|||
# Add commands from cli submodules
|
||||
subparsers = parser.add_subparsers(metavar="COMMAND")
|
||||
add_subcommand(subparsers, amanuensis.cli.admin)
|
||||
add_subcommand(subparsers, amanuensis.cli.lexicon)
|
||||
add_subcommand(subparsers, amanuensis.cli.user)
|
||||
|
||||
# Parse args and execute the desired action
|
||||
args = parser.parse_args()
|
||||
|
|
|
@ -14,9 +14,7 @@ COMMAND_HELP = "Interact with Amanuensis."
|
|||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@add_argument(
|
||||
"path", metavar="DB_PATH", help="Path to where the database should be created"
|
||||
)
|
||||
@add_argument("path", metavar="DB_PATH", help="Path to where the database should be created")
|
||||
@add_argument("--force", "-f", action="store_true", help="Overwrite existing database")
|
||||
@add_argument("--verbose", "-v", action="store_true", help="Enable db echo")
|
||||
def command_init_db(args) -> int:
|
||||
|
|
|
@ -1,30 +1,324 @@
|
|||
# Standard library imports
|
||||
import logging
|
||||
|
||||
from .helpers import add_argument
|
||||
|
||||
|
||||
COMMAND_NAME = "lexicon"
|
||||
COMMAND_HELP = "Interact with lexicons."
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
# Module imports
|
||||
from amanuensis.config import RootConfigDirectoryContext
|
||||
from amanuensis.models import LexiconModel, UserModel
|
||||
|
||||
from .helpers import (
|
||||
add_argument, no_argument, requires_lexicon, requires_user, alias,
|
||||
config_get, config_set, CONFIG_GET_ROOT_VALUE)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
#
|
||||
# CRUD commands
|
||||
#
|
||||
|
||||
|
||||
@alias('lc')
|
||||
@add_argument("--name", required=True, help="The name of the new lexicon")
|
||||
@requires_user
|
||||
@add_argument("--prompt", help="The lexicon's prompt")
|
||||
def command_create(args):
|
||||
"""
|
||||
Create a lexicon.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
"""
|
||||
Create a lexicon
|
||||
|
||||
The specified user will be the editor. A newly created created lexicon is
|
||||
not open for joining and requires additional configuration before it is
|
||||
playable. The editor should ensure that all settings are as desired before
|
||||
opening the lexicon for player joins.
|
||||
"""
|
||||
# Module imports
|
||||
from amanuensis.lexicon import valid_name, create_lexicon
|
||||
|
||||
root: RootConfigDirectoryContext = args.root
|
||||
|
||||
# Verify arguments
|
||||
if not valid_name(args.name):
|
||||
logger.error(f'Lexicon name contains illegal characters: "{args.name}"')
|
||||
return -1
|
||||
with root.lexicon.read_index() as index:
|
||||
if args.name in index.keys():
|
||||
logger.error(f'A lexicon with name "{args.name}" already exists')
|
||||
return -1
|
||||
|
||||
# Perform command
|
||||
create_lexicon(root, args.name, args.user)
|
||||
|
||||
# Output already logged by create_lexicon
|
||||
return 0
|
||||
|
||||
|
||||
@alias('ld')
|
||||
@requires_lexicon
|
||||
@add_argument("--purge", action="store_true", help="Delete the lexicon's data")
|
||||
def command_delete(args):
|
||||
"""
|
||||
Delete a lexicon.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
"""
|
||||
Delete a lexicon and optionally its data
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
# # Module imports
|
||||
# from amanuensis.config import logger
|
||||
# from amanuensis.lexicon.manage import delete_lexicon
|
||||
|
||||
# # Perform command
|
||||
# delete_lexicon(args.lexicon, args.purge)
|
||||
|
||||
# # Output
|
||||
# logger.info('Deleted lexicon "{}"'.format(args.lexicon.name))
|
||||
# return 0
|
||||
|
||||
|
||||
@alias('ll')
|
||||
@no_argument
|
||||
def command_list(args):
|
||||
"""
|
||||
List all lexicons and their statuses.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
"""
|
||||
List all lexicons and their statuses
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
# # Module imports
|
||||
# from amanuensis.lexicon.manage import get_all_lexicons
|
||||
|
||||
# # Execute command
|
||||
# lexicons = get_all_lexicons()
|
||||
|
||||
# # Output
|
||||
# statuses = []
|
||||
# for lex in lexicons:
|
||||
# statuses.append("{0.lid} {0.name} ({1})".format(lex, lex.status()))
|
||||
# for s in statuses:
|
||||
# print(s)
|
||||
# return 0
|
||||
|
||||
|
||||
@alias('ln')
|
||||
@requires_lexicon
|
||||
@add_argument("--get",
|
||||
metavar="PATHSPEC",
|
||||
dest="get",
|
||||
nargs="?",
|
||||
const=CONFIG_GET_ROOT_VALUE,
|
||||
help="Get the value of a config key")
|
||||
@add_argument("--set",
|
||||
metavar=("PATHSPEC", "VALUE"),
|
||||
dest="set",
|
||||
nargs=2,
|
||||
help="Set the value of a config key")
|
||||
def command_config(args):
|
||||
"""
|
||||
Interact with a lexicon's config
|
||||
"""
|
||||
lexicon: LexiconModel = args.lexicon
|
||||
|
||||
# Verify arguments
|
||||
if args.get and args.set:
|
||||
logger.error("Specify one of --get and --set")
|
||||
return -1
|
||||
|
||||
# Execute command
|
||||
if args.get:
|
||||
config_get(lexicon.cfg, args.get)
|
||||
|
||||
if args.set:
|
||||
with lexicon.ctx.edit_config() as cfg:
|
||||
config_set(lexicon.lid, cfg, args.set)
|
||||
|
||||
# config_* functions handle output
|
||||
return 0
|
||||
|
||||
#
|
||||
# Player/character commands
|
||||
#
|
||||
|
||||
|
||||
@alias('lpa')
|
||||
@requires_lexicon
|
||||
@requires_user
|
||||
def command_player_add(args):
|
||||
"""
|
||||
Add a player to a lexicon
|
||||
"""
|
||||
lexicon: LexiconModel = args.lexicon
|
||||
user: UserModel = args.user
|
||||
|
||||
# Module imports
|
||||
from amanuensis.lexicon import add_player_to_lexicon
|
||||
|
||||
# Verify arguments
|
||||
if user.uid in lexicon.cfg.join.joined:
|
||||
logger.error(f'"{user.cfg.username}" is already a player '
|
||||
f'in "{lexicon.cfg.name}"')
|
||||
return -1
|
||||
|
||||
# Perform command
|
||||
add_player_to_lexicon(user, lexicon)
|
||||
|
||||
# Output
|
||||
logger.info(f'Added user "{user.cfg.username}" to '
|
||||
f'lexicon "{lexicon.cfg.name}"')
|
||||
return 0
|
||||
|
||||
|
||||
@alias('lpr')
|
||||
@requires_lexicon
|
||||
@requires_user
|
||||
def command_player_remove(args):
|
||||
"""
|
||||
Remove a player from a lexicon
|
||||
|
||||
Removing a player dissociates them from any characters
|
||||
they control but does not delete any character data.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
# # Module imports
|
||||
# from amanuensis.lexicon.manage import remove_player
|
||||
|
||||
# # Verify arguments
|
||||
# if not args.user.in_lexicon(args.lexicon):
|
||||
# logger.error('"{0.username}" is not a player in lexicon "{1.name}"'
|
||||
# ''.format(args.user, args.lexicon))
|
||||
# return -1
|
||||
# if args.user.id == args.lexicon.editor:
|
||||
# logger.error("Can't remove the editor of a lexicon")
|
||||
# return -1
|
||||
|
||||
# # Perform command
|
||||
# remove_player(args.lexicon, args.user)
|
||||
|
||||
# # Output
|
||||
# logger.info('Removed "{0.username}" from lexicon "{1.name}"'.format(
|
||||
# args.user, args.lexicon))
|
||||
# return 0
|
||||
|
||||
|
||||
@alias('lpl')
|
||||
@requires_lexicon
|
||||
def command_player_list(args):
|
||||
"""
|
||||
List all players in a lexicon
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
# import json
|
||||
# # Module imports
|
||||
# from amanuensis.user import UserModel
|
||||
|
||||
# # Perform command
|
||||
# players = list(map(
|
||||
# lambda uid: UserModel.by(uid=uid).username,
|
||||
# args.lexicon.join.joined))
|
||||
|
||||
# # Output
|
||||
# print(json.dumps(players, indent=2))
|
||||
# return 0
|
||||
|
||||
|
||||
@alias('lcc')
|
||||
@requires_lexicon
|
||||
@requires_user
|
||||
@add_argument("--charname", required=True, help="The character's name")
|
||||
def command_char_create(args):
|
||||
"""
|
||||
Create a character for a lexicon
|
||||
|
||||
The specified player will be set as the character's player.
|
||||
"""
|
||||
lexicon: LexiconModel = args.lexicon
|
||||
user: UserModel = args.user
|
||||
|
||||
# Module imports
|
||||
from amanuensis.lexicon import create_character_in_lexicon
|
||||
|
||||
# Verify arguments
|
||||
if user.uid not in lexicon.cfg.join.joined:
|
||||
logger.error('"{0.username}" is not a player in lexicon "{1.name}"'
|
||||
''.format(user.cfg, lexicon.cfg))
|
||||
return -1
|
||||
|
||||
# Perform command
|
||||
create_character_in_lexicon(user, lexicon, args.charname)
|
||||
|
||||
# Output
|
||||
logger.info(f'Created character "{args.charname}" for "{user.cfg.username}"'
|
||||
f' in "{lexicon.cfg.name}"')
|
||||
return 0
|
||||
|
||||
|
||||
@alias('lcd')
|
||||
@requires_lexicon
|
||||
@add_argument("--charname", required=True, help="The character's name")
|
||||
def command_char_delete(args):
|
||||
"""
|
||||
Delete a character from a lexicon
|
||||
|
||||
Deleting a character dissociates them from any content
|
||||
they have contributed rather than deleting it.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
# # Module imports
|
||||
# from amanuensis.lexicon import LexiconModel
|
||||
# from amanuensis.lexicon.manage import delete_character
|
||||
|
||||
# # Verify arguments
|
||||
# lex = LexiconModel.by(name=args.lexicon)
|
||||
# if lex is None:
|
||||
# logger.error("Could not find lexicon '{}'".format(args.lexicon))
|
||||
# return -1
|
||||
|
||||
# # Internal call
|
||||
# delete_character(lex, args.charname)
|
||||
# return 0
|
||||
|
||||
|
||||
@alias('lcl')
|
||||
@requires_lexicon
|
||||
def command_char_list(args):
|
||||
"""
|
||||
List all characters in a lexicon
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
# import json
|
||||
# # Module imports
|
||||
# from amanuensis.lexicon import LexiconModel
|
||||
|
||||
# # Verify arguments
|
||||
# lex = LexiconModel.by(name=args.lexicon)
|
||||
# if lex is None:
|
||||
# logger.error("Could not find lexicon '{}'".format(args.lexicon))
|
||||
# return -1
|
||||
|
||||
# # Internal call
|
||||
# print(json.dumps(lex.character, indent=2))
|
||||
# return 0
|
||||
|
||||
#
|
||||
# Procedural commands
|
||||
#
|
||||
|
||||
|
||||
@alias('lpt')
|
||||
@requires_lexicon
|
||||
@add_argument("--as-deadline",
|
||||
action="store_true",
|
||||
help="Notifies players of the publish result")
|
||||
@add_argument("--force",
|
||||
action="store_true",
|
||||
help="Publish all approved articles, regardless of other checks")
|
||||
def command_publish_turn(args):
|
||||
"""
|
||||
Publishes the current turn of a lexicon
|
||||
|
||||
The --as-deadline flag is intended to be used only by the scheduled publish
|
||||
attempts controlled by the publish.deadlines setting.
|
||||
|
||||
The --force flag bypasses the publish.quorum and publish.block_on_ready
|
||||
settings.
|
||||
"""
|
||||
# Module imports
|
||||
from amanuensis.lexicon import attempt_publish
|
||||
|
||||
# Internal call
|
||||
result = attempt_publish(args.lexicon)
|
||||
|
||||
if not result:
|
||||
logger.error('Publish failed, check lexicon log')
|
||||
|
|
|
@ -1,37 +1,158 @@
|
|||
# Standard library imports
|
||||
import getpass
|
||||
import logging
|
||||
# import shutil
|
||||
|
||||
from .helpers import add_argument
|
||||
|
||||
|
||||
COMMAND_NAME = "user"
|
||||
COMMAND_HELP = "Interact with users."
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
# Module imports
|
||||
from amanuensis.models import UserModel
|
||||
|
||||
from .helpers import (
|
||||
add_argument,
|
||||
no_argument,
|
||||
requires_user,
|
||||
alias,
|
||||
config_get,
|
||||
config_set,
|
||||
CONFIG_GET_ROOT_VALUE)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@alias('uc')
|
||||
@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.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
"""
|
||||
Create a user
|
||||
"""
|
||||
# Module imports
|
||||
from amanuensis.user import (
|
||||
valid_username, valid_email, create_user)
|
||||
|
||||
# Verify arguments
|
||||
if not valid_username(args.username):
|
||||
logger.error("Invalid username: usernames may only contain alphanumer"
|
||||
"ic characters, dashes, and underscores")
|
||||
return -1
|
||||
if not args.displayname:
|
||||
args.displayname = args.username
|
||||
if args.email and not valid_email(args.email):
|
||||
logger.error("Invalid email")
|
||||
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
|
||||
new_user, tmp_pw = create_user(
|
||||
args.root,
|
||||
args.model_factory,
|
||||
args.username,
|
||||
args.displayname,
|
||||
args.email)
|
||||
|
||||
# Output
|
||||
print(tmp_pw)
|
||||
return 0
|
||||
|
||||
|
||||
@alias('ud')
|
||||
@requires_user
|
||||
def command_delete(args):
|
||||
"""
|
||||
Delete a user.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
"""
|
||||
Delete a user
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
# # Module imports
|
||||
# from amanuensis.config import logger, prepend, json_rw
|
||||
|
||||
# # Perform command
|
||||
# user_path = prepend('user', args.user.id)
|
||||
# shutil.rmtree(user_path)
|
||||
# with json_rw('user', 'index.json') as index:
|
||||
# del index[args.user.username]
|
||||
|
||||
# # TODO resolve user id references in all games
|
||||
|
||||
# # Output
|
||||
# logger.info("Deleted user {0.username} ({0.id})".format(args.user))
|
||||
# return 0
|
||||
|
||||
|
||||
@alias('ul')
|
||||
@no_argument
|
||||
def command_list(args):
|
||||
"""
|
||||
List all users.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
"""List all users"""
|
||||
raise NotImplementedError()
|
||||
# # Module imports
|
||||
# from amanuensis.config import prepend, json_ro
|
||||
# from amanuensis.user import UserModel
|
||||
|
||||
# # Perform command
|
||||
# users = []
|
||||
# with json_ro('user', 'index.json') as index:
|
||||
# for username, uid in index.items():
|
||||
# users.append(UserModel.by(uid=uid))
|
||||
|
||||
# # Output
|
||||
# users.sort(key=lambda u: u.username)
|
||||
# for user in users:
|
||||
# print("{0.id} {0.displayname} ({0.username})".format(user))
|
||||
# return 0
|
||||
|
||||
|
||||
@alias('un')
|
||||
@requires_user
|
||||
@add_argument(
|
||||
"--get", metavar="PATHSPEC", dest="get",
|
||||
nargs="?", const=CONFIG_GET_ROOT_VALUE, help="Get the value of a config key")
|
||||
@add_argument(
|
||||
"--set", metavar=("PATHSPEC", "VALUE"), dest="set",
|
||||
nargs=2, help="Set the value of a config key")
|
||||
def command_config(args):
|
||||
"""
|
||||
Interact with a user's config
|
||||
"""
|
||||
user: UserModel = args.user
|
||||
|
||||
# Verify arguments
|
||||
if args.get and args.set:
|
||||
logger.error("Specify one of --get and --set")
|
||||
return -1
|
||||
|
||||
# Perform command
|
||||
if args.get:
|
||||
config_get(user.cfg, args.get)
|
||||
|
||||
if args.set:
|
||||
with user.ctx.edit_config() as cfg:
|
||||
config_set(user.uid, cfg, args.set)
|
||||
|
||||
# Output
|
||||
return 0
|
||||
|
||||
|
||||
@alias('up')
|
||||
@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.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
"""
|
||||
Set a user's password
|
||||
"""
|
||||
user: UserModel = args.user
|
||||
|
||||
# Verify arguments
|
||||
password: str = args.password or getpass.getpass("Password: ")
|
||||
|
||||
# Perform command
|
||||
user.set_password(password)
|
||||
|
||||
# Output
|
||||
logger.info('Updated password for {}'.format(user.cfg.username))
|
||||
return 0
|
||||
|
|
|
@ -29,7 +29,6 @@ class EnvironmentConfig(AmanuensisConfig):
|
|||
|
||||
class CommandLineConfig(AmanuensisConfig):
|
||||
"""Loads config values from command line arguments."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("--config-file", default=AmanuensisConfig.CONFIG_FILE)
|
||||
|
|
2
mypy.ini
2
mypy.ini
|
@ -1,4 +1,4 @@
|
|||
[mypy]
|
||||
ignore_missing_imports = true
|
||||
exclude = "|amanuensis/lexicon/.*|amanuensis/models/.*|amanuensis/resources/.*|amanuensis/server/.*|amanuensis/user/.*|amanuensis/__main__.py|"
|
||||
exclude = "amanuensis/cli/.*|amanuensis/config/.*|amanuensis/lexicon/.*|amanuensis/log/.*|amanuensis/models/.*|amanuensis/resources/.*|amanuensis/server/.*|amanuensis/user/.*|amanuensis/__main__.py"
|
||||
; mypy stable doesn't support pyproject.toml yet
|
|
@ -21,7 +21,7 @@ amanuensis-cli = "amanuensis.cli:main"
|
|||
amanuensis-server = "amanuensis.server:run"
|
||||
|
||||
[tool.black]
|
||||
extend-exclude = "^/amanuensis/lexicon/.*|^/amanuensis/models/.*|^/amanuensis/resources/.*|^/amanuensis/server/.*|^/amanuensis/user/.*|^/amanuensis/__main__.py"
|
||||
extend-exclude = "^/amanuensis/cli/.*|^/amanuensis/config/.*|^/amanuensis/lexicon/.*|^/amanuensis/log/.*|^/amanuensis/models/.*|^/amanuensis/resources/.*|^/amanuensis/server/.*|^/amanuensis/user/.*|^/amanuensis/__main__.py"
|
||||
|
||||
[tool.mypy]
|
||||
ignore_missing_imports = true
|
||||
|
|
Loading…
Reference in New Issue