Coverage for src/couchers/models/discussions.py: 100%
59 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-12-25 10:58 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-12-25 10:58 +0000
1from datetime import datetime
3from sqlalchemy import BigInteger, DateTime, ForeignKey, String, UniqueConstraint, func
4from sqlalchemy.orm import Mapped, backref, column_property, mapped_column, relationship
6from couchers.models.base import Base, communities_seq
9class Discussion(Base):
10 """
11 forum board
12 """
14 __tablename__ = "discussions"
16 id: Mapped[int] = mapped_column(
17 BigInteger, communities_seq, primary_key=True, server_default=communities_seq.next_value()
18 )
20 title: Mapped[str] = mapped_column(String)
21 content: Mapped[str] = mapped_column(String)
22 thread_id: Mapped[int] = mapped_column(ForeignKey("threads.id"), unique=True)
23 created: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
25 creator_user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
26 owner_cluster_id: Mapped[int] = mapped_column(ForeignKey("clusters.id"), index=True)
28 slug = column_property(func.slugify(title))
30 thread = relationship("Thread", backref="discussion", uselist=False)
32 subscribers = relationship("User", backref="discussions", secondary="discussion_subscriptions", viewonly=True)
34 creator_user = relationship("User", backref="created_discussions", foreign_keys="Discussion.creator_user_id")
35 owner_cluster = relationship("Cluster", backref=backref("owned_discussions", lazy="dynamic"), uselist=False)
38class DiscussionSubscription(Base):
39 """
40 users subscriptions to discussions
41 """
43 __tablename__ = "discussion_subscriptions"
44 __table_args__ = (UniqueConstraint("discussion_id", "user_id"),)
46 id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
48 user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
49 discussion_id: Mapped[int] = mapped_column(ForeignKey("discussions.id"), index=True)
50 joined: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
51 left: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
53 user = relationship("User", backref="discussion_subscriptions")
54 discussion = relationship("Discussion", backref="discussion_subscriptions")
57class Thread(Base):
58 """
59 Thread
60 """
62 __tablename__ = "threads"
64 id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
66 created: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
67 deleted: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
70class Comment(Base):
71 """
72 Comment
73 """
75 __tablename__ = "comments"
77 id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
79 thread_id: Mapped[int] = mapped_column(ForeignKey("threads.id"), index=True)
80 author_user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
81 content: Mapped[str] = mapped_column(String) # CommonMark without images
82 created: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
83 deleted: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
85 thread = relationship("Thread", backref="comments")
88class Reply(Base):
89 """
90 Reply
91 """
93 __tablename__ = "replies"
95 id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
97 comment_id: Mapped[int] = mapped_column(ForeignKey("comments.id"), index=True)
98 author_user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
99 content: Mapped[str] = mapped_column(String) # CommonMark without images
100 created: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
101 deleted: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
103 comment = relationship("Comment", backref="replies")
106class ClusterDiscussionAssociation(Base):
107 """
108 discussions related to clusters
109 """
111 __tablename__ = "cluster_discussion_associations"
112 __table_args__ = (UniqueConstraint("discussion_id", "cluster_id"),)
114 id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
116 discussion_id: Mapped[int] = mapped_column(ForeignKey("discussions.id"), index=True)
117 cluster_id: Mapped[int] = mapped_column(ForeignKey("clusters.id"), index=True)
119 discussion = relationship("Discussion", backref="cluster_discussion_associations")
120 cluster = relationship("Cluster", backref="cluster_discussion_associations")