mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-08-03 22:14:14 -04:00
Support filtering the /messages API by relation type (MSC3874). (#14148)
Gated behind an experimental configuration flag.
This commit is contained in:
parent
6b24235142
commit
4283bd1cf9
9 changed files with 212 additions and 177 deletions
|
@ -36,7 +36,7 @@ from jsonschema import FormatChecker
|
|||
from synapse.api.constants import EduTypes, EventContentFields
|
||||
from synapse.api.errors import SynapseError
|
||||
from synapse.api.presence import UserPresenceState
|
||||
from synapse.events import EventBase
|
||||
from synapse.events import EventBase, relation_from_event
|
||||
from synapse.types import JsonDict, RoomID, UserID
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -53,6 +53,12 @@ FILTER_SCHEMA = {
|
|||
# check types are valid event types
|
||||
"types": {"type": "array", "items": {"type": "string"}},
|
||||
"not_types": {"type": "array", "items": {"type": "string"}},
|
||||
# MSC3874, filtering /messages.
|
||||
"org.matrix.msc3874.rel_types": {"type": "array", "items": {"type": "string"}},
|
||||
"org.matrix.msc3874.not_rel_types": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -334,8 +340,15 @@ class Filter:
|
|||
self.labels = filter_json.get("org.matrix.labels", None)
|
||||
self.not_labels = filter_json.get("org.matrix.not_labels", [])
|
||||
|
||||
self.related_by_senders = self.filter_json.get("related_by_senders", None)
|
||||
self.related_by_rel_types = self.filter_json.get("related_by_rel_types", None)
|
||||
self.related_by_senders = filter_json.get("related_by_senders", None)
|
||||
self.related_by_rel_types = filter_json.get("related_by_rel_types", None)
|
||||
|
||||
# For compatibility with _check_fields.
|
||||
self.rel_types = None
|
||||
self.not_rel_types = []
|
||||
if hs.config.experimental.msc3874_enabled:
|
||||
self.rel_types = filter_json.get("org.matrix.msc3874.rel_types", None)
|
||||
self.not_rel_types = filter_json.get("org.matrix.msc3874.not_rel_types", [])
|
||||
|
||||
def filters_all_types(self) -> bool:
|
||||
return "*" in self.not_types
|
||||
|
@ -386,11 +399,19 @@ class Filter:
|
|||
# check if there is a string url field in the content for filtering purposes
|
||||
labels = content.get(EventContentFields.LABELS, [])
|
||||
|
||||
# Check if the event has a relation.
|
||||
rel_type = None
|
||||
if isinstance(event, EventBase):
|
||||
relation = relation_from_event(event)
|
||||
if relation:
|
||||
rel_type = relation.rel_type
|
||||
|
||||
field_matchers = {
|
||||
"rooms": lambda v: room_id == v,
|
||||
"senders": lambda v: sender == v,
|
||||
"types": lambda v: _matches_wildcard(ev_type, v),
|
||||
"labels": lambda v: v in labels,
|
||||
"rel_types": lambda v: rel_type == v,
|
||||
}
|
||||
|
||||
result = self._check_fields(field_matchers)
|
||||
|
|
|
@ -117,3 +117,6 @@ class ExperimentalConfig(Config):
|
|||
self.msc3882_token_timeout = self.parse_duration(
|
||||
experimental.get("msc3882_token_timeout", "5m")
|
||||
)
|
||||
|
||||
# MSC3874: Filtering /messages with rel_types / not_rel_types.
|
||||
self.msc3874_enabled: bool = experimental.get("msc3874_enabled", False)
|
||||
|
|
|
@ -114,6 +114,8 @@ class VersionsRestServlet(RestServlet):
|
|||
"org.matrix.msc3882": self.config.experimental.msc3882_enabled,
|
||||
# Adds support for remotely enabling/disabling pushers, as per MSC3881
|
||||
"org.matrix.msc3881": self.config.experimental.msc3881_enabled,
|
||||
# Adds support for filtering /messages by event relation.
|
||||
"org.matrix.msc3874": self.config.experimental.msc3874_enabled,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
@ -357,6 +357,24 @@ def filter_to_clause(event_filter: Optional[Filter]) -> Tuple[str, List[str]]:
|
|||
)
|
||||
args.extend(event_filter.related_by_rel_types)
|
||||
|
||||
if event_filter.rel_types:
|
||||
clauses.append(
|
||||
"(%s)"
|
||||
% " OR ".join(
|
||||
"event_relation.relation_type = ?" for _ in event_filter.rel_types
|
||||
)
|
||||
)
|
||||
args.extend(event_filter.rel_types)
|
||||
|
||||
if event_filter.not_rel_types:
|
||||
clauses.append(
|
||||
"((%s) OR event_relation.relation_type IS NULL)"
|
||||
% " AND ".join(
|
||||
"event_relation.relation_type != ?" for _ in event_filter.not_rel_types
|
||||
)
|
||||
)
|
||||
args.extend(event_filter.not_rel_types)
|
||||
|
||||
return " AND ".join(clauses), args
|
||||
|
||||
|
||||
|
@ -1278,8 +1296,8 @@ class StreamWorkerStore(EventsWorkerStore, SQLBaseStore):
|
|||
# Multiple labels could cause the same event to appear multiple times.
|
||||
needs_distinct = True
|
||||
|
||||
# If there is a filter on relation_senders and relation_types join to the
|
||||
# relations table.
|
||||
# If there is a relation_senders and relation_types filter join to the
|
||||
# relations table to get events related to the current event.
|
||||
if event_filter and (
|
||||
event_filter.related_by_senders or event_filter.related_by_rel_types
|
||||
):
|
||||
|
@ -1294,6 +1312,13 @@ class StreamWorkerStore(EventsWorkerStore, SQLBaseStore):
|
|||
LEFT JOIN events AS related_event ON (relation.event_id = related_event.event_id)
|
||||
"""
|
||||
|
||||
# If there is a not_rel_types filter join to the relations table to get
|
||||
# the event's relation information.
|
||||
if event_filter and (event_filter.rel_types or event_filter.not_rel_types):
|
||||
join_clause += """
|
||||
LEFT JOIN event_relations AS event_relation USING (event_id)
|
||||
"""
|
||||
|
||||
if needs_distinct:
|
||||
select_keywords += " DISTINCT"
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue