destinyebuka commited on
Commit
2043cb2
·
1 Parent(s): 495207e
app/models/message.py CHANGED
@@ -43,6 +43,7 @@ class Message:
43
  "replied_to_sender": replied_to_sender, # Name of original sender
44
  "is_read": False,
45
  "read_at": None,
 
46
  # Edit tracking
47
  "is_edited": False,
48
  "edited_at": None,
@@ -163,13 +164,37 @@ class Message:
163
  # Reactions
164
  "reactions": message_doc.get("reactions", {}),
165
  "created_at": Message._serialize_datetime(message_doc.get("created_at")),
166
- # Status field for read receipts (derived from is_read)
167
- "status": "read" if message_doc.get("is_read", False) else "sent",
168
  # Action availability flags for frontend UI
169
  "can_edit": action_availability["can_edit"],
170
  "can_delete_for_everyone": action_availability["can_delete_for_everyone"],
171
  }
172
 
173
  return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
 
 
43
  "replied_to_sender": replied_to_sender, # Name of original sender
44
  "is_read": False,
45
  "read_at": None,
46
+ "read_by": [], # List of user IDs who have read this message
47
  # Edit tracking
48
  "is_edited": False,
49
  "edited_at": None,
 
164
  # Reactions
165
  "reactions": message_doc.get("reactions", {}),
166
  "created_at": Message._serialize_datetime(message_doc.get("created_at")),
167
+ # Status field for read receipts - calculated from sender's perspective
168
+ "status": Message._calculate_status(message_doc, for_user_id),
169
  # Action availability flags for frontend UI
170
  "can_edit": action_availability["can_edit"],
171
  "can_delete_for_everyone": action_availability["can_delete_for_everyone"],
172
  }
173
 
174
  return response
175
+
176
+ @staticmethod
177
+ def _calculate_status(message_doc: dict, for_user_id: Optional[str] = None) -> str:
178
+ """
179
+ Calculate message status from user's perspective.
180
+
181
+ For sender: Check if recipient has read it
182
+ For recipient: Always show as delivered (they have it)
183
+ """
184
+ sender_id = message_doc.get("sender_id")
185
+ read_by = message_doc.get("read_by", [])
186
+
187
+ # If viewing as sender
188
+ if for_user_id and for_user_id == sender_id:
189
+ # Check if anyone else has read it
190
+ other_readers = [uid for uid in read_by if uid != sender_id]
191
+ if other_readers:
192
+ return "read"
193
+ else:
194
+ return "delivered" # Sent and delivered but not read yet
195
+ else:
196
+ # Viewing as recipient - they have the message
197
+ return "delivered"
198
+
199
 
200
 
app/services/conversation_service.py CHANGED
@@ -1001,22 +1001,27 @@ If user says they found what they wanted or wants to stop notifications, use del
1001
  detail="You are not a participant in this conversation"
1002
  )
1003
 
1004
- # Mark messages as read
1005
  now = datetime.utcnow()
1006
- await db.messages.update_many(
1007
  {
1008
  "conversation_id": conversation_id,
1009
- "sender_id": {"$ne": current_user_id},
1010
- "is_read": False,
1011
  },
1012
  {
1013
  "$set": {
1014
- "is_read": True,
1015
  "read_at": now,
 
 
 
1016
  }
1017
  }
1018
  )
1019
 
 
 
1020
  # Reset unread count for current user
1021
  await db.conversations.update_one(
1022
  {"_id": ObjectId(conversation_id)},
 
1001
  detail="You are not a participant in this conversation"
1002
  )
1003
 
1004
+ # Mark messages as read and add user to read_by array
1005
  now = datetime.utcnow()
1006
+ result = await db.messages.update_many(
1007
  {
1008
  "conversation_id": conversation_id,
1009
+ "sender_id": {"$ne": current_user_id}, # Not sent by this user
1010
+ "read_by": {"$ne": current_user_id}, # Not already read by this user
1011
  },
1012
  {
1013
  "$set": {
1014
+ "is_read": True, # Keep for backwards compatibility
1015
  "read_at": now,
1016
+ },
1017
+ "$addToSet": {
1018
+ "read_by": current_user_id # Add user to read_by array (no duplicates)
1019
  }
1020
  }
1021
  )
1022
 
1023
+ logger.info(f"Marked {result.modified_count} messages as read, added {current_user_id} to read_by")
1024
+
1025
  # Reset unread count for current user
1026
  await db.conversations.update_one(
1027
  {"_id": ObjectId(conversation_id)},