# Path: modules/auth/Env.py
# class Env:
#     def __init__(self, config: ConfigWrapper, db: Database):
#         self.db = db
#         self.config = config
#         self.userDB = UserDB(self.db[self.config["auth coll user"]])
#         self.tokenDB = TokenDB(self.db[self.config["auth coll token"]])
# 
# Path: modules/auth/User.py
# class User(NamedTuple('User', [
#         ('id', UserID), 
#         ('name', Username),
#         ('password', Password),
#         ('salt', Salt),
#         ('privs', List[Priv])
#     ])):
# class UserBSONHandler:
# class UserDB(NamedTuple('UserDB', [
#         ('coll', Collection)
#     ])):
#     def new(name: Username, password: Password, privs: List[Priv] = []):
#     def hashPassword(password: Password, salt: Opt[Salt] = None) -> Tuple[Password, Salt]:
#     def checkPassword(self, password: Password) -> bool:
#     def reads(bson: Dict) -> User:
#     def writes(user: User) -> Dict:
#     def write(self, user: User):
#     def byId(self, _id: UserID) -> Opt[User]:
# 
# Path: modules/auth/Token.py
# class Token(NamedTuple('Token', [
#         ('id', TokenID),
#         ('name', str),
#         ('privs', List[Priv])
#     ])):
# class TokenBSONHandler:
# class TokenDB(NamedTuple('TokenDB', [
#         ('coll', Collection)
#     ])):
#     def hasPriv(self, priv: Priv) -> bool:
#     def reads(bson: Dict) -> Token:
#     def writes(token: Token) -> Dict:
#     def write(self, token: Token):
#     def byId(self, _id: TokenID) -> Opt[Token]:
# 
# Path: modules/auth/Priv.py

# 
# Path: webapp/DefaultResponse.py



from default_imports import *
from modules.auth.Env import Env
from modules.auth.User import User, UserID, Username, Password
from modules.auth.Token import Token, TokenID
from modules.auth.Priv import Priv
from webapp.DefaultResponse import BadRequest
from flask import request, abort
from functools import wraps
Authable = TypeVar('Authable', User, Token)

Authorised = NewType('Authorised', bool)

AuthID = TypeVar('AuthID', UserID, TokenID)

class Auth(NamedTuple('Auth', [('env', Env)])):
    def loginUser(self, username: Username, password: Password) -> Tuple[Opt[User], Authorised]:
        """
        Attempts to log in a user.
        Returns True is successful.
        False if the user exists and the password is incorrect.
        None if the user does not exist.
        """
        user = self.env.userDB.byId(username)
        if user is not None:
            return (user, user.checkPassword(password))
        return (None, False)

    def registerUser(self, name: Username, password: Password, privs: List[Priv] = []) -> Opt[User]:
        """
        Will attempt to register a user.
        Returns User object if successful, otherwise None.
        """
        user = User.new(name, password, privs)
        if env.userDB.byId(user.id) is None:
            env.userDB.write(user)
            return user
        return None


# Path: modules/auth/Env.py
# class Env:
#     def __init__(self, config: ConfigWrapper, db: Database):
#         self.db = db
#         self.config = config
#         self.userDB = UserDB(self.db[self.config["auth coll user"]])
#         self.tokenDB = TokenDB(self.db[self.config["auth coll token"]])
# 
# Path: modules/auth/User.py
# class User(NamedTuple('User', [
#         ('id', UserID), 
#         ('name', Username),
#         ('password', Password),
#         ('salt', Salt),
#         ('privs', List[Priv])
#     ])):
# class UserBSONHandler:
# class UserDB(NamedTuple('UserDB', [
#         ('coll', Collection)
#     ])):
#     def new(name: Username, password: Password, privs: List[Priv] = []):
#     def hashPassword(password: Password, salt: Opt[Salt] = None) -> Tuple[Password, Salt]:
#     def checkPassword(self, password: Password) -> bool:
#     def reads(bson: Dict) -> User:
#     def writes(user: User) -> Dict:
#     def write(self, user: User):
#     def byId(self, _id: UserID) -> Opt[User]:
# 
# Path: modules/auth/Token.py
# class Token(NamedTuple('Token', [
#         ('id', TokenID),
#         ('name', str),
#         ('privs', List[Priv])
#     ])):
# class TokenBSONHandler:
# class TokenDB(NamedTuple('TokenDB', [
#         ('coll', Collection)
#     ])):
#     def hasPriv(self, priv: Priv) -> bool:
#     def reads(bson: Dict) -> Token:
#     def writes(token: Token) -> Dict:
#     def write(self, token: Token):
#     def byId(self, _id: TokenID) -> Opt[Token]:
# 
# Path: modules/auth/Priv.py

# 
# Path: webapp/DefaultResponse.py



# Path: modules/auth/Auth.py
from default_imports import *
from modules.auth.Env import Env
from modules.auth.User import User, UserID, Username, Password
from modules.auth.Token import Token, TokenID
from modules.auth.Priv import Priv
from webapp.DefaultResponse import BadRequest
from flask import request, abort
from functools import wraps

Authable = TypeVar('Authable', User, Token)

Authorised = NewType('Authorised', bool)

AuthID = TypeVar('AuthID', UserID, TokenID)

class Auth(NamedTuple('Auth', [('env', Env)])):
    def loginUser(self, username: Username, password: Password) -> Tuple[Opt[User], Authorised]:
        """
        Attempts to log in a user.
        Returns True is successful.
        False if the user exists and the password is incorrect.
        None if the user does not exist.
        """
        user = self.env.userDB.byId(username)
        if user is not None:
            return (user, user.checkPassword(password))
        return (None, False)

    def registerUser(self, name: Username, password: Password, privs: List[Priv] = []) -> Opt[User]:
        """
        Will attempt to register a user.
        Returns User object if successful, otherwise None.
        """
        user = User.new(name, password, privs)
        if env.userDB.byId(user.id) is None:
            env.userDB.write(user)
            return user
        return None


    def authoriseTokenId(self, tokenId: TokenID, priv: Priv) -> Tuple[Opt[Token], Authorised]: