Add basic editing support

This commit is contained in:
Erik Johnston 2019-05-14 16:59:21 +01:00
parent 5c39d262c0
commit d46aab3fa8
4 changed files with 167 additions and 15 deletions

View file

@ -346,7 +346,7 @@ class EventClientSerializer(object):
defer.returnValue(event)
event_id = event.event_id
event = serialize_event(event, time_now, **kwargs)
serialized_event = serialize_event(event, time_now, **kwargs)
# If MSC1849 is enabled then we need to look if thre are any relations
# we need to bundle in with the event
@ -359,14 +359,36 @@ class EventClientSerializer(object):
)
if annotations.chunk:
r = event["unsigned"].setdefault("m.relations", {})
r = serialized_event["unsigned"].setdefault("m.relations", {})
r[RelationTypes.ANNOTATION] = annotations.to_dict()
if references.chunk:
r = event["unsigned"].setdefault("m.relations", {})
r = serialized_event["unsigned"].setdefault("m.relations", {})
r[RelationTypes.REFERENCES] = references.to_dict()
defer.returnValue(event)
edit = None
if event.type == EventTypes.Message:
edit = yield self.store.get_applicable_edit(
event.event_id, event.type, event.sender,
)
if edit:
# If there is an edit replace the content, preserving existing
# relations.
relations = event.content.get("m.relates_to")
serialized_event["content"] = edit.content.get("m.new_content", {})
if relations:
serialized_event["content"]["m.relates_to"] = relations
else:
serialized_event["content"].pop("m.relates_to", None)
r = serialized_event["unsigned"].setdefault("m.relations", {})
r[RelationTypes.REPLACES] = {
"event_id": edit.event_id,
}
defer.returnValue(serialized_event)
def serialize_events(self, events, time_now, **kwargs):
"""Serializes multiple events.

View file

@ -143,3 +143,4 @@ class SlavedEventStore(EventFederationWorkerStore,
if relates_to:
self.get_relations_for_event.invalidate_many((relates_to,))
self.get_aggregation_groups_for_event.invalidate_many((relates_to,))
self.get_applicable_edit.invalidate_many((relates_to,))

View file

@ -17,11 +17,13 @@ import logging
import attr
from synapse.api.constants import RelationTypes
from twisted.internet import defer
from synapse.api.constants import EventTypes, RelationTypes
from synapse.api.errors import SynapseError
from synapse.storage._base import SQLBaseStore
from synapse.storage.stream import generate_pagination_where_clause
from synapse.util.caches.descriptors import cached
from synapse.util.caches.descriptors import cached, cachedInlineCallbacks
logger = logging.getLogger(__name__)
@ -312,6 +314,59 @@ class RelationsWorkerStore(SQLBaseStore):
"get_aggregation_groups_for_event", _get_aggregation_groups_for_event_txn
)
@cachedInlineCallbacks(tree=True)
def get_applicable_edit(self, event_id, event_type, sender):
"""Get the most recent edit (if any) that has happened for the given
event.
Correctly handles checking whether edits were allowed to happen.
Args:
event_id (str): The original event ID
event_type (str): The original event type
sender (str): The original event sender
Returns:
Deferred[EventBase|None]: Returns the most recent edit, if any.
"""
# We only allow edits for `m.room.message` events that have the same sender
# and event type. We can't assert these things during regular event auth so
# we have to do the post hoc.
if event_type != EventTypes.Message:
return
sql = """
SELECT event_id, origin_server_ts FROM events
INNER JOIN event_relations USING (event_id)
WHERE
relates_to_id = ?
AND relation_type = ?
AND type = ?
AND sender = ?
ORDER by origin_server_ts DESC, event_id DESC
LIMIT 1
"""
def _get_applicable_edit_txn(txn):
txn.execute(
sql, (event_id, RelationTypes.REPLACES, event_type, sender)
)
row = txn.fetchone()
if row:
return row[0]
edit_id = yield self.runInteraction(
"get_applicable_edit", _get_applicable_edit_txn
)
if not edit_id:
return
edit_event = yield self.get_event(edit_id, allow_none=True)
defer.returnValue(edit_event)
class RelationsStore(RelationsWorkerStore):
def _handle_event_relations(self, txn, event):
@ -357,3 +412,4 @@ class RelationsStore(RelationsWorkerStore):
txn.call_after(
self.get_aggregation_groups_for_event.invalidate_many, (parent_id,)
)
txn.call_after(self.get_applicable_edit.invalidate_many, (parent_id,))