06/15 Phase 3 codes
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
"""Messaging models: Conversation (per listing, per buyer/seller pair) + Message.
|
||||
|
||||
One conversation per (listing, buyer) pair — enforced by unique constraint.
|
||||
The seller is always listing.user; buyer is any other authenticated user.
|
||||
Messages are append-only; soft-delete not needed at Phase 3.
|
||||
"""
|
||||
from datetime import datetime
|
||||
from app.extensions import db
|
||||
|
||||
|
||||
class Conversation(db.Model):
|
||||
__tablename__ = "conversations"
|
||||
__table_args__ = (
|
||||
db.UniqueConstraint("listing_id", "buyer_id", name="uq_conv_listing_buyer"),
|
||||
)
|
||||
|
||||
id = db.Column(db.BigInteger().with_variant(db.Integer, "sqlite"),
|
||||
primary_key=True, autoincrement=True)
|
||||
listing_id = db.Column(db.BigInteger().with_variant(db.Integer, "sqlite"),
|
||||
db.ForeignKey("listings.id"), nullable=False, index=True)
|
||||
buyer_id = db.Column(db.BigInteger().with_variant(db.Integer, "sqlite"),
|
||||
db.ForeignKey("users.id"), nullable=False, index=True)
|
||||
seller_id = db.Column(db.BigInteger().with_variant(db.Integer, "sqlite"),
|
||||
db.ForeignKey("users.id"), nullable=False, index=True)
|
||||
last_message_at = db.Column(db.DateTime, nullable=True, index=True)
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
||||
|
||||
listing = db.relationship("Listing",
|
||||
backref=db.backref("conversations", lazy="dynamic"))
|
||||
buyer = db.relationship("User", foreign_keys=[buyer_id],
|
||||
backref=db.backref("bought_conversations", lazy="dynamic"))
|
||||
seller = db.relationship("User", foreign_keys=[seller_id],
|
||||
backref=db.backref("sold_conversations", lazy="dynamic"))
|
||||
messages = db.relationship("Message", back_populates="conversation",
|
||||
order_by="Message.created_at",
|
||||
cascade="all, delete-orphan", lazy="selectin")
|
||||
|
||||
def other_party(self, user):
|
||||
return self.seller if user.id == self.buyer_id else self.buyer
|
||||
|
||||
def unread_count(self, user):
|
||||
return sum(1 for m in self.messages
|
||||
if m.sender_id != user.id and m.read_at is None)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Conversation {self.id} L{self.listing_id}>"
|
||||
|
||||
|
||||
class Message(db.Model):
|
||||
__tablename__ = "messages"
|
||||
|
||||
id = db.Column(db.BigInteger().with_variant(db.Integer, "sqlite"),
|
||||
primary_key=True, autoincrement=True)
|
||||
conversation_id = db.Column(db.BigInteger().with_variant(db.Integer, "sqlite"),
|
||||
db.ForeignKey("conversations.id"),
|
||||
nullable=False, index=True)
|
||||
sender_id = db.Column(db.BigInteger().with_variant(db.Integer, "sqlite"),
|
||||
db.ForeignKey("users.id"), nullable=False)
|
||||
body = db.Column(db.Text, nullable=False)
|
||||
read_at = db.Column(db.DateTime, nullable=True)
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
||||
|
||||
conversation = db.relationship("Conversation", back_populates="messages")
|
||||
sender = db.relationship("User",
|
||||
backref=db.backref("sent_messages", lazy="dynamic"))
|
||||
|
||||
@property
|
||||
def is_read(self):
|
||||
return self.read_at is not None
|
||||
|
||||
def mark_read(self):
|
||||
if self.read_at is None:
|
||||
self.read_at = datetime.utcnow()
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Message {self.id} C{self.conversation_id}>"
|
||||
Reference in New Issue
Block a user