예제 #1
0
class Post(db.Model):
	# __tablename__ = 'posts'
	id = db.Column(db.Integer, primary_key=True, autoincrement=True)
	author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
	comments = db.relationship('Comment', backref='Post', lazy=True)
	likes = db.relationship('Like', backref='Post', lazy=True)
	tags = db.relationship(
		'Tag', secondary=tags, lazy='subquery',
		backref=db.backref('posts', lazy=True),
	)
	title = db.Column(db.String, unique=False)
	desc = db.Column(db.Text, unique=False)  # TODO:Check limit and create character limit?
	s3_name = db.Column(db.String, unique=True, nullable=False)
	# TODO replace this with a method to return url with s3 name?
	# s3_url = db.Column(db.String, unique=True, nullable=False)

	def s3_url(self):
		return f"https://{s3.bucket_name}.s3.amazonaws.com/{self.s3_name}"

	def resp_dict(self):
		get_user = lambda id: User.query.get(id)
		post_author = User.query.get(self.author_id)
		return {
			'id': self.id,
			'title': self.title,
			'author_id': self.author_id,
			# 's3_url': self.s3_url,
			's3_url': self.s3_url(),
			'description': self.desc,
			'author_username': post_author.username,
			'author_avi': post_author.avi_url(),
			'comments': [
				{
					'body': comment.body,
					'author_id': comment.author_id,
					'avi': get_user(comment.author_id).avi_url(),
					'username': get_user(comment.author_id).username,
				} for comment in self.comments
			],
			'likes': [
				{
					'value': like.value,
					'user_id': like.user_id,
					'avi': get_user(like.user_id).avi_url(),
					'username': get_user(like.user_id).username
				} for like in self.likes
			],
			'tags': [tag.name for tag in self.tags]
		}
예제 #2
0
class PlotModel(db.Model):
    __tablename__ = 'plot'
    id = db.Column(db.Integer, primary_key=True)
    cpm = db.Column(db.String(30))
    values = db.Column(db.JSON)
    data = db.Column(db.JSON)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    user = db.relationship('UserModel')  # type: src.UserModel

    def __init__(self, cpm: str, values, data, user_id):
        self.cpm = cpm
        self.values = values
        self.data = data
        self.user_id = user_id

    def json(self):
        return {
            'plot': {
                'user': self.user.username,
                'cpm': self.cpm,
                'values': self.values,
                'data': self.data
            }
        }

    def save(self):
        db.session.add(self)
        db.session.commit()

    @classmethod
    def find_by_id(cls, _id) -> PlotModel:
        return cls.query.get(_id)
예제 #3
0
class Recipe(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    name = db.Column(db.String(80))
    ingredients = db.relationship('Ingredients',
                                  backref='recipe',
                                  lazy='dynamic')
    imageUrl = db.Column(db.String(80))
    created = db.Column(db.DateTime)

    def __init__(self, user_id, name, ingredients, imageUrl, created=None):
        self.user_id = user_id
        self.name = name
        self.ingredients = []
        for ing in ingredients:
            if 'name' in name:
                name = ing.name
            if name is None:
                name = ing.get('name')
            self.ingredients.append(Ingredients(self.id, name))

        if created is None:
            created = datetime.utcnow()
        self.created = created
        self.imageUrl = imageUrl

    def __repr__(self):
        return '<Recipe: user_id: %s, name: %s, imageUrl: %s>' % (
            self.user_id, self.name, self.imageUrl)
예제 #4
0
class User(Model):
    id = Column(db.Integer, primary_key=True)
    username = Column(db.String(80), nullable=False)
    email = Column(db.String(128), unique=True, nullable=False)
    password_hash = Column(db.String(128), nullable=False)
    confirmed = Column(db.Boolean, default=False)
    todos = db.relationship(Todo, backref='user', lazy=True)
    created_at = Column(db.DateTime, nullable=False, default=datetime.utcnow)

    def set_password(self, password):
        print('hello')
        if len(password) < 8 or len(password) > 50:
            raise AssertionError(
                'Password must be between 8 and 50 characters')

        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

    def save(self):
        db.session.add(self)
        db.session.commit()

    def __repr__(self):
        return f'<User {self.username}>'
예제 #5
0
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80))
    email = db.Column(db.String(80))
    password = db.Column(db.String(200))
    created = db.Column(db.DateTime)
    recipes = db.relationship('Recipe', backref='user', lazy='dynamic')
    token = db.Column(db.String(250))

    def hash_password(self, password):
        self.password = pwd_context.encrypt(password)

    def verify_password(self, password):
        return pwd_context.verify(password, self.password)

    def generate_auth_token(
        self,
        expiration=(60 *
                    10)):  # 60 * x mins - will probably want to increase this
        # Check if valid token already exists, otherwise we can generate a new one
        if self.token is not None:
            token_state = User.verify_auth_token(self.token)
            if token_state is "Valid":
                log.info("Token is valid...returning")
                return self.token
        s = Serializer(secret_key, expires_in=expiration)
        self.token = s.dumps({'id': self.id})
        return self.token

    def getID(self):
        return self.id

    @staticmethod
    def verify_auth_token(token):
        s = Serializer(secret_key)
        try:
            data = s.loads(token)
        except SignatureExpired:
            return "Expired"
        except BadSignature:
            return "Invalid"
        return "Valid"

    def __init__(self, username, email, password, recipes=[], created=None):
        self.username = username
        self.email = email
        self.password = pwd_context.encrypt(password)
        self.recipes = recipes
        if created is None:
            created = datetime.utcnow()
        self.created = created
        self.token = self.generate_auth_token()

    def __repr__(self):
        return '<User: id: %s, username: %s, email: %s, password: %s, token: %s>' % (
            self.id, self.username, self.email, self.password, self.token)
