From 78af6bbb981c41e5509c99454deb7205c31bf964 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Tue, 23 Sep 2014 15:28:32 +0100 Subject: Add m.room.deletion. If an event is deleted it will be returned to clients 'pruned', i.e. all client specified keys will be removed. --- synapse/rest/room.py | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'synapse/rest') diff --git a/synapse/rest/room.py b/synapse/rest/room.py index ecb1e346d9..85a1d2eae3 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -19,7 +19,7 @@ from twisted.internet import defer from base import RestServlet, client_path_pattern from synapse.api.errors import SynapseError, Codes from synapse.streams.config import PaginationConfig -from synapse.api.events.room import RoomMemberEvent +from synapse.api.events.room import RoomMemberEvent, RoomDeletionEvent from synapse.api.constants import Membership import json @@ -430,6 +430,41 @@ class RoomMembershipRestServlet(RestServlet): self.txns.store_client_transaction(request, txn_id, response) defer.returnValue(response) +class RoomDeleteEventRestServlet(RestServlet): + def register(self, http_server): + PATTERN = ("/rooms/(?P[^/]*)/delete/(?P[^/]*)") + register_txn_path(self, PATTERN, http_server) + + @defer.inlineCallbacks + def on_POST(self, request, room_id, event_id): + user = yield self.auth.get_user_by_req(request) + content = _parse_json(request) + + event = self.event_factory.create_event( + etype=RoomDeletionEvent.TYPE, + room_id=urllib.unquote(room_id), + user_id=user.to_string(), + content=content, + deletes=event_id, + ) + + msg_handler = self.handlers.message_handler + yield msg_handler.send_message(event) + + defer.returnValue((200, {"event_id": event.event_id})) + + @defer.inlineCallbacks + def on_PUT(self, request, room_id, event_id, txn_id): + try: + defer.returnValue(self.txns.get_client_transaction(request, txn_id)) + except KeyError: + pass + + response = yield self.on_POST(request, room_id, event_id) + + self.txns.store_client_transaction(request, txn_id, response) + defer.returnValue(response) + def _parse_json(request): try: @@ -485,3 +520,4 @@ def register_servlets(hs, http_server): PublicRoomListRestServlet(hs).register(http_server) RoomStateRestServlet(hs).register(http_server) RoomInitialSyncRestServlet(hs).register(http_server) + RoomDeleteEventRestServlet(hs).register(http_server) -- cgit 1.4.1 From 70899d3ab29cd57301fb135130c940f312bfe482 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Wed, 24 Sep 2014 15:27:59 +0100 Subject: Rename deletions to redactions --- synapse/api/auth.py | 18 +++++++++--------- synapse/api/events/__init__.py | 4 ++-- synapse/api/events/factory.py | 4 ++-- synapse/api/events/room.py | 6 +++--- synapse/api/events/utils.py | 4 ++-- synapse/handlers/room.py | 2 +- synapse/rest/room.py | 12 ++++++------ synapse/storage/__init__.py | 23 ++++++++++++----------- synapse/storage/_base.py | 18 +++++++++--------- synapse/storage/room.py | 8 ++++---- synapse/storage/roommember.py | 6 +++--- synapse/storage/schema/deletions.sql | 7 ------- synapse/storage/schema/delta/v4.sql | 11 ++++++----- synapse/storage/schema/im.sql | 2 +- synapse/storage/schema/redactions.sql | 8 ++++++++ synapse/storage/stream.py | 18 +++++++++--------- 16 files changed, 77 insertions(+), 74 deletions(-) delete mode 100644 synapse/storage/schema/deletions.sql create mode 100644 synapse/storage/schema/redactions.sql (limited to 'synapse/rest') diff --git a/synapse/api/auth.py b/synapse/api/auth.py index fb14d9a2b3..9c65d47fb4 100644 --- a/synapse/api/auth.py +++ b/synapse/api/auth.py @@ -20,7 +20,7 @@ from twisted.internet import defer from synapse.api.constants import Membership, JoinRules from synapse.api.errors import AuthError, StoreError, Codes, SynapseError from synapse.api.events.room import ( - RoomMemberEvent, RoomPowerLevelsEvent, RoomDeletionEvent, + RoomMemberEvent, RoomPowerLevelsEvent, RoomRedactionEvent, ) from synapse.util.logutils import log_function @@ -72,8 +72,8 @@ class Auth(object): if event.type == RoomPowerLevelsEvent.TYPE: yield self._check_power_levels(event) - if event.type == RoomDeletionEvent.TYPE: - yield self._check_deletion(event) + if event.type == RoomRedactionEvent.TYPE: + yield self._check_redaction(event) defer.returnValue(True) else: @@ -327,7 +327,7 @@ class Auth(object): ) @defer.inlineCallbacks - def _check_deletion(self, event): + def _check_redaction(self, event): user_level = yield self.store.get_power_level( event.room_id, event.user_id, @@ -338,15 +338,15 @@ class Auth(object): else: user_level = 0 - _, _, delete_level = yield self.store.get_ops_levels(event.room_id) + _, _, redact_level = yield self.store.get_ops_levels(event.room_id) - if not delete_level: - delete_level = 50 + if not redact_level: + redact_level = 50 - if user_level < delete_level: + if user_level < redact_level: raise AuthError( 403, - "You don't have permission to delete events" + "You don't have permission to redact events" ) @defer.inlineCallbacks diff --git a/synapse/api/events/__init__.py b/synapse/api/events/__init__.py index d68629209d..0ceb703c74 100644 --- a/synapse/api/events/__init__.py +++ b/synapse/api/events/__init__.py @@ -59,7 +59,7 @@ class SynapseEvent(JsonEncodedObject): "age_ts", "prev_content", "prev_state", - "pruned_because", + "redacted_because", ] internal_keys = [ @@ -70,7 +70,7 @@ class SynapseEvent(JsonEncodedObject): "origin", "outlier", "power_level", - "deleted", + "redacted", ] required_keys = [ diff --git a/synapse/api/events/factory.py b/synapse/api/events/factory.py index c65ea8372b..0d94850cec 100644 --- a/synapse/api/events/factory.py +++ b/synapse/api/events/factory.py @@ -18,7 +18,7 @@ from synapse.api.events.room import ( InviteJoinEvent, RoomConfigEvent, RoomNameEvent, GenericEvent, RoomPowerLevelsEvent, RoomJoinRulesEvent, RoomOpsPowerLevelsEvent, RoomCreateEvent, RoomAddStateLevelEvent, RoomSendEventLevelEvent, - RoomDeletionEvent, + RoomRedactionEvent, ) from synapse.util.stringutils import random_string @@ -40,7 +40,7 @@ class EventFactory(object): RoomAddStateLevelEvent, RoomSendEventLevelEvent, RoomOpsPowerLevelsEvent, - RoomDeletionEvent, + RoomRedactionEvent, ] def __init__(self, hs): diff --git a/synapse/api/events/room.py b/synapse/api/events/room.py index 9861395556..cd936074fc 100644 --- a/synapse/api/events/room.py +++ b/synapse/api/events/room.py @@ -182,10 +182,10 @@ class RoomAliasesEvent(SynapseStateEvent): return {} -class RoomDeletionEvent(SynapseEvent): - TYPE = "m.room.deletion" +class RoomRedactionEvent(SynapseEvent): + TYPE = "m.room.redaction" - valid_keys = SynapseEvent.valid_keys + ["deletes"] + valid_keys = SynapseEvent.valid_keys + ["redacts"] def get_content_template(self): return {} diff --git a/synapse/api/events/utils.py b/synapse/api/events/utils.py index 3d8b9a1db1..c3a32be8c1 100644 --- a/synapse/api/events/utils.py +++ b/synapse/api/events/utils.py @@ -23,7 +23,7 @@ def prune_event(event): """ Prunes the given event of all keys we don't know about or think could potentially be dodgy. - This is used when we "delete" an event. We want to remove all fields that + This is used when we "redact" an event. We want to remove all fields that the user has specified, but we do want to keep necessary information like type, state_key etc. """ @@ -55,7 +55,7 @@ def prune_event(event): elif event.type == RoomSendEventLevelEvent.TYPE: add_fields("level") elif event.type == RoomOpsPowerLevelsEvent.TYPE: - add_fields("kick_level", "ban_level", "delete_level") + add_fields("kick_level", "ban_level", "redact_level") elif event.type == RoomAliasesEvent.TYPE: add_fields("aliases") diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py index 18597c694d..b7a9d77ca2 100644 --- a/synapse/handlers/room.py +++ b/synapse/handlers/room.py @@ -255,7 +255,7 @@ class RoomCreationHandler(BaseHandler): etype=RoomOpsPowerLevelsEvent.TYPE, ban_level=50, kick_level=50, - delete_level=50, + redact_level=50, ) return [ diff --git a/synapse/rest/room.py b/synapse/rest/room.py index 85a1d2eae3..399084ae2a 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -19,7 +19,7 @@ from twisted.internet import defer from base import RestServlet, client_path_pattern from synapse.api.errors import SynapseError, Codes from synapse.streams.config import PaginationConfig -from synapse.api.events.room import RoomMemberEvent, RoomDeletionEvent +from synapse.api.events.room import RoomMemberEvent, RoomRedactionEvent from synapse.api.constants import Membership import json @@ -430,9 +430,9 @@ class RoomMembershipRestServlet(RestServlet): self.txns.store_client_transaction(request, txn_id, response) defer.returnValue(response) -class RoomDeleteEventRestServlet(RestServlet): +class RoomRedactEventRestServlet(RestServlet): def register(self, http_server): - PATTERN = ("/rooms/(?P[^/]*)/delete/(?P[^/]*)") + PATTERN = ("/rooms/(?P[^/]*)/redact/(?P[^/]*)") register_txn_path(self, PATTERN, http_server) @defer.inlineCallbacks @@ -441,11 +441,11 @@ class RoomDeleteEventRestServlet(RestServlet): content = _parse_json(request) event = self.event_factory.create_event( - etype=RoomDeletionEvent.TYPE, + etype=RoomRedactionEvent.TYPE, room_id=urllib.unquote(room_id), user_id=user.to_string(), content=content, - deletes=event_id, + redacts=event_id, ) msg_handler = self.handlers.message_handler @@ -520,4 +520,4 @@ def register_servlets(hs, http_server): PublicRoomListRestServlet(hs).register(http_server) RoomStateRestServlet(hs).register(http_server) RoomInitialSyncRestServlet(hs).register(http_server) - RoomDeleteEventRestServlet(hs).register(http_server) + RoomRedactEventRestServlet(hs).register(http_server) diff --git a/synapse/storage/__init__.py b/synapse/storage/__init__.py index accb4359bd..fcf8b4d183 100644 --- a/synapse/storage/__init__.py +++ b/synapse/storage/__init__.py @@ -24,7 +24,7 @@ from synapse.api.events.room import ( RoomAddStateLevelEvent, RoomSendEventLevelEvent, RoomOpsPowerLevelsEvent, - RoomDeletionEvent, + RoomRedactionEvent, ) from synapse.util.logutils import log_function @@ -57,7 +57,7 @@ SCHEMAS = [ "presence", "im", "room_aliases", - "deletions", + "redactions", ] @@ -184,8 +184,8 @@ class DataStore(RoomMemberStore, RoomStore, self._store_send_event_level(txn, event) elif event.type == RoomOpsPowerLevelsEvent.TYPE: self._store_ops_level(txn, event) - elif event.type == RoomDeletionEvent.TYPE: - self._store_deletion(txn, event) + elif event.type == RoomRedactionEvent.TYPE: + self._store_redaction(txn, event) vals = { "topological_ordering": event.depth, @@ -207,7 +207,7 @@ class DataStore(RoomMemberStore, RoomStore, unrec = { k: v for k, v in event.get_full_dict().items() - if k not in vals.keys() and k not in ["deleted", "pruned_because"] + if k not in vals.keys() and k not in ["redacted", "redacted_because"] } vals["unrecognized_keys"] = json.dumps(unrec) @@ -245,25 +245,26 @@ class DataStore(RoomMemberStore, RoomStore, } ) - def _store_deletion(self, txn, event): + def _store_redaction(self, txn, event): txn.execute( - "INSERT INTO deletions (event_id, deletes) VALUES (?,?) OR IGNORE", - (event.event_id, event.deletes) + "INSERT OR IGNORE INTO redactions " + "(event_id, redacts) VALUES (?,?)", + (event.event_id, event.redacts) ) @defer.inlineCallbacks def get_current_state(self, room_id, event_type=None, state_key=""): del_sql = ( - "SELECT event_id FROM deletions WHERE deletes = e.event_id" + "SELECT event_id FROM redactions WHERE redacts = e.event_id" ) sql = ( - "SELECT e.*, (%(deleted)s) AS deleted FROM events as e " + "SELECT e.*, (%(redacted)s) AS redacted FROM events as e " "INNER JOIN current_state_events as c ON e.event_id = c.event_id " "INNER JOIN state_events as s ON e.event_id = s.event_id " "WHERE c.room_id = ? " ) % { - "deleted": del_sql, + "redacted": del_sql, } if event_type: diff --git a/synapse/storage/_base.py b/synapse/storage/_base.py index 444e7628d1..889de2bedc 100644 --- a/synapse/storage/_base.py +++ b/synapse/storage/_base.py @@ -383,14 +383,14 @@ class SQLBaseStore(object): prev = self._parse_event_from_row(prevs[0]) ev.prev_content = prev.content - if not hasattr(ev, "deleted"): - logger.debug("Doesn't have deleted key: %s", ev) - ev.deleted = self._has_been_deleted_txn(txn, ev) + if not hasattr(ev, "redacted"): + logger.debug("Doesn't have redacted key: %s", ev) + ev.redacted = self._has_been_redacted_txn(txn, ev) - if ev.deleted: - # Get the deletion event. + if ev.redacted: + # Get the redaction event. sql = "SELECT * FROM events WHERE event_id = ?" - txn.execute(sql, (ev.deleted,)) + txn.execute(sql, (ev.redacted,)) del_evs = self._parse_events_txn( txn, self.cursor_to_dict(txn) @@ -398,12 +398,12 @@ class SQLBaseStore(object): if del_evs: prune_event(ev) - ev.pruned_because = del_evs[0] + ev.redacted_because = del_evs[0] return events - def _has_been_deleted_txn(self, txn, event): - sql = "SELECT event_id FROM deletions WHERE deletes = ?" + def _has_been_redacted_txn(self, txn, event): + sql = "SELECT event_id FROM redactions WHERE redacts = ?" txn.execute(sql, (event.event_id,)) result = txn.fetchone() return result[0] if result else None diff --git a/synapse/storage/room.py b/synapse/storage/room.py index b1239a0f1a..8cd46334cf 100644 --- a/synapse/storage/room.py +++ b/synapse/storage/room.py @@ -27,7 +27,7 @@ import logging logger = logging.getLogger(__name__) -OpsLevel = collections.namedtuple("OpsLevel", ("ban_level", "kick_level", "delete_level")) +OpsLevel = collections.namedtuple("OpsLevel", ("ban_level", "kick_level", "redact_level")) class RoomStore(SQLBaseStore): @@ -189,7 +189,7 @@ class RoomStore(SQLBaseStore): def _get_ops_levels(self, txn, room_id): sql = ( - "SELECT ban_level, kick_level, delete_level " + "SELECT ban_level, kick_level, redact_level " "FROM room_ops_levels as r " "INNER JOIN current_state_events as c " "ON r.event_id = c.event_id " @@ -327,8 +327,8 @@ class RoomStore(SQLBaseStore): if "ban_level" in event.content: content["ban_level"] = event.content["ban_level"] - if "delete_level" in event.content: - content["delete_level"] = event.content["delete_level"] + if "redact_level" in event.content: + content["redact_level"] = event.content["redact_level"] self._simple_insert_txn( txn, diff --git a/synapse/storage/roommember.py b/synapse/storage/roommember.py index 97222da571..84c462330b 100644 --- a/synapse/storage/roommember.py +++ b/synapse/storage/roommember.py @@ -183,18 +183,18 @@ class RoomMemberStore(SQLBaseStore): def _get_members_query_txn(self, txn, where_clause, where_values): del_sql = ( - "SELECT event_id FROM deletions WHERE deletes = e.event_id" + "SELECT event_id FROM redactions WHERE redacts = e.event_id" ) sql = ( - "SELECT e.*, (%(deleted)s) AS deleted FROM events as e " + "SELECT e.*, (%(redacted)s) AS redacted FROM events as e " "INNER JOIN room_memberships as m " "ON e.event_id = m.event_id " "INNER JOIN current_state_events as c " "ON m.event_id = c.event_id " "WHERE %(where)s " ) % { - "deleted": del_sql, + "redacted": del_sql, "where": where_clause, } diff --git a/synapse/storage/schema/deletions.sql b/synapse/storage/schema/deletions.sql deleted file mode 100644 index 2e2635317a..0000000000 --- a/synapse/storage/schema/deletions.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE IF NOT EXISTS deletions ( - event_id TEXT NOT NULL, - deletes TEXT NOT NULL -); - -CREATE INDEX IF NOT EXISTS deletions_event_id ON deletions (event_id); -CREATE INDEX IF NOT EXISTS deletions_deletes ON deletions (deletes); diff --git a/synapse/storage/schema/delta/v4.sql b/synapse/storage/schema/delta/v4.sql index fc8bb5ad84..25d2ead450 100644 --- a/synapse/storage/schema/delta/v4.sql +++ b/synapse/storage/schema/delta/v4.sql @@ -1,11 +1,12 @@ -CREATE TABLE IF NOT EXISTS deletions ( +CREATE TABLE IF NOT EXISTS redactions ( event_id TEXT NOT NULL, - deletes TEXT NOT NULL + redacts TEXT NOT NULL, + CONSTRAINT ev_uniq UNIQUE (event_id) ); -CREATE INDEX IF NOT EXISTS deletions_event_id ON deletions (event_id); -CREATE INDEX IF NOT EXISTS deletions_deletes ON deletions (deletes); +CREATE INDEX IF NOT EXISTS redactions_event_id ON redactions (event_id); +CREATE INDEX IF NOT EXISTS redactions_redacts ON redactions (redacts); -ALTER TABLE room_ops_levels ADD COLUMN delete_level INTEGER; +ALTER TABLE room_ops_levels ADD COLUMN redact_level INTEGER; PRAGMA user_version = 4; diff --git a/synapse/storage/schema/im.sql b/synapse/storage/schema/im.sql index 649d54b813..3aa83f5c8c 100644 --- a/synapse/storage/schema/im.sql +++ b/synapse/storage/schema/im.sql @@ -151,7 +151,7 @@ CREATE TABLE IF NOT EXISTS room_ops_levels( room_id TEXT NOT NULL, ban_level INTEGER, kick_level INTEGER, - delete_level INTEGER + redact_level INTEGER ); CREATE INDEX IF NOT EXISTS room_ops_levels_event_id ON room_ops_levels(event_id); diff --git a/synapse/storage/schema/redactions.sql b/synapse/storage/schema/redactions.sql new file mode 100644 index 0000000000..4c2829d05d --- /dev/null +++ b/synapse/storage/schema/redactions.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS redactions ( + event_id TEXT NOT NULL, + redacts TEXT NOT NULL, + CONSTRAINT ev_uniq UNIQUE (event_id) +); + +CREATE INDEX IF NOT EXISTS redactions_event_id ON redactions (event_id); +CREATE INDEX IF NOT EXISTS redactions_redacts ON redactions (redacts); diff --git a/synapse/storage/stream.py b/synapse/storage/stream.py index aaac0aae30..91baa18319 100644 --- a/synapse/storage/stream.py +++ b/synapse/storage/stream.py @@ -158,7 +158,7 @@ class StreamStore(SQLBaseStore): ) del_sql = ( - "SELECT event_id FROM deletions WHERE deletes = e.event_id" + "SELECT event_id FROM redactions WHERE redacts = e.event_id" ) if limit: @@ -175,14 +175,14 @@ class StreamStore(SQLBaseStore): return sql = ( - "SELECT *, (%(deleted)s) AS deleted FROM events AS e WHERE " + "SELECT *, (%(redacted)s) AS redacted FROM events AS e WHERE " "((room_id IN (%(current)s)) OR " "(event_id IN (%(invites)s))) " "AND e.stream_ordering > ? AND e.stream_ordering <= ? " "AND e.outlier = 0 " "ORDER BY stream_ordering ASC LIMIT %(limit)d " ) % { - "deleted": del_sql, + "redacted": del_sql, "current": current_room_membership_sql, "invites": membership_sql, "limit": limit @@ -230,15 +230,15 @@ class StreamStore(SQLBaseStore): limit_str = "" del_sql = ( - "SELECT event_id FROM deletions WHERE deletes = events.event_id" + "SELECT event_id FROM redactions WHERE redacts = events.event_id" ) sql = ( - "SELECT *, (%(deleted)s) AS deleted FROM events " + "SELECT *, (%(redacted)s) AS redacted FROM events " "WHERE outlier = 0 AND room_id = ? AND %(bounds)s " "ORDER BY topological_ordering %(order)s, stream_ordering %(order)s %(limit)s " ) % { - "deleted": del_sql, + "redacted": del_sql, "bounds": bounds, "order": order, "limit": limit_str @@ -272,15 +272,15 @@ class StreamStore(SQLBaseStore): # TODO (erikj): Handle compressed feedback del_sql = ( - "SELECT event_id FROM deletions WHERE deletes = events.event_id" + "SELECT event_id FROM redactions WHERE redacts = events.event_id" ) sql = ( - "SELECT *, (%(deleted)s) AS deleted FROM events " + "SELECT *, (%(redacted)s) AS redacted FROM events " "WHERE room_id = ? AND stream_ordering <= ? " "ORDER BY topological_ordering DESC, stream_ordering DESC LIMIT ? " ) % { - "deleted": del_sql, + "redacted": del_sql, } rows = yield self._execute_and_decode( -- cgit 1.4.1