Source code for djask.auth.abstract

from __future__ import annotations

from time import time
from typing import Any

import sqlalchemy as sa
from apiflask.exceptions import abort
from authlib.jose import jwt
from flask_login.mixins import UserMixin
from sqlalchemy.ext.declarative import AbstractConcreteBase
from werkzeug.security import check_password_hash
from werkzeug.security import generate_password_hash

from ..extensions import db


[docs]class AbstractUser(AbstractConcreteBase, UserMixin): """ A base class for all user models. It enables you to define a user model other than the :class:`~djask.auth.models.User` model below. .. versionadded:: 0.1.0 """ __table_args__ = {"extend_existing": True} username = sa.Column(sa.String(128), index=True, unique=True) name = sa.Column(sa.String(128)) email = sa.Column(sa.String(256), unique=True) password_hash = sa.Column(sa.String(256)) is_admin = sa.Column(sa.Boolean, default=False) def __repr__(self): # pragma: no cover return f"<User {self.username}>"
[docs] def set_password(self, password: str) -> None: """Set the password for the user. :param password: The password to set .. versionadded:: 0.1.0 """ self.password_hash = generate_password_hash(password)
[docs] def check_password(self, password: str) -> bool: """Check if the password is correct. :param password: The password to check .. versionadded:: 0.1.0 """ return check_password_hash(self.password_hash, password)
[docs] def api_token(self, expiration=3600 * 24 * 7) -> str: """Generate a new API token for the user. :param expiration: The expiration time of the token in seconds :returns: The API token .. versionadded:: 0.3.0 .. versionchanged:: 0.4.2 """ from ..globals import current_app # noreorder header = {"alg": "HS256"} data = {"id": self.id, "created": time(), "expiration": expiration} return jwt.encode(header, data, current_app.config["SECRET_KEY"]).decode()
[docs] def update(self, data: dict[str, Any]) -> None: """Update the user with the given dict. :param data: The dict containing user data .. versionadded:: 0.4.2 """ for attr, value in data.items(): if not hasattr(self, attr) and attr != "password": # pragma: no cover abort(400, f"User model has no attribute {attr}.") elif attr == "password": self.set_password(value) continue if attr == "password_hash": # pragma: no cover abort(400, "You should not hard-code the password hash.") self.__setattr__(attr, value) db.session.add(self) db.session.commit()