예제 #6
0
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.String(64),
                   primary_key=True,
                   nullable=False,
                   unique=True)
    pseudo = db.Column(db.String(64), primary_key=True, nullable=False)
    creation_date = db.Column(db.DateTime, nullable=False)
    update_date = db.Column(db.DateTime, nullable=True)
    tweets = db.relationship('Tweet', back_populates="user")
예제 #7
0
class Tweet(db.Model):
    __tablename__ = "tweets"
    id = db.Column(db.String(64),
                   primary_key=True,
                   nullable=False,
                   unique=True)
    message = db.Column(db.String(280), nullable=False)
    creation_date = db.Column(db.DateTime, nullable=False)
    update_date = db.Column(db.DateTime, nullable=True)
    user_id = db.Column(db.String(64), db.ForeignKey(user.User.id))
    user = db.relationship('User', back_populates="tweets")
예제 #8
0
class Todos(db.Model):
    __table_name__ = "todos"

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(50))
    contents = db.Column(db.String(200))
    created_at = db.Column(db.DateTime, server_default=func.now())
    updated_at = db.Column(db.DateTime, onupdate=func.now())

    user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
    user = db.relationship("User", backref="todos", lazy=True)  # 객체 이름을 받는다.
예제 #9
0
class Chat(db.Model):
	id = db.Column(db.Integer, primary_key=True, autoincrement=True)
	room_name = db.Column(db.String, nullable=False, unique=True)
	messages = db.relationship(
		'Message', secondary=messages, lazy='subquery',
		backref=db.backref('messages', lazy=True),
	)
	users = db.relationship(
		'User', secondary=chats, lazy='subquery',
		backref=db.backref('users', lazy=True),
	)

	def resp_dict(self, exceptID=None):
		return {
			'roomName': self.room_name,
			'users': [user.resp_dict(follows=False) for user in self.users if user.id != exceptID],
			'messages': [message.resp_dict() for message in self.messages]
		}

	def __repr__(self):
		return f"<Chat id:{self.id} name:{self.name}>"
예제 #10
0
class UserModel(db.Model):
    __tablename__ = 'user'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(30), unique=True)
    password = db.Column(db.String(30))

    plots = db.relationship('PlotModel', lazy='dynamic')  # type: list

    def __init__(self, username, password):
        self.username = username
        self.password = password

    def json(self):
        return {
            'user': self.username,
            'is_admin': (self.is_admin() is not None),
            'plots': [plot.id for plot in self.plots]
        }

    def save(self):
        db.session.add(self)
        db.session.commit()

    def is_admin(self):
        return AdminModel.find_by_id(self.id)

    @classmethod
    def find_by_username(cls, username) -> UserModel:
        return cls.query.filter_by(username=username).first()

    @classmethod
    def find_by_id(cls, _id) -> UserModel:
        return cls.query.get(_id)

    @classmethod
    def set_master_admin(cls, password, access_level) -> bool:
        _LOGGER.debug("Checking master admin..")
        master_admin = UserModel.find_by_username("admin")
        if not master_admin:
            _LOGGER.debug("No master admin set, creating new..")
            user = UserModel("admin", password)
            user.save()
            master_admin = AdminModel(user.id, access_level)
            master_admin.save()
            _LOGGER.debug(f"Admin 'admin' set with password '{password}'.")
            return True

        else:
            _LOGGER.debug("Already set.")
            return False
