107 lines
3.3 KiB
Markdown
107 lines
3.3 KiB
Markdown
# 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
|
|
}
|
|
}
|
|
)
|
|
```
|