|
25 | 25 | from canonicaljson import json
|
26 | 26 | from prometheus_client import Counter
|
27 | 27 |
|
| 28 | +from twisted.enterprise.adbapi import Connection |
28 | 29 | from twisted.internet import defer
|
29 | 30 |
|
30 | 31 | import synapse.metrics
|
|
61 | 62 | ["type", "origin_type", "origin_entity"],
|
62 | 63 | )
|
63 | 64 |
|
| 65 | +STATE_EVENT_TYPES_TO_MARK_UNREAD = [ |
| 66 | + EventTypes.PowerLevels, |
| 67 | + EventTypes.Topic, |
| 68 | + EventTypes.Name, |
| 69 | +] |
| 70 | + |
64 | 71 |
|
65 | 72 | def encode_json(json_object):
|
66 | 73 | """
|
@@ -977,7 +984,7 @@ def _update_metadata_tables_txn(
|
977 | 984 | txn, events=[event for event, _ in events_and_contexts]
|
978 | 985 | )
|
979 | 986 |
|
980 |
| - for event, _ in events_and_contexts: |
| 987 | + for event, context in events_and_contexts: |
981 | 988 | if event.type == EventTypes.Name:
|
982 | 989 | # Insert into the event_search table.
|
983 | 990 | self._store_room_name_txn(txn, event)
|
@@ -1009,6 +1016,8 @@ def _update_metadata_tables_txn(
|
1009 | 1016 | if isinstance(expiry_ts, int) and not event.is_state():
|
1010 | 1017 | self._insert_event_expiry_txn(txn, event.event_id, expiry_ts)
|
1011 | 1018 |
|
| 1019 | + self._maybe_insert_unread_event_txn(txn, event, context) |
| 1020 | + |
1012 | 1021 | # Insert into the room_memberships table.
|
1013 | 1022 | self._store_room_members_txn(
|
1014 | 1023 | txn,
|
@@ -1614,3 +1623,72 @@ def f(txn, stream_ordering):
|
1614 | 1623 | await self.db.runInteraction("locally_reject_invite", f, stream_ordering)
|
1615 | 1624 |
|
1616 | 1625 | return stream_ordering
|
| 1626 | + |
| 1627 | + def _maybe_insert_unread_event_txn( |
| 1628 | + self, txn: Connection, event: EventBase, context: EventContext, |
| 1629 | + ): |
| 1630 | + """Mark the event as unread for every current member of the room if it passes the |
| 1631 | + conditions for that. |
| 1632 | +
|
| 1633 | + These conditions are: the event must either have a body, be an encrypted message, |
| 1634 | + or be either a power levels event, a room name event or a room topic event, and |
| 1635 | + must be neither rejected or soft-failed nor an edit or a notice. |
| 1636 | +
|
| 1637 | + Args: |
| 1638 | + txn: The transaction to use to retrieve room members and to mark the event |
| 1639 | + as unread. |
| 1640 | + event: The event to evaluate and maybe mark as unread. |
| 1641 | + context: The context in which the event was sent (used to figure out whether |
| 1642 | + the event has been rejected). |
| 1643 | + """ |
| 1644 | + content = event.content |
| 1645 | + |
| 1646 | + is_edit = ( |
| 1647 | + content.get("m.relates_to", {}).get("rel_type") == RelationTypes.REPLACE |
| 1648 | + ) |
| 1649 | + is_notice = not event.is_state() and content.get("msgtype") == "m.notice" |
| 1650 | + |
| 1651 | + # We don't want rejected or soft-failed events, edits or notices to be marked |
| 1652 | + # unread. |
| 1653 | + if ( |
| 1654 | + context.rejected |
| 1655 | + or is_edit |
| 1656 | + or is_notice |
| 1657 | + or event.internal_metadata.is_soft_failed() |
| 1658 | + ): |
| 1659 | + return |
| 1660 | + |
| 1661 | + body_exists = content.get("body") is not None |
| 1662 | + is_state_event_to_mark_unread = ( |
| 1663 | + event.is_state() and event.type in STATE_EVENT_TYPES_TO_MARK_UNREAD |
| 1664 | + ) |
| 1665 | + is_encrypted_message = ( |
| 1666 | + not event.is_state() and event.type == EventTypes.Encrypted |
| 1667 | + ) |
| 1668 | + |
| 1669 | + # We want to mark unread messages with a body, some state events (power levels, |
| 1670 | + # room name, room topic) and encrypted messages. |
| 1671 | + if not (body_exists or is_state_event_to_mark_unread or is_encrypted_message): |
| 1672 | + return |
| 1673 | + |
| 1674 | + # Get the list of users that are currently joined to the room. |
| 1675 | + users_in_room = self.db.simple_select_onecol_txn( |
| 1676 | + txn=txn, |
| 1677 | + table="room_memberships", |
| 1678 | + keyvalues={"membership": Membership.JOIN, "room_id": event.room_id}, |
| 1679 | + retcol="user_id", |
| 1680 | + ) |
| 1681 | + |
| 1682 | + # Mark the message as unread for every user currently in the room. |
| 1683 | + self.db.simple_insert_many_txn( |
| 1684 | + txn=txn, |
| 1685 | + table="unread_messages", |
| 1686 | + values=[ |
| 1687 | + { |
| 1688 | + "user_id": user_id, |
| 1689 | + "stream_ordering": event.internal_metadata.stream_ordering, |
| 1690 | + "room_id": event.room_id, |
| 1691 | + } |
| 1692 | + for user_id in users_in_room |
| 1693 | + ], |
| 1694 | + ) |
0 commit comments