예제 #11
0
class Chat(db.Model):
    """
    Telegram chat.
    One user can have multiple chats.
    """
    __tablename__ = "chats"

    # Columns
    id = db.Column(db.Integer, primary_key=True)
    telegram_id = db.Column(
        db.BigInteger,
        unique=True,
        nullable=False,
        comment="Unique ID to identificate chat in Telegram")
    type = db.Column(db.Enum(ChatType),
                     nullable=False,
                     comment="Type of Telegram chat")
    user_id = db.Column(
        db.Integer,
        db.ForeignKey("users.id"),
        nullable=False,
        comment="Through this chat message can be sent to this user")

    # Relationships
    user = db.relationship("User", back_populates="chats", uselist=False)

    def __repr__(self):
        return f"<Chat {self.id}>"

    @staticmethod
    def create_fake(user):
        """
        Creates fake chat.

        :param user: User to associate created chat with.
        """
        from faker import Faker

        fake = Faker()
        random_number = fake.pyint(min_value=1, max_value=10, step=1)
        result = Chat(user=user)

        result.telegram_id = fake.pyint(min_value=10000000,
                                        max_value=10000000000,
                                        step=1)
        result.type = (fake.random_element(list(ChatType)) if
                       (random_number % 10 == 0) else ChatType.PRIVATE)

        return result
예제 #12
0
class AdminModel(db.Model):
    __tablename__ = 'admin'
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
    access_level = db.Column(db.Integer, nullable=False)

    user = db.relationship('UserModel')

    def __init__(self, user_id, access_level):
        self.user_id = user_id
        self.access_level = access_level

    def json(self):
        return {'admin': self.user.username, 'access_level': self.access_level}

    def save(self):
        db.session.add(self)
        db.session.commit()

    @classmethod
    def find_by_id(cls, user_id) -> AdminModel:
        return cls.query.get(user_id)
예제 #13
0
class User(db.Model):
    """
    Telegram user.
    """
    __tablename__ = "users"

    # Columns
    id = db.Column(db.Integer, primary_key=True)
    create_date = db.Column(db.DateTime(timezone=False),
                            server_default=func.now(),
                            nullable=False)
    last_update_date = db.Column(db.DateTime(timezone=False),
                                 server_default=func.now(),
                                 onupdate=func.now(),
                                 nullable=False)
    telegram_id = db.Column(
        db.Integer,
        unique=True,
        nullable=False,
        comment="Unique ID to identificate user in Telegram")
    is_bot = db.Column(db.Boolean,
                       nullable=False,
                       comment="User is bot in Telegram")
    language = db.Column(db.Enum(SupportedLanguages),
                         default=SupportedLanguages.EN,
                         nullable=False,
                         comment="Preferred language of user")
    group = db.Column(db.Enum(UserGroup),
                      default=UserGroup.USER,
                      nullable=False,
                      comment="User rights group")

    # Relationships
    chats = db.relationship("Chat", back_populates="user", uselist=True)
    yandex_disk_token = db.relationship("YandexDiskToken",
                                        back_populates="user",
                                        uselist=False)

    def __repr__(self):
        return f"<User {self.id}>"

    @staticmethod
    def create_fake():
        """
        Creates fake user.
        """
        from faker import Faker

        fake = Faker()
        random_number = fake.pyint(min_value=1, max_value=20, step=1)
        result = User()

        result.create_date = fake.date_time_between(start_date="-2y",
                                                    end_date="now",
                                                    tzinfo=None)
        result.last_update_date = fake.date_time_between_dates(
            datetime_start=result.create_date, tzinfo=None)
        result.telegram_id = fake.pyint(min_value=100000,
                                        max_value=10000000,
                                        step=1)
        result.is_bot = (fake.pyint() % 121 == 0)
        result.language = fake.random_element(list(SupportedLanguages))
        result.group = (fake.random_element(list(UserGroup)) if
                        (random_number % 20 == 0) else UserGroup.USER)

        return result
