# project/server/models.py

import jwt
import datetime

from project.server import app, db, bcrypt

class User(db.Model):
    """ User Model for storing user related details """
    __tablename__ = "users"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(255), unique=True, nullable=False)
    email = db.Column(db.String(255), unique=True, nullable=False)
    password = db.Column(db.String(255), nullable=False)
    name = db.Column(db.String(255), nullable=False)
    age = db.Column(db.Integer, nullable=False)
    address = db.Column(db.Integer(255), nullable=False)
    registered_on = db.Column(db.DateTime, nullable=False)
    admin = db.Column(db.Boolean, nullable=False, default=False)

    def __init__(self, email, username, password, name, age, address, admin=False):
        self.email = email
        self.username = username
        self.password = bcrypt.generate_password_hash(
            password, app.config.get('BCRYPT_LOG_ROUNDS')
        ).decode()
        self.name = name
        self.age = age
        self.address = address
        self.registered_on = datetime.datetime.now()
        self.admin = admin

    def encode_auth_token(self, user_id):
        """
        Generates the Auth Token
        :return: string
        """
        try:
            payload = {
                'exp': datetime.datetime.utcnow() + datetime.timedelta(days=0, seconds=5),
                'iat': datetime.datetime.utcnow(),
                'sub': user_id
            }
            return jwt.encode(
                payload,
                app.config.get('SECRET_KEY'),
                algorithm='HS256'
            )
        except Exception as e:
            return e

    @staticmethod
    def decode_auth_token(auth_token):
        """
        Validates the auth token
        :param auth_token:
        :return: integer|string
        """
        try:
            payload = jwt.decode(auth_token, app.config.get('SECRET_KEY'))
            is_blacklisted_token = BlacklistToken.check_blacklist(auth_token)
            if is_blacklisted_token:
                return 'Token blacklisted. Please log in again.'
            else:
                return payload['sub']
        except jwt.ExpiredSignatureError:
            return 'Signature expired. Please log in again.'
        except jwt.InvalidTokenError:
            return 'Invalid token. Please log in again.'


class BlacklistToken(db.Model):
    """
    Token Model for storing JWT tokens
    """
    __tablename__ = 'blacklist_tokens'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    token = db.Column(db.String(500), unique=True, nullable=False)
    blacklisted_on = db.Column(db.DateTime, nullable=False)

    def __init__(self, token):
        self.token = token
        self.blacklisted_on = datetime.datetime.now()

    def __repr__(self):
        return '<id: token: {}'.format(self.token)

    @staticmethod
    def check_blacklist(auth_token):
        # Check whether auth token has been blacklisted
        res = BlacklistToken.query.filter_by(token=str(auth_token)).first()
        if res:
            return True
        else:
            return False

[((216, 275), 'project.server.db.Column', 'db.Column', (['db.Integer'], {'primary_key': '(True)', 'autoincrement': '(True)'}), '(db.Integer, primary_key=True, autoincrement=True)\n', (225, 275), False, 'from project.server import app, db, bcrypt\n'), ((533, 570), 'project.server.db.Column', 'db.Column', (['db.Integer'], {'nullable': '(False)'}), '(db.Integer, nullable=False)\n', (542, 570), False, 'from project.server import app, db, bcrypt\n'), ((648, 686), 'project.server.db.Column', 'db.Column', (['db.DateTime'], {'nullable': '(False)'}), '(db.DateTime, nullable=False)\n', (657, 686), False, 'from project.server import app, db, bcrypt\n'), ((699, 751), 'project.server.db.Column', 'db.Column', (['db.Boolean'], {'nullable': '(False)', 'default': '(False)'}), '(db.Boolean, nullable=False, default=False)\n', (708, 751), False, 'from project.server import app, db, bcrypt\n'), ((2572, 2631), 'project.server.db.Column', 'db.Column', (['db.Integer'], {'primary_key': '(True)', 'autoincrement': '(True)'}), '(db.Integer, primary_key=True, autoincrement=True)\n', (2581, 2631), False, 'from project.server import app, db, bcrypt\n'), ((2720, 2758), 'project.server.db.Column', 'db.Column', (['db.DateTime'], {'nullable': '(False)'}), '(db.DateTime, nullable=False)\n', (2729, 2758), False, 'from project.server import app, db, bcrypt\n'), ((301, 315), 'project.server.db.String', 'db.String', (['(255)'], {}), '(255)\n', (310, 315), False, 'from project.server import app, db, bcrypt\n'), ((368, 382), 'project.server.db.String', 'db.String', (['(255)'], {}), '(255)\n', (377, 382), False, 'from project.server import app, db, bcrypt\n'), ((438, 452), 'project.server.db.String', 'db.String', (['(255)'], {}), '(255)\n', (447, 452), False, 'from project.server import app, db, bcrypt\n'), ((491, 505), 'project.server.db.String', 'db.String', (['(255)'], {}), '(255)\n', (500, 505), False, 'from project.server import app, db, bcrypt\n'), ((595, 610), 'project.server.db.Integer', 'db.Integer', (['(255)'], {}), '(255)\n', (605, 610), False, 'from project.server import app, db, bcrypt\n'), ((1137, 1160), 'datetime.datetime.now', 'datetime.datetime.now', ([], {}), '()\n', (1158, 1160), False, 'import datetime\n'), ((2654, 2668), 'project.server.db.String', 'db.String', (['(500)'], {}), '(500)\n', (2663, 2668), False, 'from project.server import app, db, bcrypt\n'), ((2848, 2871), 'datetime.datetime.now', 'datetime.datetime.now', ([], {}), '()\n', (2869, 2871), False, 'import datetime\n'), ((1463, 1489), 'datetime.datetime.utcnow', 'datetime.datetime.utcnow', ([], {}), '()\n', (1487, 1489), False, 'import datetime\n'), ((1608, 1636), 'project.server.app.config.get', 'app.config.get', (['"""SECRET_KEY"""'], {}), "('SECRET_KEY')\n", (1622, 1636), False, 'from project.server import app, db, bcrypt\n'), ((1970, 1998), 'project.server.app.config.get', 'app.config.get', (['"""SECRET_KEY"""'], {}), "('SECRET_KEY')\n", (1984, 1998), False, 'from project.server import app, db, bcrypt\n'), ((974, 1009), 'project.server.app.config.get', 'app.config.get', (['"""BCRYPT_LOG_ROUNDS"""'], {}), "('BCRYPT_LOG_ROUNDS')\n", (988, 1009), False, 'from project.server import app, db, bcrypt\n'), ((1372, 1398), 'datetime.datetime.utcnow', 'datetime.datetime.utcnow', ([], {}), '()\n', (1396, 1398), False, 'import datetime\n'), ((1401, 1438), 'datetime.timedelta', 'datetime.timedelta', ([], {'days': '(0)', 'seconds': '(5)'}), '(days=0, seconds=5)\n', (1419, 1438), False, 'import datetime\n')]