From d6e194b2bc1b71c04d55617359b43f4dde5bc593 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 4 Dec 2023 04:36:12 -0700 Subject: Implement MSC4069: Inhibit profile propagation (#16636) MSC: https://github.com/matrix-org/matrix-spec-proposals/pull/4069 --- tests/rest/client/test_profile.py | 160 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) (limited to 'tests/rest') diff --git a/tests/rest/client/test_profile.py b/tests/rest/client/test_profile.py index 8f923fd40f..eb0fa00bb3 100644 --- a/tests/rest/client/test_profile.py +++ b/tests/rest/client/test_profile.py @@ -312,6 +312,166 @@ class ProfileTestCase(unittest.HomeserverTestCase): ) self.assertEqual(channel.code, 200, channel.result) + @unittest.override_config( + {"experimental_features": {"msc4069_profile_inhibit_propagation": True}} + ) + def test_msc4069_inhibit_propagation(self) -> None: + """Tests to ensure profile update propagation can be inhibited.""" + for prop in ["avatar_url", "displayname"]: + room_id = self.helper.create_room_as(tok=self.owner_tok) + + channel = self.make_request( + "PUT", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + content={"membership": "join", prop: "mxc://my.server/existing"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + channel = self.make_request( + "PUT", + f"/profile/{self.owner}/{prop}?org.matrix.msc4069.propagate=false", + content={prop: "http://my.server/pic.gif"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + res = ( + self._get_avatar_url() + if prop == "avatar_url" + else self._get_displayname() + ) + self.assertEqual(res, "http://my.server/pic.gif") + + channel = self.make_request( + "GET", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + self.assertEqual(channel.json_body.get(prop), "mxc://my.server/existing") + + def test_msc4069_inhibit_propagation_disabled(self) -> None: + """Tests to ensure profile update propagation inhibit flags are ignored when the + experimental flag is not enabled. + """ + for prop in ["avatar_url", "displayname"]: + room_id = self.helper.create_room_as(tok=self.owner_tok) + + channel = self.make_request( + "PUT", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + content={"membership": "join", prop: "mxc://my.server/existing"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + channel = self.make_request( + "PUT", + f"/profile/{self.owner}/{prop}?org.matrix.msc4069.propagate=false", + content={prop: "http://my.server/pic.gif"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + res = ( + self._get_avatar_url() + if prop == "avatar_url" + else self._get_displayname() + ) + self.assertEqual(res, "http://my.server/pic.gif") + + channel = self.make_request( + "GET", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + # The ?propagate=false should be ignored by the server because the config flag + # isn't enabled. + self.assertEqual(channel.json_body.get(prop), "http://my.server/pic.gif") + + def test_msc4069_inhibit_propagation_default(self) -> None: + """Tests to ensure profile update propagation happens by default.""" + for prop in ["avatar_url", "displayname"]: + room_id = self.helper.create_room_as(tok=self.owner_tok) + + channel = self.make_request( + "PUT", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + content={"membership": "join", prop: "mxc://my.server/existing"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + channel = self.make_request( + "PUT", + f"/profile/{self.owner}/{prop}", + content={prop: "http://my.server/pic.gif"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + res = ( + self._get_avatar_url() + if prop == "avatar_url" + else self._get_displayname() + ) + self.assertEqual(res, "http://my.server/pic.gif") + + channel = self.make_request( + "GET", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + # The ?propagate=false should be ignored by the server because the config flag + # isn't enabled. + self.assertEqual(channel.json_body.get(prop), "http://my.server/pic.gif") + + @unittest.override_config( + {"experimental_features": {"msc4069_profile_inhibit_propagation": True}} + ) + def test_msc4069_inhibit_propagation_like_default(self) -> None: + """Tests to ensure clients can request explicit profile propagation.""" + for prop in ["avatar_url", "displayname"]: + room_id = self.helper.create_room_as(tok=self.owner_tok) + + channel = self.make_request( + "PUT", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + content={"membership": "join", prop: "mxc://my.server/existing"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + channel = self.make_request( + "PUT", + f"/profile/{self.owner}/{prop}?org.matrix.msc4069.propagate=true", + content={prop: "http://my.server/pic.gif"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + res = ( + self._get_avatar_url() + if prop == "avatar_url" + else self._get_displayname() + ) + self.assertEqual(res, "http://my.server/pic.gif") + + channel = self.make_request( + "GET", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + # The client requested ?propagate=true, so it should have happened. + self.assertEqual(channel.json_body.get(prop), "http://my.server/pic.gif") + def _setup_local_files(self, names_and_props: Dict[str, Dict[str, Any]]) -> None: """Stores metadata about files in the database. -- cgit 1.5.1 From 9e7f80037d08619cdd193831540d34e9ed5aacd7 Mon Sep 17 00:00:00 2001 From: Mathieu Velten Date: Mon, 4 Dec 2023 13:31:42 +0100 Subject: Server notices: add an autojoin setting for the notices room (#16699) Co-authored-by: Patrick Cloke --- changelog.d/16699.feature | 1 + docs/server_notices.md | 3 +++ docs/usage/configuration/config_documentation.md | 3 +++ synapse/config/server_notices.py | 2 ++ synapse/server_notices/server_notices_manager.py | 15 ++++++++++++- tests/rest/admin/test_server_notice.py | 27 ++++++++++++++++++++++++ 6 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 changelog.d/16699.feature (limited to 'tests/rest') diff --git a/changelog.d/16699.feature b/changelog.d/16699.feature new file mode 100644 index 0000000000..7ede50f326 --- /dev/null +++ b/changelog.d/16699.feature @@ -0,0 +1 @@ +Add an autojoin setting for the notices room so users get joined directly instead of receiving an invite. diff --git a/docs/server_notices.md b/docs/server_notices.md index 339d10a0ab..aae25d23b8 100644 --- a/docs/server_notices.md +++ b/docs/server_notices.md @@ -46,6 +46,7 @@ server_notices: system_mxid_display_name: "Server Notices" system_mxid_avatar_url: "mxc://server.com/oumMVlgDnLYFaPVkExemNVVZ" room_name: "Server Notices" + auto_join: true ``` The only compulsory setting is `system_mxid_localpart`, which defines the user @@ -55,6 +56,8 @@ room which will be created. `system_mxid_display_name` and `system_mxid_avatar_url` can be used to set the displayname and avatar of the Server Notices user. +`auto_join` will autojoin users to the notices room instead of sending an invite. + ## Sending notices To send server notices to users you can use the diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 7c4e742cd5..812a7d429b 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -3815,6 +3815,8 @@ Sub-options for this setting include: * `system_mxid_display_name`: set the display name of the "notices" user * `system_mxid_avatar_url`: set the avatar for the "notices" user * `room_name`: set the room name of the server notices room +* `auto_join`: boolean. If true, the user will be automatically joined to the room instead of being invited. + Defaults to false. _Added in Synapse 1.98.0._ Example configuration: ```yaml @@ -3823,6 +3825,7 @@ server_notices: system_mxid_display_name: "Server Notices" system_mxid_avatar_url: "mxc://server.com/oumMVlgDnLYFaPVkExemNVVZ" room_name: "Server Notices" + auto_join: true ``` --- ### `enable_room_list_search` diff --git a/synapse/config/server_notices.py b/synapse/config/server_notices.py index ce041abe9b..a8badba0f8 100644 --- a/synapse/config/server_notices.py +++ b/synapse/config/server_notices.py @@ -48,6 +48,7 @@ class ServerNoticesConfig(Config): self.server_notices_mxid_display_name: Optional[str] = None self.server_notices_mxid_avatar_url: Optional[str] = None self.server_notices_room_name: Optional[str] = None + self.server_notices_auto_join: bool = False def read_config(self, config: JsonDict, **kwargs: Any) -> None: c = config.get("server_notices") @@ -62,3 +63,4 @@ class ServerNoticesConfig(Config): self.server_notices_mxid_avatar_url = c.get("system_mxid_avatar_url", None) # todo: i18n self.server_notices_room_name = c.get("room_name", "Server Notices") + self.server_notices_auto_join = c.get("auto_join", False) diff --git a/synapse/server_notices/server_notices_manager.py b/synapse/server_notices/server_notices_manager.py index 44b999677a..2353b5d47f 100644 --- a/synapse/server_notices/server_notices_manager.py +++ b/synapse/server_notices/server_notices_manager.py @@ -224,14 +224,27 @@ class ServerNoticesManager: if room.room_id == room_id: return + user_id_obj = UserID.from_string(user_id) await self._room_member_handler.update_membership( requester=requester, - target=UserID.from_string(user_id), + target=user_id_obj, room_id=room_id, action="invite", ratelimit=False, ) + if self._config.servernotices.server_notices_auto_join: + user_requester = create_requester( + user_id, authenticated_entity=self._server_name + ) + await self._room_member_handler.update_membership( + requester=user_requester, + target=user_id_obj, + room_id=room_id, + action="join", + ratelimit=False, + ) + async def _update_notice_user_profile_if_changed( self, requester: Requester, diff --git a/tests/rest/admin/test_server_notice.py b/tests/rest/admin/test_server_notice.py index dfd14f5751..2398bc503a 100644 --- a/tests/rest/admin/test_server_notice.py +++ b/tests/rest/admin/test_server_notice.py @@ -477,6 +477,33 @@ class ServerNoticeTestCase(unittest.HomeserverTestCase): # second room has new ID self.assertNotEqual(first_room_id, second_room_id) + @override_config( + {"server_notices": {"system_mxid_localpart": "notices", "auto_join": True}} + ) + def test_auto_join(self) -> None: + """ + Tests that the user get automatically joined to the notice room + when `auto_join` setting is used. + """ + # user has no room memberships + self._check_invite_and_join_status(self.other_user, 0, 0) + + # send server notice + server_notice_request_content = { + "user_id": self.other_user, + "content": {"msgtype": "m.text", "body": "test msg one"}, + } + + self.make_request( + "POST", + self.url, + access_token=self.admin_user_tok, + content=server_notice_request_content, + ) + + # user has joined the room + self._check_invite_and_join_status(self.other_user, 0, 1) + @override_config({"server_notices": {"system_mxid_localpart": "notices"}}) def test_update_notice_user_name_when_changed(self) -> None: """ -- cgit 1.5.1 From 0a00c99823818228479f9fdb8c77e61a49a65e18 Mon Sep 17 00:00:00 2001 From: David Robertson Date: Tue, 5 Dec 2023 12:06:21 +0000 Subject: Fix upgrading a room without `events` field in power levels (#16725) --- changelog.d/16725.bugfix | 1 + synapse/handlers/room.py | 2 +- tests/rest/client/test_upgrade_room.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 changelog.d/16725.bugfix (limited to 'tests/rest') diff --git a/changelog.d/16725.bugfix b/changelog.d/16725.bugfix new file mode 100644 index 0000000000..42dc249fb9 --- /dev/null +++ b/changelog.d/16725.bugfix @@ -0,0 +1 @@ +Fix a bug introduced in Synapse 1.7.2 where rooms whose power levels lacked an `events` field could not be upgraded. diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py index f865bed1ec..2823ca6f0d 100644 --- a/synapse/handlers/room.py +++ b/synapse/handlers/room.py @@ -549,7 +549,7 @@ class RoomCreationHandler: except (TypeError, ValueError): ban = 50 needed_power_level = max( - state_default_int, ban, max(event_power_levels.values()) + state_default_int, ban, max(event_power_levels.values(), default=0) ) # Get the user's current power level, this matches the logic in get_user_power_level, diff --git a/tests/rest/client/test_upgrade_room.py b/tests/rest/client/test_upgrade_room.py index 0b4c691318..28f772261b 100644 --- a/tests/rest/client/test_upgrade_room.py +++ b/tests/rest/client/test_upgrade_room.py @@ -246,6 +246,34 @@ class UpgradeRoomTest(unittest.HomeserverTestCase): # We should now have an integer power level. self.assertEqual(new_power_levels["users"][self.creator], 100, new_power_levels) + def test_events_field_missing(self) -> None: + """Regression test for https://github.com/matrix-org/synapse/issues/16715.""" + # Create a new room. + room_id = self.helper.create_room_as( + self.creator, tok=self.creator_token, room_version="10" + ) + self.helper.join(room_id, self.other, tok=self.other_token) + + # Retrieve the room's current power levels. + power_levels = self.helper.get_state( + room_id, + "m.room.power_levels", + tok=self.creator_token, + ) + + # Remove the events field and re-set the power levels. + del power_levels["events"] + self.helper.send_state( + room_id, + "m.room.power_levels", + body=power_levels, + tok=self.creator_token, + ) + + # Upgrade the room. Check the homeserver reports success. + channel = self._upgrade_room(room_id=room_id) + self.assertEqual(200, channel.code, channel.result) + def test_space(self) -> None: """Test upgrading a space.""" -- cgit 1.5.1