"""Collaboration models for VoIdea. Voting, threaded comments, activity log, and notifications. """ from typing import Optional from sqlalchemy import Boolean, ForeignKey, String, Text, UniqueConstraint from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy.orm import Mapped, mapped_column from app.core.base import SQLBase, TimestampMixin, UUIDMixin class IdeaVote(SQLBase, UUIDMixin, TimestampMixin): __tablename__ = "idea_votes" idea_id: Mapped[UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("ideas.id", ondelete="CASCADE"), nullable=False, index=True, ) user_id: Mapped[UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True, ) vote: Mapped[str] = mapped_column( String(4), nullable=False ) __table_args__ = ( UniqueConstraint("idea_id", "user_id", name="uq_idea_user_vote"), ) class IdeaComment(SQLBase, UUIDMixin, TimestampMixin): __tablename__ = "idea_comments" idea_id: Mapped[UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("ideas.id", ondelete="CASCADE"), nullable=False, index=True, ) user_id: Mapped[UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True, ) content: Mapped[str] = mapped_column(Text, nullable=False) parent_id: Mapped[Optional[UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("idea_comments.id", ondelete="CASCADE"), nullable=True, ) class IdeaActivity(SQLBase, UUIDMixin, TimestampMixin): __tablename__ = "idea_activities" idea_id: Mapped[UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("ideas.id", ondelete="CASCADE"), nullable=False, index=True, ) user_id: Mapped[Optional[UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True, ) action: Mapped[str] = mapped_column( String(50), nullable=False ) details: Mapped[Optional[dict]] = mapped_column( JSONB, nullable=True ) class Notification(SQLBase, UUIDMixin, TimestampMixin): __tablename__ = "notifications" user_id: Mapped[UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True, ) type: Mapped[str] = mapped_column( String(50), nullable=False, index=True ) title: Mapped[str] = mapped_column( String(255), nullable=False ) body: Mapped[str] = mapped_column(Text, nullable=False) link: Mapped[Optional[str]] = mapped_column( String(512), nullable=True ) is_read: Mapped[bool] = mapped_column( Boolean, default=False, nullable=False, index=True )