예제 #14
0
class User(db.Model):
	# __tablename__ = "users"
	id = db.Column(db.Integer, primary_key=True)
	email = db.Column(db.String(25), unique=True, nullable=False)
	username = db.Column(db.String(255), unique=True, nullable=False)
	password = db.Column(db.String(255), nullable=False)
	last_ip = db.Column(db.String(255), nullable=True)
	created = db.Column(db.DateTime, nullable=False)
	admin = db.Column(db.Boolean, nullable=False, default=False)
	posts = db.relationship('Post', backref='author', lazy=True)
	comments = db.relationship('Comment', backref='author', lazy=True)
	likes = db.relationship('Like', backref='user', lazy=True)
	bio = db.Column(db.Text, nullable=True)
	avi_s3_name = db.Column(db.String, unique=True, nullable=True)
	chats = db.relationship(
		'Chat', secondary=chats, lazy='subquery',
		backref=db.backref('chats', lazy=True)
	)

	def __init__(self, email, username, password, admin=False):
		self.email = email
		self.username = username
		self.password = bcrypt.generate_password_hash(
			password, current_app.config.get('BCRYPT_LOG_ROUNDS')
		).decode()
		self.created = datetime.utcnow()
		self.admin = admin

	def __repr__(self):
		return f"<User id: {self.id} username: '******'>"

	def avi_url(self):
		url = f"https://{s3.bucket_name}.s3.amazonaws.com/{self.avi_s3_name}" if self.avi_s3_name else None
		return url

	def resp_dict(self, follows=True, include_private=False):
		user = {
			'id': self.id,
			'username': self.username,
			'created': str(self.created),
			'bio': self.bio,
			'avi': self.avi_url(),
		}
		if follows:
			user['following'] = [
				user.resp_dict(follows=False) for _, user in
				UserFollow.query.join(
					User, UserFollow.followed_id == User.id
				).filter(
					UserFollow.follower_id == self.id
				).add_entity(
					User
				).all()
			]
		if include_private:
			# TODO: extra information to supply to own user?
			pass
		return user

	def encode_auth_token(self, user_id):
		try:
			payload = {
				'exp': datetime.utcnow() + timedelta(days=0, minutes=30, seconds=0),
				'iat': datetime.utcnow(),
				'sub': user_id
			}
			return jwt.encode(
				payload, current_app.config.get('SECRET_KEY'), algorithm='HS256'
			)
		except Exception as e:
			raise e

	@staticmethod
	def decode_auth_token(auth_token):
		try:
			payload = jwt.decode(auth_token, current_app.config.get('SECRET_KEY'))
			is_blacklisted_token = BlacklistToken.check_blacklist(auth_token)
			if is_blacklisted_token:
				return "Token is blacklisted - please log in again"
			else:
				return payload['sub']
		except jwt.ExpiredSignatureError:
			return 'Signiture expired. Please log in again.'
		except jwt.InvalidTokenError:
			return 'Invalid token. Please log in again.'
예제 #15
0
class UserFollow(db.Model):
	id = db.Column(db.Integer, primary_key=True, autoincrement=True)
	follower_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False, unique=False)
	followed_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False, unique=False)
	follower = db.relationship('User', foreign_keys=[followed_id])
	followed = db.relationship('User', foreign_keys=[follower_id])
