73 lines
2.1 KiB
Python
Executable File
73 lines
2.1 KiB
Python
Executable File
"""Admin User model with separate authentication."""
|
|
|
|
from datetime import UTC, datetime
|
|
|
|
from sqlalchemy import Boolean, Column, DateTime, Integer, String
|
|
from werkzeug.security import check_password_hash, generate_password_hash
|
|
|
|
from customer_portal.models import Base
|
|
|
|
|
|
class AdminUser(Base):
|
|
"""Admin user with username/password authentication.
|
|
|
|
Separate from Customer - admins have their own login.
|
|
"""
|
|
|
|
__tablename__ = "admin_users"
|
|
|
|
id = Column(Integer, primary_key=True)
|
|
username = Column(String(100), unique=True, nullable=False, index=True)
|
|
password_hash = Column(String(255), nullable=False)
|
|
name = Column(String(255), nullable=False)
|
|
email = Column(String(255))
|
|
is_active = Column(Boolean, default=True)
|
|
|
|
created_at = Column(DateTime, default=lambda: datetime.now(UTC))
|
|
last_login_at = Column(DateTime)
|
|
|
|
def __repr__(self) -> str:
|
|
return f"<AdminUser {self.username}>"
|
|
|
|
def set_password(self, password: str) -> None:
|
|
"""Hash and set password."""
|
|
self.password_hash = generate_password_hash(password)
|
|
|
|
def check_password(self, password: str) -> bool:
|
|
"""Verify password against hash."""
|
|
return check_password_hash(self.password_hash, password)
|
|
|
|
@classmethod
|
|
def get_by_username(cls, db, username: str):
|
|
"""Get admin by username.
|
|
|
|
Args:
|
|
db: Database session
|
|
username: Admin username
|
|
|
|
Returns:
|
|
AdminUser instance or None
|
|
"""
|
|
return (
|
|
db.query(cls)
|
|
.filter(cls.username == username, cls.is_active == True) # noqa: E712
|
|
.first()
|
|
)
|
|
|
|
@classmethod
|
|
def authenticate(cls, db, username: str, password: str):
|
|
"""Authenticate admin with username and password.
|
|
|
|
Args:
|
|
db: Database session
|
|
username: Admin username
|
|
password: Plain text password
|
|
|
|
Returns:
|
|
AdminUser instance if valid, None otherwise
|
|
"""
|
|
admin = cls.get_by_username(db, username)
|
|
if admin and admin.check_password(password):
|
|
return admin
|
|
return None
|