doe/be/app/models.py
mohamad 4b7415e1c3 weeee💃
2025-03-30 16:02:49 +02:00

108 lines
4.2 KiB
Python

# app/models.py
import enum
from datetime import datetime
from sqlalchemy import (
Column,
Integer,
String,
DateTime,
ForeignKey,
Boolean,
Enum as SAEnum, # Renamed to avoid clash with Python's enum
UniqueConstraint,
event,
DDL
)
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func # For server_default=func.now()
from app.database import Base # Import Base from database setup
# Define Enum for User Roles in Groups
class UserRoleEnum(enum.Enum):
owner = "owner"
member = "member"
# --- User Model ---
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True, nullable=False)
password_hash = Column(String, nullable=False)
name = Column(String, index=True, nullable=True) # Allow nullable name initially
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
# Relationships
# Groups created by this user
created_groups = relationship("Group", back_populates="creator")
# Association object for group membership
group_associations = relationship("UserGroup", back_populates="user", cascade="all, delete-orphan")
# Items added by this user (Add later when Item model is defined)
# added_items = relationship("Item", foreign_keys="[Item.added_by_id]", back_populates="added_by_user")
# Items completed by this user (Add later)
# completed_items = relationship("Item", foreign_keys="[Item.completed_by_id]", back_populates="completed_by_user")
# Expense shares for this user (Add later)
# expense_shares = relationship("ExpenseShare", back_populates="user")
# Lists created by this user (Add later)
# created_lists = relationship("List", foreign_keys="[List.created_by_id]", back_populates="creator")
# --- Group Model ---
class Group(Base):
__tablename__ = "groups"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True, nullable=False)
created_by_id = Column(Integer, ForeignKey("users.id"), nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
# Relationships
# The user who created this group
creator = relationship("User", back_populates="created_groups")
# Association object for group membership
member_associations = relationship("UserGroup", back_populates="group", cascade="all, delete-orphan")
# Lists belonging to this group (Add later)
# lists = relationship("List", back_populates="group")
# --- UserGroup Association Model ---
class UserGroup(Base):
__tablename__ = "user_groups"
__table_args__ = (UniqueConstraint('user_id', 'group_id', name='uq_user_group'),) # Ensure user cannot be in same group twice
id = Column(Integer, primary_key=True, index=True) # Surrogate primary key
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
group_id = Column(Integer, ForeignKey("groups.id", ondelete="CASCADE"), nullable=False)
role = Column(SAEnum(UserRoleEnum), nullable=False, default=UserRoleEnum.member)
joined_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
# Relationships back to User and Group
user = relationship("User", back_populates="group_associations")
group = relationship("Group", back_populates="member_associations")
# --- Add other models below when needed ---
# class List(Base): ...
# class Item(Base): ...
# class Expense(Base): ...
# class ExpenseShare(Base): ...
# Optional: Trigger for automatically creating an 'owner' UserGroup entry when a Group is created.
# This requires importing event and DDL. It's advanced and DB-specific, might be simpler to handle in application logic.
# Example for PostgreSQL (might need adjustment):
# group_owner_trigger = DDL("""
# CREATE OR REPLACE FUNCTION add_group_owner()
# RETURNS TRIGGER AS $$
# BEGIN
# INSERT INTO user_groups (user_id, group_id, role, joined_at)
# VALUES (NEW.created_by_id, NEW.id, 'owner', NOW());
# RETURN NEW;
# END;
# $$ LANGUAGE plpgsql;
#
# CREATE TRIGGER trg_add_group_owner
# AFTER INSERT ON groups
# FOR EACH ROW EXECUTE FUNCTION add_group_owner();
# """)
# event.listen(Group.__table__, 'after_create', group_owner_trigger)