Coverage for app / backend / src / couchers / models / mod_note.py: 95%
22 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 06:18 +0000
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 06:18 +0000
1from datetime import datetime
2from typing import TYPE_CHECKING
4from sqlalchemy import BigInteger, DateTime, ForeignKey, Index, String, func
5from sqlalchemy.ext.hybrid import hybrid_property
6from sqlalchemy.orm import Mapped, mapped_column, relationship
8from couchers.models.base import Base
10if TYPE_CHECKING:
11 from couchers.models.users import User
14class ModNote(Base, kw_only=True):
15 """
16 A moderator note to a user. This could be a warning, just a note "hey, we did X", or any other similar message.
18 The user has to read and "acknowledge" the note before continuing onto the platform, and being un-jailed.
19 """
21 __tablename__ = "mod_notes"
23 id: Mapped[int] = mapped_column(BigInteger, primary_key=True, init=False)
24 user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
26 created: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), init=False)
27 acknowledged: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), default=None)
29 # this is an internal ID to allow the mods to track different types of notes
30 internal_id: Mapped[str] = mapped_column(String)
31 # the admin that left this note
32 creator_user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
34 note_content: Mapped[str] = mapped_column(String) # CommonMark without images
36 user: Mapped[User] = relationship(init=False, foreign_keys="ModNote.user_id", back_populates="mod_notes")
38 def __repr__(self) -> str:
39 return f"ModeNote(id={self.id}, user={self.user}, created={self.created}, ack'd={self.acknowledged})"
41 @hybrid_property
42 def is_pending(self) -> bool:
43 return self.acknowledged == None
45 __table_args__ = (
46 # used to look up pending notes
47 Index(
48 "ix_mod_notes_unacknowledged",
49 user_id,
50 postgresql_where=acknowledged == None,
51 ),
52 )