brewman/brewman/brewman/models/user.py

66 lines
2.0 KiB
Python

from __future__ import annotations
import uuid
from hashlib import md5
from typing import List, Optional
from sqlalchemy import Boolean, Column, Unicode, desc, select
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Session, relationship, synonym
from .login_history import LoginHistory
from .meta import Base
from .role import Role
from .user_role import user_role
def encrypt(val: str) -> str:
return md5(val.encode("utf-8") + "Salt".encode("utf-8")).hexdigest()
class User(Base):
__tablename__ = "users"
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
name: str = Column("username", Unicode(255), unique=True)
_password: str = Column("password", Unicode(60))
locked_out: bool = Column("disabled", Boolean)
roles: List[Role] = relationship("Role", secondary=user_role)
login_history: List[LoginHistory] = relationship(
"LoginHistory", order_by=desc(LoginHistory.date), back_populates="user"
)
def _get_password(self) -> str:
return self._password
def _set_password(self, password: str) -> None:
self._password = encrypt(password)
password = property(_get_password, _set_password) # type: ignore
password = synonym("_password", descriptor=password)
@property
def __name__(self) -> str:
return self.name
def __init__(self, name: str, password: str, locked_out: bool, id_: Optional[uuid.UUID] = None) -> None:
self.name = name
self.password = password
self.locked_out = locked_out
if id_ is not None:
self.id = id_
@classmethod
def auth(cls, name: str, password: str, db: Session) -> Optional[User]:
if password is None:
return None
user: Optional[User] = db.execute(select(cls).where(cls.name.ilike(name))).scalars().one_or_none()
if not user:
return None
if user.password != encrypt(password) or user.locked_out:
return None
else:
return user