108 lines
4.2 KiB
Python
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) |