class YandexDiskToken(db.Model):
    """
    Yandex.Disk token.
    One user can have only one token.
    """
    __tablename__ = "yandex_disk_tokens"

    # Columns
    id = db.Column(db.Integer, primary_key=True)
    _access_token = db.Column("access_token",
                              db.String,
                              nullable=True,
                              default=null(),
                              comment="Encrypted Y.D. OAuth token")
    access_token_type = db.Column(db.String,
                                  nullable=True,
                                  default=null(),
                                  comment="Type of access token")
    access_token_expires_in = db.Column(
        db.BigInteger,
        nullable=True,
        default=null(),
        comment="Access token lifetime in seconds")
    _refresh_token = db.Column(
        "refresh_token",
        db.String,
        nullable=True,
        default=null(),
        comment="Encrypted Y.D. refresh token to use to update access token")
    _insert_token = db.Column(
        "insert_token",
        db.String,
        nullable=True,
        default=null(),
        comment=(
            "Encrypted token for DB update controlling. "
            "i.e., you shouldn't insert values if you don't know insert token"
        ))
    insert_token_expires_in = db.Column(
        db.BigInteger,
        nullable=True,
        default=null(),
        comment="Insert token lifetime in seconds")
    user_id = db.Column(db.Integer,
                        db.ForeignKey("users.id"),
                        unique=True,
                        nullable=False,
                        comment="Tokens belongs to this user")

    # Relationships
    user = db.relationship('User',
                           back_populates="yandex_disk_token",
                           uselist=False)

    def __init__(self, **kwargs):
        super(YandexDiskToken, self).__init__(**kwargs)

        if ("_access_token" in kwargs):
            raise AttributeError("`access_token` can't be accessed directly")
        elif ("_refresh_token" in kwargs):
            raise AttributeError("`refresh_token` can't be accessed directly")
        elif ("_insert_token" in kwargs):
            raise AttributeError("`insert_token` can't be accessed directly")

    def __repr__(self):
        return f"<YD Token {self.id}>"

    def __getitem__(self, key):
        return getattr(self, key)

    def __setitem__(self, key, value):
        return setattr(self, key, value)

    @staticmethod
    def create_fake(user) -> dict:
        """
        Creates fake Yandex.Disk token.

        There is two types of token: "pending" or "received".

        Pending means the app wants to write in `access_token`
        column, but request to Yandex not maded at the moment.
        If app received invalid `insert_token` from user, then
        it shouldn't make request to Yandex.

        Received means the app successfully made a request to Yandex
        and `insert_token` not exists in a row, because `INSERT`
        operation was successfully completed.

        :param user: User to associate token with.

        :returns: "Pending" token (chance is 1/10) or
        "received" token (chance is 9/10).
        """
        from faker import Faker

        fake = Faker()
        result = YandexDiskToken(user=user)
        result_type = None
        random_number = fake.pyint(min_value=1, max_value=10, step=1)

        if (random_number % 10):
            result_type = "pending"

            result.set_access_token(fake.pystr(min_chars=32, max_chars=32))
            result.set_refresh_token(fake.pystr(min_chars=32, max_chars=32))

            result.access_token_type = "bearer"
            result.access_token_expires_in = fake.pyint(min_value=31536000,
                                                        max_value=63072000,
                                                        step=1)
        else:
            result_type = "received"

            result.set_insert_token(fake.pystr(min_chars=32, max_chars=32))

            result.insert_token_expires_in = fake.pyint(min_value=600,
                                                        max_value=900,
                                                        step=100)

        return {"value": result, "type": result_type}

    @hybrid_property
    def access_token(self):
        raise AttributeError("`access_token` can't be accessed directly")

    @access_token.setter
    def access_token(self, new_value):
        raise AttributeError("`access_token` can't be accessed directly")

    @hybrid_property
    def refresh_token(self):
        raise AttributeError("`refresh_token` can't be accessed directly")

    @refresh_token.setter
    def refresh_token(self, new_value):
        raise AttributeError("`refresh_token` can't be accessed directly")

    @hybrid_property
    def insert_token(self):
        raise AttributeError("`insert_token` can't be accessed directly")

    @insert_token.setter
    def insert_token(self, new_value):
        raise AttributeError("`insert_token` can't be accessed directly")

    def set_access_token(self, token: Union[str, None]) -> None:
        """
        Sets encrypted access token.
        """
        self._set_token(token_attribute_name="_access_token", value=token)

    def get_access_token(self) -> Union[str, None]:
        """
        Returns decrypted access token.

        :raises DataCorruptedError:
        Data in DB is corrupted.
        :raises InvalidTokenError:
        Encrypted token is invalid or expired.
        """
        return self._get_token(
            token_attribute_name="_access_token",
            expires_attribute_name="access_token_expires_in")

    def set_refresh_token(self, token: Union[str, None]) -> None:
        """
        Sets encrypted refresh token.
        """
        self._set_token(token_attribute_name="_refresh_token", value=token)

    def get_refresh_token(self) -> Union[str, None]:
        """
        Returns decrypted refresh token.

        :raises DataCorruptedError:
        Data in DB is corrupted.
        :raises InvalidTokenError:
        Encrypted token is invalid.
        """
        return self._get_token(token_attribute_name="_refresh_token")

    def set_insert_token(self, token: Union[str, None]) -> None:
        """
        Sets encrypted insert token.
        """
        self._set_token(token_attribute_name="_insert_token", value=token)

    def get_insert_token(self) -> Union[str, None]:
        """
        Returns decrypted insert token.

        :raises DataCorruptedError:
        Data in DB is corrupted.
        :raises InvalidTokenError:
        Encrypted token is invalid or expired.
        """
        return self._get_token(
            token_attribute_name="_insert_token",
            expires_attribute_name="insert_token_expires_in")

    def have_access_token(self) -> bool:
        """
        :returns: `True` if `access_token` contains
        any value otherwise `False`.
        """
        return self._have_token(token_attribute_name="_access_token")

    def have_refresh_token(self) -> bool:
        """
        :returns: `True` if `refresh_token` contains
        any value otherwise `False`.
        """
        return self._have_token(token_attribute_name="_refresh_token")

    def have_insert_token(self) -> bool:
        """
        :returns: `True` if `insert_token` contains
        any value otherwise `False`.
        """
        return self._have_token(token_attribute_name="_insert_token")

    def clear_access_token(self) -> None:
        """
        Clears all data that belongs to access token.

        - perform a commit in order to save changes!
        """
        self.access_token_type = null()

        return self._clear_token(
            token_attribute_name="_access_token",
            expires_attribute_name="access_token_expires_in")

    def clear_refresh_token(self) -> None:
        """
        Clears all data that belongs to refresh token.

        - perform a commit in order to save changes!
        """
        return self._clear_token(token_attribute_name="_refresh_token")

    def clear_insert_token(self) -> None:
        """
        Clears all data that belongs to insert token.

        - perform a commit in order to save changes!
        """
        return self._clear_token(
            token_attribute_name="_insert_token",
            expires_attribute_name="insert_token_expires_in")

    def clear_all_tokens(self) -> None:
        """
        Clears all data that belongs to any kind of token.

        - perform a commit in order to save changes!
        """
        self.clear_access_token()
        self.clear_refresh_token()
        self.clear_insert_token()

    def _set_token(self, **kwargs) -> None:
        """
        Sets encrypted token.

        :param token_attribute_name:
        Name of token attribute in class.
        :param value: Value to set.
        """
        fernet = Fernet(current_app.secret_key.encode())
        token_attribute_name = kwargs["token_attribute_name"]
        value = kwargs["value"]

        if (value is None):
            self[token_attribute_name] = None
        else:
            encrypted_data = fernet.encrypt(value.encode())
            self[token_attribute_name] = encrypted_data.decode()

    def _get_token(self, **kwargs) -> Union[str, None]:
        """
        Returns decrypted token.

        :param token_attribute_name:
        Name of token attribute in class.
        :param expires_attribute_name:
        Optional. Token lifetime in seconds.
        If specified, expiration date will be checked.

        :returns: Decrypted token or `None` if value is NULL.

        :raises DataCorruptedError: Data in DB is corrupted.
        :raises InvalidTokenError: Encrypted token is invalid.
        """
        fernet = Fernet(current_app.secret_key.encode())
        token_attribute_name = kwargs["token_attribute_name"]
        encrypted_token = self[token_attribute_name]

        if (encrypted_token is None):
            return None

        token_lifetime = None
        expires_attribute_name = kwargs.get("expires_attribute_name")

        if (expires_attribute_name is not None):
            token_lifetime = self[expires_attribute_name]

            if (not isinstance(token_lifetime, int)):
                raise DataCorruptedError("Token lifetime is not an integer")

        encrypted_token = encrypted_token.encode()
        decrypted_token = None

        try:
            decrypted_token = fernet.decrypt(encrypted_token, token_lifetime)
        except InvalidTokenFernetError:
            raise InvalidTokenError("Token is invalid or expired")

        decrypted_token = decrypted_token.decode()

        return decrypted_token

    def _have_token(self, **kwargs) -> bool:
        """
        :param token_attribute_name:
        Name of token attribute in class.

        :returns:
        `True` if token contains any value, `False` otherwise.
        """
        token_attribute_name = kwargs["token_attribute_name"]
        value = self[token_attribute_name]

        return (isinstance(value, str) and len(value) > 0)

    def _clear_token(self, **kwargs) -> None:
        """
        Clears token data.

        - perform a commit in order to save changes!

        :param token_attribute_name:
        Name of token attribute in class.
        :param expires_attribute_name:
        Optional. Token lifetime in seconds.
        If specified, expiration date will be cleared.
        """
        token_attribute_name = kwargs["token_attribute_name"]
        expires_attribute_name = kwargs.get("expires_attribute_name")

        self[token_attribute_name] = null()

        if (expires_attribute_name):
            self[expires_attribute_name] = null()