Files
service-finder/backend/app/models/identity.py

146 lines
6.8 KiB
Python

import uuid
import enum
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, JSON, Numeric, text, Enum, BigInteger, UniqueConstraint
from sqlalchemy.orm import relationship
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
from sqlalchemy.sql import func
from app.db.base_class import Base
class UserRole(str, enum.Enum):
superadmin = "superadmin"
admin = "admin"
region_admin = "region_admin"
country_admin = "country_admin"
moderator = "moderator"
sales_agent = "sales_agent"
user = "user"
service_owner = "service_owner"
fleet_manager = "fleet_manager"
driver = "driver"
class Person(Base):
"""
Természetes személy identitása. A DNS szint.
Itt tároljuk az örök adatokat, amik nem vesznek el account törléskor.
"""
__tablename__ = "persons"
__table_args__ = {"schema": "data", "extend_existing": True}
id = Column(BigInteger, primary_key=True, index=True)
id_uuid = Column(PG_UUID(as_uuid=True), default=uuid.uuid4, unique=True, nullable=False)
address_id = Column(PG_UUID(as_uuid=True), ForeignKey("data.addresses.id"), nullable=True)
# --- KRITIKUS: EGYEDI AZONOSÍTÓ HASH (Normalizált adatokból) ---
identity_hash = Column(String(64), unique=True, index=True, nullable=True)
last_name = Column(String, nullable=False)
first_name = Column(String, nullable=False)
phone = Column(String, nullable=True)
mothers_last_name = Column(String)
mothers_first_name = Column(String)
birth_place = Column(String)
birth_date = Column(DateTime)
identity_docs = Column(JSON, server_default=text("'{}'::jsonb"))
ice_contact = Column(JSON, server_default=text("'{}'::jsonb"))
# --- ÖRÖK ADATOK (Person szint) ---
lifetime_xp = Column(BigInteger, server_default=text("0"))
penalty_points = Column(Integer, server_default=text("0")) # 0-3 szint
social_reputation = Column(Numeric(3, 2), server_default=text("1.00")) # 1.00 = 100%
is_sales_agent = Column(Boolean, server_default=text("false"))
is_active = Column(Boolean, default=True, nullable=False)
is_ghost = Column(Boolean, default=False, nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
users = relationship("User", back_populates="person")
memberships = relationship("OrganizationMember", back_populates="person")
class User(Base):
"""
Login entitás. Bármikor törölhető (GDPR), de Person-höz kötött.
"""
__tablename__ = "users"
__table_args__ = {"schema": "data", "extend_existing": True}
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True, nullable=False)
hashed_password = Column(String, nullable=True)
role = Column(Enum(UserRole), default=UserRole.user)
person_id = Column(BigInteger, ForeignKey("data.persons.id"), nullable=True)
# --- ELŐFIZETÉS ÉS VIP (Időkorlátos logika) ---
subscription_plan = Column(String(30), server_default=text("'FREE'"))
subscription_expires_at = Column(DateTime(timezone=True), nullable=True)
is_vip = Column(Boolean, server_default=text("false"))
# --- REFERRAL ÉS SALES (Üzletkötői hálózat) ---
referral_code = Column(String(20), unique=True)
referred_by_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
# Farming üzletkötő (Átruházható cégkezelő)
current_sales_agent_id = Column(Integer, ForeignKey("data.users.id"), nullable=True)
# Szervezeti kapcsolat
owned_organizations = relationship("Organization", back_populates="owner")
# Ez a sor felelős a gamification.py-val való hídért
stats = relationship("UserStats", back_populates="user", uselist=False, cascade="all, delete-orphan")
ownership_history = relationship("VehicleOwnership", back_populates="user")
is_active = Column(Boolean, default=False)
is_deleted = Column(Boolean, default=False)
folder_slug = Column(String(12), unique=True, index=True)
preferred_language = Column(String(5), server_default="hu")
region_code = Column(String(5), server_default="HU")
preferred_currency = Column(String(3), server_default="HUF")
scope_level = Column(String(30), server_default="individual") # global, region, country, entity, individual
scope_id = Column(String(50))
custom_permissions = Column(JSON, server_default=text("'{}'::jsonb"))
created_at = Column(DateTime(timezone=True), server_default=func.now())
person = relationship("Person", back_populates="users")
wallet = relationship("Wallet", back_populates="user", uselist=False)
social_accounts = relationship("SocialAccount", back_populates="user", cascade="all, delete-orphan")
class Wallet(Base):
""" A 3-as felosztású pénztárca. """
__tablename__ = "wallets"
__table_args__ = {"schema": "data", "extend_existing": True}
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("data.users.id"), unique=True)
earned_credits = Column(Numeric(18, 4), server_default=text("0")) # Munka + Referral
purchased_credits = Column(Numeric(18, 4), server_default=text("0")) # Vásárolt
service_coins = Column(Numeric(18, 4), server_default=text("0")) # Csak hirdetésre!
currency = Column(String(3), default="HUF")
user = relationship("User", back_populates="wallet")
# ... (VerificationToken és SocialAccount változatlan) ...
class VerificationToken(Base):
__tablename__ = "verification_tokens"; __table_args__ = {"schema": "data"}
id = Column(Integer, primary_key=True, index=True)
token = Column(PG_UUID(as_uuid=True), default=uuid.uuid4, unique=True, nullable=False)
user_id = Column(Integer, ForeignKey("data.users.id", ondelete="CASCADE"), nullable=False)
token_type = Column(String(20), nullable=False); created_at = Column(DateTime(timezone=True), server_default=func.now())
expires_at = Column(DateTime(timezone=True), nullable=False); is_used = Column(Boolean, default=False)
class SocialAccount(Base):
__tablename__ = "social_accounts"
__table_args__ = (UniqueConstraint('provider', 'social_id', name='uix_social_provider_id'), {"schema": "data"})
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("data.users.id", ondelete="CASCADE"), nullable=False)
provider = Column(String(50), nullable=False); social_id = Column(String(255), nullable=False, index=True); email = Column(String(255), nullable=False)
extra_data = Column(JSON, server_default=text("'{}'::jsonb")); created_at = Column(DateTime(timezone=True), server_default=func.now())
user = relationship("User", back_populates="social_accounts")