Get home page and login working #14
|
@ -1,11 +0,0 @@
|
||||||
from .factory import ModelFactory
|
|
||||||
from .lexicon import LexiconModel
|
|
||||||
from .user import UserModelBase, UserModel, AnonymousUserModel
|
|
||||||
|
|
||||||
__all__ = [member.__name__ for member in [
|
|
||||||
ModelFactory,
|
|
||||||
LexiconModel,
|
|
||||||
UserModelBase,
|
|
||||||
UserModel,
|
|
||||||
AnonymousUserModel,
|
|
||||||
]]
|
|
|
@ -1,57 +0,0 @@
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from amanuensis.config import is_guid, RootConfigDirectoryContext
|
|
||||||
from amanuensis.errors import ArgumentError
|
|
||||||
|
|
||||||
from .user import UserModel
|
|
||||||
from .lexicon import LexiconModel
|
|
||||||
|
|
||||||
|
|
||||||
class ModelFactory():
|
|
||||||
def __init__(self, root: RootConfigDirectoryContext):
|
|
||||||
self.root: RootConfigDirectoryContext = root
|
|
||||||
|
|
||||||
def try_user(self, identifier: str) -> Optional[UserModel]:
|
|
||||||
user: Optional[UserModel] = None
|
|
||||||
try:
|
|
||||||
user = self.user(identifier)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
return user
|
|
||||||
|
|
||||||
def user(self, identifier: str) -> UserModel:
|
|
||||||
"""Get the user model for the given id or username"""
|
|
||||||
# Ensure we have something to work with
|
|
||||||
if identifier is None:
|
|
||||||
raise ArgumentError('identifer must not be None')
|
|
||||||
# Ensure we have a user guid
|
|
||||||
if not is_guid(identifier):
|
|
||||||
with self.root.user.read_index() as index:
|
|
||||||
uid = index.get(identifier, None)
|
|
||||||
if uid is None:
|
|
||||||
raise KeyError(f'Unknown username: {identifier})')
|
|
||||||
if not is_guid(uid):
|
|
||||||
raise ValueError(f'Invalid index entry: {uid}')
|
|
||||||
else:
|
|
||||||
uid = identifier
|
|
||||||
user = UserModel(self.root, uid)
|
|
||||||
return user
|
|
||||||
|
|
||||||
def lexicon(self, identifier: str) -> LexiconModel:
|
|
||||||
"""Get the lexicon model for the given id or name"""
|
|
||||||
# Ensure we have something to work with
|
|
||||||
if identifier is None:
|
|
||||||
raise ArgumentError('identifier must not be None')
|
|
||||||
# Ensure we have a lexicon guid
|
|
||||||
if not is_guid(identifier):
|
|
||||||
with self.root.lexicon.read_index() as index:
|
|
||||||
lid = index.get(identifier, None)
|
|
||||||
if lid is None:
|
|
||||||
raise KeyError(f'Unknown lexicon: {identifier}')
|
|
||||||
if not is_guid(lid):
|
|
||||||
raise ValueError(f'Invalid index entry: {lid}')
|
|
||||||
else:
|
|
||||||
lid = identifier
|
|
||||||
lexicon = LexiconModel(self.root, lid)
|
|
||||||
return lexicon
|
|
|
@ -1,64 +0,0 @@
|
||||||
import time
|
|
||||||
from typing import cast
|
|
||||||
|
|
||||||
from amanuensis.config import (
|
|
||||||
RootConfigDirectoryContext,
|
|
||||||
LexiconConfigDirectoryContext,
|
|
||||||
ReadOnlyOrderedDict)
|
|
||||||
|
|
||||||
|
|
||||||
class LexiconModel():
|
|
||||||
PREGAME = "unstarted"
|
|
||||||
ONGOING = "ongoing"
|
|
||||||
COMPLETE = "completed"
|
|
||||||
|
|
||||||
"""Represents a lexicon in the Amanuensis config store"""
|
|
||||||
def __init__(self, root: RootConfigDirectoryContext, lid: str):
|
|
||||||
self._lid: str = lid
|
|
||||||
# Creating the config context implicitly checks for existence
|
|
||||||
self._ctx: LexiconConfigDirectoryContext = (
|
|
||||||
cast(LexiconConfigDirectoryContext, root.lexicon[lid]))
|
|
||||||
with self._ctx.read_config() as config:
|
|
||||||
self._cfg: ReadOnlyOrderedDict = cast(ReadOnlyOrderedDict, config)
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return f'<Lexicon {self.cfg.name}>'
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f'<LexiconModel({self.lid})>'
|
|
||||||
|
|
||||||
# Properties
|
|
||||||
|
|
||||||
@property
|
|
||||||
def lid(self) -> str:
|
|
||||||
"""Lexicon guid"""
|
|
||||||
return self._lid
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ctx(self) -> LexiconConfigDirectoryContext:
|
|
||||||
"""Lexicon config directory context"""
|
|
||||||
return self._ctx
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cfg(self) -> ReadOnlyOrderedDict:
|
|
||||||
"""Cached lexicon config"""
|
|
||||||
return self._cfg
|
|
||||||
|
|
||||||
# Utilities
|
|
||||||
|
|
||||||
@property
|
|
||||||
def title(self) -> str:
|
|
||||||
return self.cfg.get('title') or f'Lexicon {self.cfg.name}'
|
|
||||||
|
|
||||||
def log(self, message: str) -> None:
|
|
||||||
now = int(time.time())
|
|
||||||
with self.ctx.edit_config() as cfg:
|
|
||||||
cfg.log.append([now, message])
|
|
||||||
|
|
||||||
@property
|
|
||||||
def status(self) -> str:
|
|
||||||
if self.cfg.turn.current is None:
|
|
||||||
return LexiconModel.PREGAME
|
|
||||||
if self.cfg.turn.current > self.cfg.turn.max:
|
|
||||||
return LexiconModel.COMPLETE
|
|
||||||
return LexiconModel.ONGOING
|
|
|
@ -1,83 +0,0 @@
|
||||||
from typing import cast
|
|
||||||
|
|
||||||
from werkzeug.security import generate_password_hash, check_password_hash
|
|
||||||
|
|
||||||
from amanuensis.config import (
|
|
||||||
RootConfigDirectoryContext,
|
|
||||||
UserConfigDirectoryContext,
|
|
||||||
ReadOnlyOrderedDict)
|
|
||||||
|
|
||||||
|
|
||||||
class UserModelBase():
|
|
||||||
"""Common base class for auth and anon user models"""
|
|
||||||
|
|
||||||
# Properties
|
|
||||||
|
|
||||||
@property
|
|
||||||
def uid(self) -> str:
|
|
||||||
"""User guid"""
|
|
||||||
return getattr(self, '_uid', None)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ctx(self) -> UserConfigDirectoryContext:
|
|
||||||
"""User config directory context"""
|
|
||||||
return getattr(self, '_ctx', None)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cfg(self) -> ReadOnlyOrderedDict:
|
|
||||||
"""Cached user config"""
|
|
||||||
return getattr(self, '_cfg', None)
|
|
||||||
|
|
||||||
# Flask-Login interfaces
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_authenticated(self) -> bool:
|
|
||||||
return self.uid is not None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_active(self) -> bool:
|
|
||||||
return self.uid is not None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_anonymous(self) -> bool:
|
|
||||||
return self.uid is None
|
|
||||||
|
|
||||||
def get_id(self) -> str:
|
|
||||||
return self.uid
|
|
||||||
|
|
||||||
|
|
||||||
class UserModel(UserModelBase):
|
|
||||||
"""Represents a user in the Amanuensis config store"""
|
|
||||||
def __init__(self, root: RootConfigDirectoryContext, uid: str):
|
|
||||||
self._uid: str = uid
|
|
||||||
# Creating the config context implicitly checks for existence
|
|
||||||
self._ctx: UserConfigDirectoryContext = (
|
|
||||||
cast(UserConfigDirectoryContext, root.user[uid]))
|
|
||||||
with self._ctx.read_config() as config:
|
|
||||||
self._cfg: ReadOnlyOrderedDict = cast(ReadOnlyOrderedDict, config)
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return f'<{self.cfg.username}>'
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f'<UserModel({self.uid})>'
|
|
||||||
|
|
||||||
# Utility methods
|
|
||||||
|
|
||||||
def set_password(self, password: str) -> None:
|
|
||||||
pw_hash = generate_password_hash(password)
|
|
||||||
with self.ctx.edit_config() as cfg:
|
|
||||||
cfg['password'] = pw_hash
|
|
||||||
|
|
||||||
def check_password(self, password) -> bool:
|
|
||||||
with self.ctx.read_config() as cfg:
|
|
||||||
return check_password_hash(cfg.password, password)
|
|
||||||
|
|
||||||
|
|
||||||
class AnonymousUserModel(UserModelBase):
|
|
||||||
"""Represents an anonymous user"""
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return '<Anonymous>'
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return '<AnonymousUserModel>'
|
|
Loading…
Reference in New Issue