from datetime import datetime from uuid import uuid4 from flask_login import UserMixin, AnonymousUserMixin from sqlalchemy import func from sqlalchemy.ext.hybrid import hybrid_property from werkzeug.security import generate_password_hash, check_password_hash from app import db from app.models.utils import ModelMixin from app.logger import log from app import schema as s def gen_password_reset_id() -> str: return str(uuid4()) class User(db.Model, UserMixin, ModelMixin): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(60), unique=True, nullable=False) email = db.Column(db.String(255), unique=True, nullable=False) password_hash = db.Column(db.String(255), default="") activated = db.Column(db.Boolean, default=False) created_at = db.Column(db.DateTime, default=datetime.now) unique_id = db.Column(db.String(36), default=gen_password_reset_id) reset_password_uid = db.Column(db.String(64), default=gen_password_reset_id) @hybrid_property def password(self): return self.password_hash @password.setter def password(self, password): self.password_hash = generate_password_hash(password) @classmethod def authenticate(cls, user_id, password): user = cls.query.filter( db.or_( func.lower(cls.username) == func.lower(user_id), func.lower(cls.email) == func.lower(user_id), ) ).first() if not user: log(log.WARNING, "user:[%s] not found", user_id) if user is not None and check_password_hash(user.password, password): return user def reset_password(self): self.password_hash = "" self.reset_password_uid = gen_password_reset_id() self.save() def __repr__(self): return f"<{self.id}: {self.username},{self.email}>" @property def json(self): u = s.User.from_orm(self) return u.json() class AnonymousUser(AnonymousUserMixin): pass