Files
boc/landvex/user-management/app/models.py
T
Bernt aee0f09db8 landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar
- Vision: Identify-modell, FAISS, OCR alla testade
- API: Alla 7 integrationstester passerade
- Upplösare: Entitetsupplösning verifierad
2026-07-05 06:41:32 +00:00

85 lines
3.4 KiB
Python

"""SQLAlchemy-modeller för user management."""
import uuid
from datetime import datetime
from enum import Enum as PyEnum
from sqlalchemy import Column, String, DateTime, Boolean, ForeignKey, Enum, Text
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship
from app.database import Base
class UserRole(str, PyEnum):
ADMIN = "admin"
MANAGER = "manager"
ANALYST = "analyst"
VIEWER = "viewer"
class UserStatus(str, PyEnum):
ACTIVE = "active"
INACTIVE = "inactive"
PENDING = "pending" # Invited, not yet set password
class User(Base):
__tablename__ = "users"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
email = Column(String(255), unique=True, nullable=False, index=True)
hashed_password = Column(String(255), nullable=True) # NULL until invitation accepted
first_name = Column(String(100), nullable=False)
last_name = Column(String(100), nullable=False)
role = Column(Enum(UserRole), nullable=False, default=UserRole.VIEWER)
status = Column(Enum(UserStatus), nullable=False, default=UserStatus.PENDING)
is_superuser = Column(Boolean, default=False)
last_login_at = Column(DateTime(timezone=True), nullable=True)
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
updated_at = Column(DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow)
tenant_id = Column(UUID(as_uuid=True), ForeignKey("tenants.id"), nullable=True)
tenant = relationship("Tenant", back_populates="users")
invitations_sent = relationship("Invitation", foreign_keys="Invitation.invited_by_id", back_populates="inviter")
invitations_received = relationship("Invitation", foreign_keys="Invitation.email", primaryjoin="User.email == Invitation.email", viewonly=True)
def __repr__(self):
return f"<User {self.email} ({self.role.value})>"
class Tenant(Base):
__tablename__ = "tenants"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
name = Column(String(255), nullable=False)
slug = Column(String(100), unique=True, nullable=False, index=True)
description = Column(Text, nullable=True)
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
updated_at = Column(DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow)
users = relationship("User", back_populates="tenant")
def __repr__(self):
return f"<Tenant {self.name}>"
class Invitation(Base):
__tablename__ = "invitations"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
email = Column(String(255), nullable=False, index=True)
token = Column(String(255), unique=True, nullable=False, index=True)
role = Column(Enum(UserRole), nullable=False, default=UserRole.VIEWER)
tenant_id = Column(UUID(as_uuid=True), ForeignKey("tenants.id"), nullable=True)
invited_by_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
expires_at = Column(DateTime(timezone=True), nullable=False)
accepted_at = Column(DateTime(timezone=True), nullable=True)
created_at = Column(DateTime(timezone=True), default=datetime.utcnow)
inviter = relationship("User", foreign_keys=[invited_by_id], back_populates="invitations_sent")
tenant = relationship("Tenant")
def __repr__(self):
return f"<Invitation {self.email} ({self.role.value})>"