78 lines
3.4 KiB
Python
78 lines
3.4 KiB
Python
import uuid
|
|
from datetime import datetime, timezone
|
|
|
|
from sqlalchemy import String, Boolean, Integer, DateTime, Text, func, ForeignKey, Uuid
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.database import Base
|
|
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
__table_args__ = {"extend_existing": True}
|
|
|
|
id: Mapped[str] = mapped_column(Text, primary_key=True)
|
|
email: Mapped[str] = mapped_column(Text, unique=True, nullable=False)
|
|
phone: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
username: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
password: Mapped[str] = mapped_column(Text, nullable=False)
|
|
firstName: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
lastName: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
avatar: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
isActive: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
emailVerified: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
|
phoneVerified: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
|
lastLoginAt: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
createdAt: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
|
|
updatedAt: Mapped[datetime] = mapped_column(DateTime, default=func.now(), onupdate=func.now(), nullable=False)
|
|
mfaSecret: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
mfaEnabled: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
|
loginAttempts: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
|
lockedUntil: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
organization_id: Mapped[uuid.UUID | None] = mapped_column(Uuid(as_uuid=True), ForeignKey("organizations.id", ondelete="SET NULL"), nullable=True)
|
|
role: Mapped[str] = mapped_column(String(20), server_default="owner", nullable=False)
|
|
plan: Mapped[str] = mapped_column(String(20), server_default="free", nullable=False)
|
|
max_queries: Mapped[int] = mapped_column(Integer, server_default="5", nullable=False)
|
|
|
|
queries: Mapped[list["Query"]] = relationship(
|
|
"Query", back_populates="user", viewonly=True,
|
|
primaryjoin="User.id == foreign(Query.user_id)",
|
|
)
|
|
subscriptions: Mapped[list["Subscription"]] = relationship(
|
|
"Subscription", back_populates="user", viewonly=True,
|
|
primaryjoin="User.id == foreign(Subscription.user_id)",
|
|
)
|
|
organization: Mapped["Organization | None"] = relationship(
|
|
"Organization", secondary="org_members", viewonly=True, uselist=False,
|
|
)
|
|
org_memberships: Mapped[list["OrgMember"]] = relationship(
|
|
"OrgMember", back_populates="user", viewonly=True,
|
|
primaryjoin="User.id == foreign(OrgMember.user_id)",
|
|
)
|
|
|
|
@property
|
|
def name(self) -> str | None:
|
|
if self.firstName and self.lastName:
|
|
return f"{self.firstName} {self.lastName}"
|
|
return self.username or self.firstName
|
|
|
|
@property
|
|
def is_admin(self) -> bool:
|
|
return False
|
|
|
|
@property
|
|
def is_active(self) -> bool:
|
|
return self.isActive
|
|
|
|
@property
|
|
def email_verified(self) -> bool:
|
|
return self.emailVerified
|
|
|
|
@property
|
|
def avatar_url(self) -> str | None:
|
|
return self.avatar
|
|
|
|
@property
|
|
def password_hash(self) -> str:
|
|
return self.password
|