From 96647a5c9c2ebb894fa859789ade601446d89755 Mon Sep 17 00:00:00 2001 From: Krombel Date: Fri, 13 Jul 2018 16:46:54 +0200 Subject: [PATCH 1/3] Adds method to send a server_notice to all rooms In #3525 it got requested to have an easier way to send a server notice to all users on the server. Besides the query that got mentioned there this adds another command which can be called via manhole to send those messages. Signed-Off-By: Matthias Kesler --- changelog.d/3531.feature | 1 + docs/server_notices.md | 9 ++++++ .../server_notices/server_notices_manager.py | 31 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 changelog.d/3531.feature diff --git a/changelog.d/3531.feature b/changelog.d/3531.feature new file mode 100644 index 000000000000..1ea5c6bfa7fc --- /dev/null +++ b/changelog.d/3531.feature @@ -0,0 +1 @@ +add simple query to send a server notice to all rooms diff --git a/docs/server_notices.md b/docs/server_notices.md index 58f8776319a9..b5b508189f1e 100644 --- a/docs/server_notices.md +++ b/docs/server_notices.md @@ -72,3 +72,12 @@ sent with something like: ``` >>> hs.get_server_notices_manager().send_notice('@user:server.com', {'msgtype':'m.text', 'body':'foo'}) ``` + +To send a notice to all users can be send with the following query: + +``` +>>> hs.get_server_notices_manager().send_notice_to_all_users({'msgtype':'m.text', 'body':'foo'}) +``` +Note: This query sends a message to all users (with creating a room for each one +if it was not done before). So please be aware that you will put your server unter heavy +load if you have a lots of users \ No newline at end of file diff --git a/synapse/server_notices/server_notices_manager.py b/synapse/server_notices/server_notices_manager.py index a26deace5318..d3dba05ec260 100644 --- a/synapse/server_notices/server_notices_manager.py +++ b/synapse/server_notices/server_notices_manager.py @@ -45,6 +45,37 @@ def is_enabled(self): """ return self._config.server_notices_mxid is not None + @defer.inlineCallbacks + def send_notice_to_all_users(self, event_content): + """Send a notice to all users on the server + + Creates the server notices rooms, if none exists. + + Args: + event_content (dict): content of event to send + + Returns: + Deferred[None] + """ + + system_mxid = self._config.server_notices_mxid + requester = create_requester(system_mxid) + + user_ids = yield self._store.get_all_local_users() + for user_id in user_ids: + logger.info("Sending server notice to %s", user_id) + + room_id = yield self.get_notice_room_for_user(user_id) + yield self._event_creation_handler.create_and_send_nonmember_event( + requester, { + "type": EventTypes.Message, + "room_id": room_id, + "sender": system_mxid, + "content": event_content, + }, + ratelimit=False, + ) + @defer.inlineCallbacks def send_notice(self, user_id, event_content): """Send a notice to the given user From 29ab2d79d84ac899d96477abb55a37f3944b930c Mon Sep 17 00:00:00 2001 From: Krombel Date: Fri, 13 Jul 2018 18:17:40 +0200 Subject: [PATCH 2/3] add admin_api --- changelog.d/3531.feature | 2 +- synapse/rest/client/v1/admin.py | 63 +++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/changelog.d/3531.feature b/changelog.d/3531.feature index 1ea5c6bfa7fc..8cd2f7f210d4 100644 --- a/changelog.d/3531.feature +++ b/changelog.d/3531.feature @@ -1 +1 @@ -add simple query to send a server notice to all rooms +add admin api to send a server notice to one or all users diff --git a/synapse/rest/client/v1/admin.py b/synapse/rest/client/v1/admin.py index 80d625eecce6..e81831d7e171 100644 --- a/synapse/rest/client/v1/admin.py +++ b/synapse/rest/client/v1/admin.py @@ -730,6 +730,68 @@ def on_GET(self, request, target_user_id): defer.returnValue((200, ret)) +class ServerNoticeRestServlet(ClientV1RestServlet): + PATTERNS = client_path_patterns("/admin/send_server_notice(/(?P[^/]+))?") + + def __init__(self, hs): + super(ServerNoticeRestServlet, self).__init__(hs) + self._notice_manager = hs.get_server_notices_manager() + + @defer.inlineCallbacks + def on_POST(self, request, user_id): + """ + This lets you send a server_notice to one or all users + Example: + http://localhost:8008/_matrix/client/r0/admin/send_server_notice/@user:host + JsonBodyToSend: + { + "event": {'msgtype':'m.text', 'body':'This is my message'} + } + or simply + { + 'event_body': 'This is my message' + } + Returns: + 200 OK. + + """ + body = parse_json_object_from_request(request, allow_empty_body=False) + event = body.get("event", None) + if event is None: + event_body = body.get("event_body", None) + if event_body is None: + raise SynapseError( + http_client.BAD_REQUEST, + "Either 'event' or 'event_body' is required", + Codes.BAD_JSON, + ) + event = { + "msgtype": "m.text", + "body": event_body + } + else: + if event.get("msgtype") is None or event.get("body") is None: + raise SynapseError( + http_client.BAD_REQUEST, + "event needs 'msgtype' and 'body' as content", + Codes.BAD_JSON, + ) + + if user_id is not None: + UserID.from_string(user_id) + requester = yield self.auth.get_user_by_req(request) + is_admin = yield self.auth.is_server_admin(requester.user) + + if not is_admin: + raise AuthError(403, "You are not a server admin") + + if user_id is not None: + yield self._notice_manager.send_notice(user_id, event) + else: + yield self._notice_manager.send_notice_to_all_users(event) + defer.returnValue((200, {})) + + def register_servlets(hs, http_server): WhoisRestServlet(hs).register(http_server) PurgeMediaCacheRestServlet(hs).register(http_server) @@ -744,3 +806,4 @@ def register_servlets(hs, http_server): QuarantineMediaInRoom(hs).register(http_server) ListMediaInRoom(hs).register(http_server) UserRegisterServlet(hs).register(http_server) + ServerNoticeRestServlet(hs).register(http_server) From a5dd1e958c0782072447cdc7839cbf0d39cc5a68 Mon Sep 17 00:00:00 2001 From: Krombel Date: Fri, 13 Jul 2018 18:27:11 +0200 Subject: [PATCH 3/3] update doc --- docs/admin_api/server_notices.md | 35 ++++++++++++++++++++++++++++++++ docs/server_notices.md | 33 +++++------------------------- synapse/rest/client/v1/admin.py | 8 ++++---- 3 files changed, 44 insertions(+), 32 deletions(-) create mode 100644 docs/admin_api/server_notices.md diff --git a/docs/admin_api/server_notices.md b/docs/admin_api/server_notices.md new file mode 100644 index 000000000000..d17c2fefd2c9 --- /dev/null +++ b/docs/admin_api/server_notices.md @@ -0,0 +1,35 @@ +# Server Notices + +The API to send notices is as follows: + +``` +POST /_matrix/client/r0/admin/send_server_notice/[] +``` + +including an `access_token` of a server admin. + +If the user_id is missing, the message is meant to go to all users on the server. + +The request body should contain the following: + +```json +{ + "event": { + "msgtype":"m.text", + "body": "This is my message" + } +} +``` +or as shortcut you can also send +```json +{ + "event_body": "This is my message" +} +``` + +## Notes: +1) You have to configure server notices in [homeserver.yaml](../server_notices.md) before +you can use this API +2) This query sends a message to all users (and creates a room for each one if it was not +done before). So please be aware that you will put your server under heavy load if you +have a large number of registered users. \ No newline at end of file diff --git a/docs/server_notices.md b/docs/server_notices.md index b5b508189f1e..d88b91b83ecb 100644 --- a/docs/server_notices.md +++ b/docs/server_notices.md @@ -1,5 +1,4 @@ -Server Notices -============== +# Server Notices 'Server Notices' are a new feature introduced in Synapse 0.30. They provide a channel whereby server administrators can send messages to users on the server. @@ -11,8 +10,7 @@ they may also find a use for features such as "Message of the day". This is a feature specific to Synapse, but it uses standard Matrix communication mechanisms, so should work with any Matrix client. -User experience ---------------- +## User experience When the user is first sent a server notice, they will get an invitation to a room (typically called 'Server Notices', though this is configurable in @@ -29,8 +27,7 @@ levels. Having joined the room, the user can leave the room if they want. Subsequent server notices will then cause a new room to be created. -Synapse configuration ---------------------- +## Synapse configuration Server notices come from a specific user id on the server. Server administrators are free to choose the user id - something like `server` is @@ -58,26 +55,6 @@ 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. -Sending notices ---------------- +## Sending notices -As of the current version of synapse, there is no convenient interface for -sending notices (other than the automated ones sent as part of consent -tracking). - -In the meantime, it is possible to test this feature using the manhole. Having -gone into the manhole as described in [manhole.md](manhole.md), a notice can be -sent with something like: - -``` ->>> hs.get_server_notices_manager().send_notice('@user:server.com', {'msgtype':'m.text', 'body':'foo'}) -``` - -To send a notice to all users can be send with the following query: - -``` ->>> hs.get_server_notices_manager().send_notice_to_all_users({'msgtype':'m.text', 'body':'foo'}) -``` -Note: This query sends a message to all users (with creating a room for each one -if it was not done before). So please be aware that you will put your server unter heavy -load if you have a lots of users \ No newline at end of file +To send server notices to users you can use the [admin_api](admin_api/server_notices.md). \ No newline at end of file diff --git a/synapse/rest/client/v1/admin.py b/synapse/rest/client/v1/admin.py index e81831d7e171..f583d16e1004 100644 --- a/synapse/rest/client/v1/admin.py +++ b/synapse/rest/client/v1/admin.py @@ -557,7 +557,7 @@ class ResetPasswordRestServlet(ClientV1RestServlet): """Post request to allow an administrator reset password for a user. This needs user to have administrator access in Synapse. Example: - http://localhost:8008/_matrix/client/api/v1/admin/reset_password/ + http://localhost:8008/_matrix/client/r0/admin/reset_password/ @user:to_reset_password?access_token=admin_access_token JsonBodyToSend: { @@ -603,7 +603,7 @@ class GetUsersPaginatedRestServlet(ClientV1RestServlet): """Get request to get specific number of users from Synapse. This needs user to have administrator access in Synapse. Example: - http://localhost:8008/_matrix/client/api/v1/admin/users_paginate/ + http://localhost:8008/_matrix/client/r0/admin/users_paginate/ @admin:user?access_token=admin_access_token&start=0&limit=10 Returns: 200 OK with json object {list[dict[str, Any]], count} or empty object. @@ -652,7 +652,7 @@ def on_POST(self, request, target_user_id): """Post request to get specific number of users from Synapse.. This needs user to have administrator access in Synapse. Example: - http://localhost:8008/_matrix/client/api/v1/admin/users_paginate/ + http://localhost:8008/_matrix/client/r0/admin/users_paginate/ @admin:user?access_token=admin_access_token JsonBodyToSend: { @@ -687,7 +687,7 @@ class SearchUsersRestServlet(ClientV1RestServlet): search term. This needs user to have administrator access in Synapse. Example: - http://localhost:8008/_matrix/client/api/v1/admin/search_users/ + http://localhost:8008/_matrix/client/r0/admin/search_users/ @admin:user?access_token=admin_access_token&term=alice Returns: 200 OK with json object {list[dict[str, Any]], count} or empty object.