diff --git a/synapse/config/server_notices.py b/synapse/config/server_notices.py
index a8badba0f8..79f365cad5 100644
--- a/synapse/config/server_notices.py
+++ b/synapse/config/server_notices.py
@@ -38,6 +38,14 @@ class ServerNoticesConfig(Config):
server_notices_room_name (str|None):
The name to use for the server notices room.
None if server notices are not enabled.
+
+ server_notices_room_avatar_url (str|None):
+ The avatar URL to use for the server notices room.
+ None if server notices are not enabled.
+
+ server_notices_room_topic (str|None):
+ The topic to use for the server notices room.
+ None if server notices are not enabled.
"""
section = "servernotices"
@@ -48,6 +56,8 @@ 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_room_avatar_url: Optional[str] = None
+ self.server_notices_room_topic: Optional[str] = None
self.server_notices_auto_join: bool = False
def read_config(self, config: JsonDict, **kwargs: Any) -> None:
@@ -63,4 +73,6 @@ 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_room_avatar_url = c.get("room_avatar_url", None)
+ self.server_notices_room_topic = c.get("room_topic", None)
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 2353b5d47f..39a54362d8 100644
--- a/synapse/server_notices/server_notices_manager.py
+++ b/synapse/server_notices/server_notices_manager.py
@@ -16,7 +16,7 @@ from typing import TYPE_CHECKING, Optional
from synapse.api.constants import EventTypes, Membership, RoomCreationPreset
from synapse.events import EventBase
-from synapse.types import Requester, StreamKeyType, UserID, create_requester
+from synapse.types import JsonDict, Requester, StreamKeyType, UserID, create_requester
from synapse.util.caches.descriptors import cached
if TYPE_CHECKING:
@@ -36,6 +36,7 @@ class ServerNoticesManager:
self._room_member_handler = hs.get_room_member_handler()
self._event_creation_handler = hs.get_event_creation_handler()
self._message_handler = hs.get_message_handler()
+ self._storage_controllers = hs.get_storage_controllers()
self._is_mine_id = hs.is_mine_id
self._server_name = hs.hostname
@@ -160,6 +161,27 @@ class ServerNoticesManager:
self._config.servernotices.server_notices_mxid_display_name,
self._config.servernotices.server_notices_mxid_avatar_url,
)
+ await self._update_room_info(
+ requester,
+ room_id,
+ EventTypes.Name,
+ "name",
+ self._config.servernotices.server_notices_room_name,
+ )
+ await self._update_room_info(
+ requester,
+ room_id,
+ EventTypes.RoomAvatar,
+ "url",
+ self._config.servernotices.server_notices_room_avatar_url,
+ )
+ await self._update_room_info(
+ requester,
+ room_id,
+ EventTypes.Topic,
+ "topic",
+ self._config.servernotices.server_notices_room_topic,
+ )
return room_id
# apparently no existing notice room: create a new one
@@ -178,15 +200,31 @@ class ServerNoticesManager:
"avatar_url": self._config.servernotices.server_notices_mxid_avatar_url,
}
+ room_config: JsonDict = {
+ "preset": RoomCreationPreset.PRIVATE_CHAT,
+ "power_level_content_override": {"users_default": -10},
+ }
+
+ if self._config.servernotices.server_notices_room_name:
+ room_config["name"] = self._config.servernotices.server_notices_room_name
+ if self._config.servernotices.server_notices_room_topic:
+ room_config["topic"] = self._config.servernotices.server_notices_room_topic
+ if self._config.servernotices.server_notices_room_avatar_url:
+ room_config["initial_state"] = [
+ {
+ "type": EventTypes.RoomAvatar,
+ "state_key": "",
+ "content": {
+ "url": self._config.servernotices.server_notices_room_avatar_url,
+ },
+ }
+ ]
+
# `ignore_forced_encryption` is used to bypass `encryption_enabled_by_default_for_room_type`
# setting if it set, since the server notices will not be encrypted anyway.
room_id, _, _ = await self._room_creation_handler.create_room(
requester,
- config={
- "preset": RoomCreationPreset.PRIVATE_CHAT,
- "name": self._config.servernotices.server_notices_room_name,
- "power_level_content_override": {"users_default": -10},
- },
+ config=room_config,
ratelimit=False,
creator_join_profile=join_profile,
ignore_forced_encryption=True,
@@ -265,11 +303,12 @@ class ServerNoticesManager:
assert self.server_notices_mxid is not None
- notice_user_data_in_room = await self._message_handler.get_room_data(
- create_requester(self.server_notices_mxid),
- room_id,
- EventTypes.Member,
- self.server_notices_mxid,
+ notice_user_data_in_room = (
+ await self._storage_controllers.state.get_current_state_event(
+ room_id,
+ EventTypes.Member,
+ self.server_notices_mxid,
+ )
)
assert notice_user_data_in_room is not None
@@ -288,3 +327,55 @@ class ServerNoticesManager:
ratelimit=False,
content={"displayname": display_name, "avatar_url": avatar_url},
)
+
+ async def _update_room_info(
+ self,
+ requester: Requester,
+ room_id: str,
+ info_event_type: str,
+ info_content_key: str,
+ info_value: Optional[str],
+ ) -> None:
+ """
+ Updates a specific notice room's info if it's different from what is set.
+
+ Args:
+ requester: The user who is performing the update.
+ room_id: The ID of the server notice room
+ info_event_type: The event type holding the specific info
+ info_content_key: The key containing the specific info in the event's content
+ info_value: The expected value for the specific info
+ """
+ room_info_event = await self._storage_controllers.state.get_current_state_event(
+ room_id,
+ info_event_type,
+ "",
+ )
+
+ existing_info_value = None
+ if room_info_event:
+ existing_info_value = room_info_event.get(info_content_key)
+ if existing_info_value == info_value:
+ return
+ if not existing_info_value and not info_value:
+ # A missing `info_value` can either be represented by a None
+ # or an empty string, so we assume that if they're both falsey
+ # they're equivalent.
+ return
+
+ if info_value is None:
+ info_value = ""
+
+ room_info_event_dict = {
+ "type": info_event_type,
+ "room_id": room_id,
+ "sender": requester.user.to_string(),
+ "state_key": "",
+ "content": {
+ info_content_key: info_value,
+ },
+ }
+
+ event, _ = await self._event_creation_handler.create_and_send_nonmember_event(
+ requester, room_info_event_dict, ratelimit=False
+ )
|