MSC4076: Add disable_badge_count to pusher configuration (#17975)

This PR implements [MSC4076: Let E2EE clients calculate app badge counts
themselves
(disable_badge_count)](https://github.com/matrix-org/matrix-spec-proposals/pull/4076).
This commit is contained in:
manuroe 2024-12-03 23:58:43 +01:00 committed by GitHub
parent 657dd5151e
commit abf44ad324
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 98 additions and 6 deletions

View file

@ -0,0 +1 @@
[MSC4076](https://github.com/matrix-org/matrix-spec-proposals/pull/4076): Add `disable_badge_count` to pusher configuration.

View file

@ -448,3 +448,6 @@ class ExperimentalConfig(Config):
# MSC4222: Adding `state_after` to sync v2 # MSC4222: Adding `state_after` to sync v2
self.msc4222_enabled: bool = experimental.get("msc4222_enabled", False) self.msc4222_enabled: bool = experimental.get("msc4222_enabled", False)
# MSC4076: Add `disable_badge_count`` to pusher configuration
self.msc4076_enabled: bool = experimental.get("msc4076_enabled", False)

View file

@ -127,6 +127,11 @@ class HttpPusher(Pusher):
if self.data is None: if self.data is None:
raise PusherConfigException("'data' key can not be null for HTTP pusher") raise PusherConfigException("'data' key can not be null for HTTP pusher")
# Check if badge counts should be disabled for this push gateway
self.disable_badge_count = self.hs.config.experimental.msc4076_enabled and bool(
self.data.get("org.matrix.msc4076.disable_badge_count", False)
)
self.name = "%s/%s/%s" % ( self.name = "%s/%s/%s" % (
pusher_config.user_name, pusher_config.user_name,
pusher_config.app_id, pusher_config.app_id,
@ -461,9 +466,10 @@ class HttpPusher(Pusher):
content: JsonDict = { content: JsonDict = {
"event_id": event.event_id, "event_id": event.event_id,
"room_id": event.room_id, "room_id": event.room_id,
"counts": {"unread": badge},
"prio": priority, "prio": priority,
} }
if not self.disable_badge_count:
content["counts"] = {"unread": badge}
# event_id_only doesn't include the tweaks, so override them. # event_id_only doesn't include the tweaks, so override them.
tweaks = {} tweaks = {}
else: else:
@ -478,10 +484,10 @@ class HttpPusher(Pusher):
"type": event.type, "type": event.type,
"sender": event.user_id, "sender": event.user_id,
"prio": priority, "prio": priority,
"counts": { }
if not self.disable_badge_count:
content["counts"] = {
"unread": badge, "unread": badge,
# 'missed_calls': 2
},
} }
if event.type == "m.room.member" and event.is_state(): if event.type == "m.room.member" and event.is_state():
content["membership"] = event.content["membership"] content["membership"] = event.content["membership"]

View file

@ -17,9 +17,11 @@
# [This file includes modifications made by New Vector Limited] # [This file includes modifications made by New Vector Limited]
# #
# #
from typing import Any, List, Tuple from typing import Any, Dict, List, Tuple
from unittest.mock import Mock from unittest.mock import Mock
from parameterized import parameterized
from twisted.internet.defer import Deferred from twisted.internet.defer import Deferred
from twisted.test.proto_helpers import MemoryReactor from twisted.test.proto_helpers import MemoryReactor
@ -1085,3 +1087,83 @@ class HTTPPusherTests(HomeserverTestCase):
self.pump() self.pump()
self.assertEqual(len(self.push_attempts), 11) self.assertEqual(len(self.push_attempts), 11)
@parameterized.expand(
[
# Badge count disabled
(True, True),
(True, False),
# Badge count enabled
(False, True),
(False, False),
]
)
@override_config({"experimental_features": {"msc4076_enabled": True}})
def test_msc4076_badge_count(
self, disable_badge_count: bool, event_id_only: bool
) -> None:
# Register the user who gets notified
user_id = self.register_user("user", "pass")
access_token = self.login("user", "pass")
# Register the user who sends the message
other_user_id = self.register_user("otheruser", "pass")
other_access_token = self.login("otheruser", "pass")
# Register the pusher with disable_badge_count set to True
user_tuple = self.get_success(
self.hs.get_datastores().main.get_user_by_access_token(access_token)
)
assert user_tuple is not None
device_id = user_tuple.device_id
# Set the push data dict based on test input parameters
push_data: Dict[str, Any] = {
"url": "http://example.com/_matrix/push/v1/notify",
}
if disable_badge_count:
push_data["org.matrix.msc4076.disable_badge_count"] = True
if event_id_only:
push_data["format"] = "event_id_only"
self.get_success(
self.hs.get_pusherpool().add_or_update_pusher(
user_id=user_id,
device_id=device_id,
kind="http",
app_id="m.http",
app_display_name="HTTP Push Notifications",
device_display_name="pushy push",
pushkey="a@example.com",
lang=None,
data=push_data,
)
)
# Create a room
room = self.helper.create_room_as(user_id, tok=access_token)
# The other user joins
self.helper.join(room=room, user=other_user_id, tok=other_access_token)
# The other user sends a message
self.helper.send(room, body="Hi!", tok=other_access_token)
# Advance time a bit, so the pusher will register something has happened
self.pump()
# One push was attempted to be sent
self.assertEqual(len(self.push_attempts), 1)
self.assertEqual(
self.push_attempts[0][1], "http://example.com/_matrix/push/v1/notify"
)
if disable_badge_count:
# Verify that the notification DOESN'T contain a counts field
self.assertNotIn("counts", self.push_attempts[0][2]["notification"])
else:
# Ensure that the notification DOES contain a counts field
self.assertIn("counts", self.push_attempts[0][2]["notification"])
self.assertEqual(
self.push_attempts[0][2]["notification"]["counts"]["unread"], 1
)