Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spec annotations #1475

Merged
merged 6 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelogs/client_server/newsfragments/1475.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `m.annotation` relations (reactions), as per [MSC2677](https://github.com/matrix-org/matrix-spec-proposals/pull/2677).
4 changes: 4 additions & 0 deletions content/client-server-api/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1996,6 +1996,7 @@ This specification describes the following relationship types:

* [Rich replies](#rich-replies) (**Note**: does not use `rel_type`).
* [Event replacements](#event-replacements).
* [Event annotations](#event-annotations-and-reactions).
* [Threads](#threading).
* [References](#reference-relations)

Expand Down Expand Up @@ -2579,6 +2580,7 @@ that profile.
| [Moderation policies](#moderation-policy-lists) | Optional | Optional | Optional | Optional | Optional |
| [Spaces](#spaces) | Optional | Optional | Optional | Optional | Optional |
| [Event Replacements](#event-replacements) | Optional | Optional | Optional | Optional | Optional |
| [Event Annotations and reactions](#event-annotations-and-reactions) | Optional | Optional | Optional | Optional | Optional |
| [Threading](#threading) | Optional | Optional | Optional | Optional | Optional |
| [Reference Relations](#reference-relations) | Optional | Optional | Optional | Optional | Optional |

Expand Down Expand Up @@ -2665,5 +2667,7 @@ systems.
{{< cs-module name="moderation_policies" >}}
{{< cs-module name="spaces" >}}
{{< cs-module name="event_replacements" >}}
{{< cs-module name="event_annotations" >}}
{{< cs-module name="threading" >}}
{{< cs-module name="reference_relations" >}}

93 changes: 93 additions & 0 deletions content/client-server-api/modules/event_annotations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
### Event annotations and reactions

{{% added-in v="1.7" %}}

#### `m.annotation` relationship type

Annotations are events that use an [event
relationship](#forming-relationships-between-events) with a `rel_type` of
`m.annotation`.

Annotations are normally used for "reactions": for example, if the user wants
to react to an event with a thumbs-up, then the client sends an annotation
event with the corresponding emoji (👍). Another potential usage is to allow
bots to send an event indicating the success or failure of a command.

Along with the normal properties `event_id` and `rel_type`, an `m.relates_to`
property with `rel_type: m.annotion` should contain a `key` that indicates the
annotation being applied. For example, when reacting with emojis, the key
contains the emoji being used.

An example `m.annotation` relationship is shown below:

```json
"m.relates_to": {
"rel_type": "m.annotation",
"event_id": "$some_event_id",
"key": "👍"
}
```

{{% boxes/note %}}
Any `type` of event is eligible for an annotation, including state events.
{{% /boxes/note %}}

#### Events

{{% event event="m.reaction" %}}

#### Client behaviour {id="annotations-client-behaviour"}

The intention of annotations is that they are counted up, rather than being
displayed individually. Clients must keep count of the number of annotations
with a given event `type` and annotation `key` they observe for each event;
these counts are typically presented alongside the event in the timeline.

When performing this count:

* Each event `type` and annotation `key` should normally be counted
separately, though whether to actually do so is an implementation decision.

* Annotation events sent by [ignored users](#ignoring-users) should be
excluded from the count.

* Multiple identical annotations (i.e., with the same event `type` and
annotation `key`) from the same user (i.e., events with the same `sender`)
should be treated as a single annotation.

* Implementations should ignore any annotation event which refers to an event
which itself has an `m.relates_to` with `rel_type: m.annotation` or
`rel_type: m.replace`. In other words, it is not possible to annotate a
[replacement event](#event-replacements) or an annotation. Annotations should
instead refer to the original event.

* When an annotation is redacted, it is removed from the count.

{{% boxes/note %}}
It is not possible to edit a reaction, since replacement events do not change
`m.relates_to` (see [Applying `m.new_content`](#applying-mnew_content)), and
there is no other meaningful content within `m.reaction`. If a user wishes to
change their reaction, the original reaction should be redacted and a new one
sent in its place.
{{% /boxes/note %}}

#### Server behaviour

##### Avoiding duplicate annotations

Homeservers should prevent users from sending a second annotation for a given
event with identical event `type` and annotation `key` (unless the first event
has been redacted).

Attempts to send such an annotation should be rejected with a 400 error and an
error code of `M_DUPLICATE_ANNOTATION`.
Comment on lines +82 to +83
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wonder if I should add something about this to the docs on /send

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think so. That endpoint seems to need more documentation about errors in general, but starting with this would be a good step at least.


Note that this does not guarantee that duplicate annotations will not arrive
over federation. Clients are responsible for deduplicating received
annotations when [counting annotations](#annotations-client-behaviour).

##### Server-side aggregation of `m.annotation` relationships

`m.annotation` relationships are *not*
[aggregated](#aggregations-of-child-events) by the server. In other words,
`m.annotation` is not included in the `m.relations` property.
25 changes: 25 additions & 0 deletions content/client-server-api/modules/push.md
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,31 @@ Definition:
}
```

**<a name="mrulereaction"></a>`.m.rule.reaction`**

{{% added-in v="1.7" %}}

Matches any event whose type is `m.room.reaction`. This suppresses notifications for [`m.reaction`](#mreaction) events.

Definition:

```json
{
"rule_id": ".m.rule.reaction",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.reaction"
}
],
"actions": []
}
```


**`.m.rule.room.server_acl`**

{{% added-in v="1.4" %}}
Expand Down
9 changes: 9 additions & 0 deletions data/api/client-server/room_send.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright 2016 OpenMarket Ltd
# Copyright 2023 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -88,5 +89,13 @@ paths:
A unique identifier for the event.
required:
- event_id
400:
description: |-
The request is invalid. A [standard error response](/client-server-api/#standard-error-response)
will be returned. As well as the normal common error codes, other reasons for rejection include:

- `M_DUPLICATE_ANNOTATION`: The request is an attempt to send a [duplicate annotation](/client-server-api/#avoiding-duplicate-annotations).
schema:
"$ref": "definitions/errors/error.yaml"
tags:
- Room participation
11 changes: 11 additions & 0 deletions data/event-schemas/examples/m.reaction.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$ref": "core/room_event.json",
"type": "m.reaction",
"content": {
"m.relates_to": {
"rel_type": "m.annotation",
"event_id": "$some_event_id",
"key": "👍"
}
}
}
37 changes: 37 additions & 0 deletions data/event-schemas/schema/m.reaction.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
allOf:
- $ref: core-event-schema/room_event.yaml
description: |-
Indicates a reaction to a previous event.

Has no defined `content` properties of its own. Its only purpose is to hold an
[`m.relates_to`](/client-server-api/#definition-mrelates_to) property.

Since they contain no content other than `m.relates_to`, `m.reaction` events
are normally not encrypted, as there would be no benefit in doing so.
type: object
properties:
content:
type: object
properties:
m.relates_to:
description: |-
Indicates the event being reacted to, and the type of reaction.
type: object
title: ReactionRelatesTo
properties:
rel_type:
type: string
enum: ["m.annotation"]
event_id:
type: string
description: |-
The event ID of the event that this is a reaction to.
example: "$some_event_id"
key:
type: string
description: |-
An emoji representing the reaction being made. Should include the
unicode emoji presentation selector (`\uFE0F`) for codepoints
which allow it (see the [emoji variation sequences
list](https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-variation-sequences.txt)).
example: "👍"