diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index 21f80efc99..6aa48e1919 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -45,6 +45,7 @@
- [Account validity callbacks](modules/account_validity_callbacks.md)
- [Password auth provider callbacks](modules/password_auth_provider_callbacks.md)
- [Background update controller callbacks](modules/background_update_controller_callbacks.md)
+ - [Account data callbacks](modules/account_data_callbacks.md)
- [Porting a legacy module to the new interface](modules/porting_legacy_module.md)
- [Workers](workers.md)
- [Using `synctl` with Workers](synctl_workers.md)
diff --git a/docs/development/contributing_guide.md b/docs/development/contributing_guide.md
index 071202e196..9db9352c9e 100644
--- a/docs/development/contributing_guide.md
+++ b/docs/development/contributing_guide.md
@@ -220,27 +220,6 @@ export SYNAPSE_POSTGRES_PASSWORD=mydevenvpassword
trial
```
-#### Prebuilt container
-
-Since configuring PostgreSQL can be fiddly, we can make use of a pre-made
-Docker container to set up PostgreSQL and run our tests for us. To do so, run
-
-```shell
-scripts-dev/test_postgresql.sh
-```
-
-Any extra arguments to the script will be passed to `tox` and then to `trial`,
-so we can run a specific test in this container with e.g.
-
-```shell
-scripts-dev/test_postgresql.sh tests.replication.test_sharded_event_persister.EventPersisterShardTestCase
-```
-
-The container creates a folder in your Synapse checkout called
-`.tox-pg-container` and uses this as a tox environment. The output of any
-`trial` runs goes into `_trial_temp` in your synapse source directory — the same
-as running `trial` directly on your host machine.
-
## Run the integration tests ([Sytest](https://github.com/matrix-org/sytest)).
The integration tests are a more comprehensive suite of tests. They
@@ -254,8 +233,14 @@ configuration:
```sh
$ docker run --rm -it -v /path/where/you/have/cloned/the/repository\:/src:ro -v /path/to/where/you/want/logs\:/logs matrixdotorg/sytest-synapse:buster
```
+(Note that the paths must be full paths! You could also write `$(realpath relative/path)` if needed.)
+
+This configuration should generally cover your needs.
+
+- To run with Postgres, supply the `-e POSTGRES=1 -e MULTI_POSTGRES=1` environment flags.
+- To run with Synapse in worker mode, supply the `-e WORKERS=1 -e REDIS=1` environment flags (in addition to the Postgres flags).
-This configuration should generally cover your needs. For more details about other configurations, see [documentation in the SyTest repo](https://github.com/matrix-org/sytest/blob/develop/docker/README.md).
+For more details about other configurations, see the [Docker-specific documentation in the SyTest repo](https://github.com/matrix-org/sytest/blob/develop/docker/README.md).
## Run the integration tests ([Complement](https://github.com/matrix-org/complement)).
diff --git a/docs/modules/account_data_callbacks.md b/docs/modules/account_data_callbacks.md
new file mode 100644
index 0000000000..25de911627
--- /dev/null
+++ b/docs/modules/account_data_callbacks.md
@@ -0,0 +1,106 @@
+# Account data callbacks
+
+Account data callbacks allow module developers to react to changes of the account data
+of local users. Account data callbacks can be registered using the module API's
+`register_account_data_callbacks` method.
+
+## Callbacks
+
+The available account data callbacks are:
+
+### `on_account_data_updated`
+
+_First introduced in Synapse v1.57.0_
+
+```python
+async def on_account_data_updated(
+ user_id: str,
+ room_id: Optional[str],
+ account_data_type: str,
+ content: "synapse.module_api.JsonDict",
+) -> None:
+```
+
+Called after user's account data has been updated. The module is given the
+Matrix ID of the user whose account data is changing, the room ID the data is associated
+with, the type associated with the change, as well as the new content. If the account
+data is not associated with a specific room, then the room ID is `None`.
+
+This callback is triggered when new account data is added or when the data associated with
+a given type (and optionally room) changes. This includes deletion, since in Matrix,
+deleting account data consists of replacing the data associated with a given type
+(and optionally room) with an empty dictionary (`{}`).
+
+Note that this doesn't trigger when changing the tags associated with a room, as these are
+processed separately by Synapse.
+
+If multiple modules implement this callback, Synapse runs them all in order.
+
+## Example
+
+The example below is a module that implements the `on_account_data_updated` callback, and
+sends an event to an audit room when a user changes their account data.
+
+```python
+import json
+import attr
+from typing import Any, Dict, Optional
+
+from synapse.module_api import JsonDict, ModuleApi
+from synapse.module_api.errors import ConfigError
+
+
+@attr.s(auto_attribs=True)
+class CustomAccountDataConfig:
+ audit_room: str
+ sender: str
+
+
+class CustomAccountDataModule:
+ def __init__(self, config: CustomAccountDataConfig, api: ModuleApi):
+ self.api = api
+ self.config = config
+
+ self.api.register_account_data_callbacks(
+ on_account_data_updated=self.log_new_account_data,
+ )
+
+ @staticmethod
+ def parse_config(config: Dict[str, Any]) -> CustomAccountDataConfig:
+ def check_in_config(param: str):
+ if param not in config:
+ raise ConfigError(f"'{param}' is required")
+
+ check_in_config("audit_room")
+ check_in_config("sender")
+
+ return CustomAccountDataConfig(
+ audit_room=config["audit_room"],
+ sender=config["sender"],
+ )
+
+ async def log_new_account_data(
+ self,
+ user_id: str,
+ room_id: Optional[str],
+ account_data_type: str,
+ content: JsonDict,
+ ) -> None:
+ content_raw = json.dumps(content)
+ msg_content = f"{user_id} has changed their account data for type {account_data_type} to: {content_raw}"
+
+ if room_id is not None:
+ msg_content += f" (in room {room_id})"
+
+ await self.api.create_and_send_event_into_room(
+ {
+ "room_id": self.config.audit_room,
+ "sender": self.config.sender,
+ "type": "m.room.message",
+ "content": {
+ "msgtype": "m.text",
+ "body": msg_content
+ }
+ }
+ )
+```
diff --git a/docs/modules/third_party_rules_callbacks.md b/docs/modules/third_party_rules_callbacks.md
index 1d3c39967f..e1a5b6524f 100644
--- a/docs/modules/third_party_rules_callbacks.md
+++ b/docs/modules/third_party_rules_callbacks.md
@@ -247,6 +247,24 @@ admin API.
If multiple modules implement this callback, Synapse runs them all in order.
+### `on_threepid_bind`
+
+_First introduced in Synapse v1.56.0_
+
+```python
+async def on_threepid_bind(user_id: str, medium: str, address: str) -> None:
+```
+
+Called after creating an association between a local user and a third-party identifier
+(email address, phone number). The module is given the Matrix ID of the user the
+association is for, as well as the medium (`email` or `msisdn`) and address of the
+third-party identifier.
+
+Note that this callback is _not_ called after a successful association on an _identity
+server_.
+
+If multiple modules implement this callback, Synapse runs them all in order.
+
## Example
The example below is a module that implements the third-party rules callback
diff --git a/docs/modules/writing_a_module.md b/docs/modules/writing_a_module.md
index e7c0ffad58..e6303b739e 100644
--- a/docs/modules/writing_a_module.md
+++ b/docs/modules/writing_a_module.md
@@ -33,7 +33,7 @@ A module can implement the following static method:
```python
@staticmethod
-def parse_config(config: dict) -> dict
+def parse_config(config: dict) -> Any
```
This method is given a dictionary resulting from parsing the YAML configuration for the
diff --git a/docs/sample_config.yaml b/docs/sample_config.yaml
index a21b48ab2e..b8d8c0dbf0 100644
--- a/docs/sample_config.yaml
+++ b/docs/sample_config.yaml
@@ -539,6 +539,15 @@ templates:
#
#custom_template_directory: /path/to/custom/templates/
+# List of rooms to exclude from sync responses. This is useful for server
+# administrators wishing to group users into a room without these users being able
+# to see it from their client.
+#
+# By default, no room is excluded.
+#
+#exclude_rooms_from_sync:
+# - !foo:example.com
+
# Message retention policy at the server level.
#
diff --git a/docs/upgrade.md b/docs/upgrade.md
index 062e823333..f6d226526a 100644
--- a/docs/upgrade.md
+++ b/docs/upgrade.md
@@ -85,6 +85,19 @@ process, for example:
dpkg -i matrix-synapse-py3_1.3.0+stretch1_amd64.deb
```
+# Upgrading to v1.57.0
+
+## Changes to database schema for application services
+
+Synapse v1.57.0 includes a [change](https://github.com/matrix-org/synapse/pull/12209) to the
+way transaction IDs are managed for application services. If your deployment uses a dedicated
+worker for application service traffic, **it must be stopped** when the database is upgraded
+(which normally happens when the main process is upgraded), to ensure the change is made safely
+without any risk of reusing transaction IDs.
+
+Deployments which do not use separate worker processes can be upgraded as normal. Similarly,
+deployments where no applciation services are in use can be upgraded as normal.
+
# Upgrading to v1.56.0
## Groups/communities feature has been deprecated
diff --git a/docs/workers.md b/docs/workers.md
index 8ac95e39bb..caef44b614 100644
--- a/docs/workers.md
+++ b/docs/workers.md
@@ -27,7 +27,7 @@ feeds streams of newly written data between processes so they can be kept in
sync with the database state.
When configured to do so, Synapse uses a
-[Redis pub/sub channel](https://redis.io/topics/pubsub) to send the replication
+[Redis pub/sub channel](https://redis.io/docs/manual/pubsub/) to send the replication
stream between all configured Synapse processes. Additionally, processes may
make HTTP requests to each other, primarily for operations which need to wait
for a reply ─ such as sending an event.
|