Skip to content

Commit 09b9756

Browse files
committed
Merge branch 'develop' into madlittlemods/per-tenant-logging-server-name
2 parents 02e4e5d + fd8fa97 commit 09b9756

File tree

4 files changed

+75
-20
lines changed

4 files changed

+75
-20
lines changed

changelog.d/18721.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix room upgrade `room_config` argument and documentation for `user_may_create_room` spam-checker callback.

docs/modules/spam_checker_callbacks.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,15 @@ _Changed in Synapse v1.132.0: Added the `room_config` argument. Callbacks that o
195195
async def user_may_create_room(user_id: str, room_config: synapse.module_api.JsonDict) -> Union["synapse.module_api.NOT_SPAM", "synapse.module_api.errors.Codes", bool]
196196
```
197197

198-
Called when processing a room creation request.
198+
Called when processing a room creation or room upgrade request.
199199

200200
The arguments passed to this callback are:
201201

202202
* `user_id`: The Matrix user ID of the user (e.g. `@alice:example.com`).
203-
* `room_config`: The contents of the body of a [/createRoom request](https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3createroom) as a dictionary.
203+
* `room_config`: The contents of the body of the [`/createRoom` request](https://spec.matrix.org/v1.15/client-server-api/#post_matrixclientv3createroom) as a dictionary.
204+
For a [room upgrade request](https://spec.matrix.org/v1.15/client-server-api/#post_matrixclientv3roomsroomidupgrade) it is a synthesised subset of what an equivalent
205+
`/createRoom` request would have looked like. Specifically, it contains the `creation_content` (linking to the previous room) and `initial_state` (containing a
206+
subset of the state of the previous room).
204207

205208
The callback must return one of:
206209
- `synapse.module_api.NOT_SPAM`, to allow the operation. Other callbacks may still

synapse/handlers/room.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ async def clone_existing_room(
597597
new_room_version,
598598
additional_creators=additional_creators,
599599
)
600-
initial_state = {}
600+
initial_state: MutableStateMap = {}
601601

602602
# Replicate relevant room events
603603
types_to_copy: List[Tuple[str, Optional[str]]] = [
@@ -693,14 +693,23 @@ async def clone_existing_room(
693693
additional_creators,
694694
)
695695

696-
# We construct what the body of a call to /createRoom would look like for passing
697-
# to the spam checker. We don't include a preset here, as we expect the
696+
# We construct a subset of what the body of a call to /createRoom would look like
697+
# for passing to the spam checker. We don't include a preset here, as we expect the
698698
# initial state to contain everything we need.
699+
# TODO: given we are upgrading, it would make sense to pass the room_version
700+
# TODO: the preset might be useful too
699701
spam_check = await self._spam_checker_module_callbacks.user_may_create_room(
700702
user_id,
701703
{
702704
"creation_content": creation_content,
703-
"initial_state": list(initial_state.items()),
705+
"initial_state": [
706+
{
707+
"type": state_key[0],
708+
"state_key": state_key[1],
709+
"content": event_content,
710+
}
711+
for state_key, event_content in initial_state.items()
712+
],
704713
},
705714
)
706715
if spam_check != self._spam_checker_module_callbacks.NOT_SPAM:

tests/module_api/test_spamchecker.py

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from twisted.internet.testing import MemoryReactor
1818

19+
from synapse.api.constants import EventContentFields, EventTypes
1920
from synapse.config.server import DEFAULT_ROOM_VERSION
2021
from synapse.rest import admin, login, room, room_upgrade_rest_servlet
2122
from synapse.server import HomeServer
@@ -51,8 +52,8 @@ def create_room(self, content: JsonDict) -> FakeChannel:
5152

5253
return channel
5354

54-
def test_may_user_create_room(self) -> None:
55-
"""Test that the may_user_create_room callback is called when a user
55+
def test_user_may_create_room(self) -> None:
56+
"""Test that the user_may_create_room callback is called when a user
5657
creates a room, and that it receives the correct parameters.
5758
"""
5859

@@ -67,16 +68,50 @@ async def user_may_create_room(
6768
user_may_create_room=user_may_create_room
6869
)
6970

70-
channel = self.create_room({"foo": "baa"})
71+
expected_room_config = {"foo": "baa"}
72+
channel = self.create_room(expected_room_config)
73+
7174
self.assertEqual(channel.code, 200)
7275
self.assertEqual(self.last_user_id, self.user_id)
73-
self.assertEqual(self.last_room_config["foo"], "baa")
76+
self.assertEqual(self.last_room_config, expected_room_config)
7477

75-
def test_may_user_create_room_on_upgrade(self) -> None:
76-
"""Test that the may_user_create_room callback is called when a room is upgraded."""
78+
def test_user_may_create_room_with_initial_state(self) -> None:
79+
"""Test that the user_may_create_room callback is called when a user
80+
creates a room with some initial state events, and that it receives the correct parameters.
81+
"""
82+
83+
async def user_may_create_room(
84+
user_id: str, room_config: JsonDict
85+
) -> Union[Literal["NOT_SPAM"], Codes]:
86+
self.last_room_config = room_config
87+
self.last_user_id = user_id
88+
return "NOT_SPAM"
89+
90+
self._module_api.register_spam_checker_callbacks(
91+
user_may_create_room=user_may_create_room
92+
)
93+
94+
expected_room_config = {
95+
"foo": "baa",
96+
"initial_state": [
97+
{
98+
"type": EventTypes.Topic,
99+
"content": {EventContentFields.TOPIC: "foo"},
100+
}
101+
],
102+
}
103+
channel = self.create_room(expected_room_config)
104+
105+
self.assertEqual(channel.code, 200)
106+
self.assertEqual(self.last_user_id, self.user_id)
107+
self.assertEqual(self.last_room_config, expected_room_config)
108+
109+
def test_user_may_create_room_on_upgrade(self) -> None:
110+
"""Test that the user_may_create_room callback is called when a room is upgraded."""
77111

78112
# First, create a room to upgrade.
79-
channel = self.create_room({"topic": "foo"})
113+
channel = self.create_room({EventContentFields.TOPIC: "foo"})
114+
80115
self.assertEqual(channel.code, 200)
81116
room_id = channel.json_body["room_id"]
82117

@@ -107,13 +142,15 @@ async def user_may_create_room(
107142
# Check that the initial state received by callback contains the topic event.
108143
self.assertTrue(
109144
any(
110-
event[0][0] == "m.room.topic" and event[1].get("topic") == "foo"
145+
event.get("type") == EventTypes.Topic
146+
and event.get("state_key") == ""
147+
and event.get("content").get(EventContentFields.TOPIC) == "foo"
111148
for event in self.last_room_config["initial_state"]
112149
)
113150
)
114151

115-
def test_may_user_create_room_disallowed(self) -> None:
116-
"""Test that the codes response from may_user_create_room callback is respected
152+
def test_user_may_create_room_disallowed(self) -> None:
153+
"""Test that the codes response from user_may_create_room callback is respected
117154
and returned via the API.
118155
"""
119156

@@ -128,14 +165,16 @@ async def user_may_create_room(
128165
user_may_create_room=user_may_create_room
129166
)
130167

131-
channel = self.create_room({"foo": "baa"})
168+
expected_room_config = {"foo": "baa"}
169+
channel = self.create_room(expected_room_config)
170+
132171
self.assertEqual(channel.code, 403)
133172
self.assertEqual(channel.json_body["errcode"], Codes.UNAUTHORIZED)
134173
self.assertEqual(self.last_user_id, self.user_id)
135-
self.assertEqual(self.last_room_config["foo"], "baa")
174+
self.assertEqual(self.last_room_config, expected_room_config)
136175

137-
def test_may_user_create_room_compatibility(self) -> None:
138-
"""Test that the may_user_create_room callback is called when a user
176+
def test_user_may_create_room_compatibility(self) -> None:
177+
"""Test that the user_may_create_room callback is called when a user
139178
creates a room for a module that uses the old callback signature
140179
(without the `room_config` parameter)
141180
"""
@@ -151,6 +190,7 @@ async def user_may_create_room(
151190
)
152191

153192
channel = self.create_room({"foo": "baa"})
193+
154194
self.assertEqual(channel.code, 200)
155195
self.assertEqual(self.last_user_id, self.user_id)
156196

@@ -178,6 +218,7 @@ async def user_may_send_state_event(
178218
)
179219

180220
channel = self.create_room({})
221+
181222
self.assertEqual(channel.code, 200)
182223

183224
room_id = channel.json_body["room_id"]
@@ -222,6 +263,7 @@ async def user_may_send_state_event(
222263
)
223264

224265
channel = self.create_room({})
266+
225267
self.assertEqual(channel.code, 200)
226268

227269
room_id = channel.json_body["room_id"]

0 commit comments

Comments
 (0)