66 lines
2.0 KiB
Python
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
|