diff options
-rw-r--r-- | synapse/api/constants.py | 7 | ||||
-rw-r--r-- | synapse/api/events/__init__.py | 7 | ||||
-rw-r--r-- | synapse/api/events/factory.py | 8 | ||||
-rw-r--r-- | synapse/api/events/room.py | 30 | ||||
-rw-r--r-- | synapse/handlers/room.py | 73 | ||||
-rw-r--r-- | synapse/storage/__init__.py | 9 | ||||
-rw-r--r-- | synapse/storage/room.py | 80 | ||||
-rw-r--r-- | synapse/storage/schema/im.sql | 32 |
8 files changed, 225 insertions, 21 deletions
diff --git a/synapse/api/constants.py b/synapse/api/constants.py index f69f2445a2..9b5b9f5936 100644 --- a/synapse/api/constants.py +++ b/synapse/api/constants.py @@ -42,3 +42,10 @@ class PresenceState(object): UNAVAILABLE = u"unavailable" ONLINE = u"online" FREE_FOR_CHAT = u"free_for_chat" + + +class JoinRules(object): + PUBLIC = u"public" + KNOCK = u"knock" + INVITE = u"invite" + PRIVATE = u"private" diff --git a/synapse/api/events/__init__.py b/synapse/api/events/__init__.py index f9653e0b2a..bf8d288acc 100644 --- a/synapse/api/events/__init__.py +++ b/synapse/api/events/__init__.py @@ -152,3 +152,10 @@ class SynapseEvent(JsonEncodedObject): msg = self._check_json(entry, template[key][0]) if msg: return msg + + +class SynapseStateEvent(SynapseEvent): + def __init__(self, **kwargs): + if "state_key" not in kwargs: + kwargs["state_key"] = "" + super(SynapseStateEvent, self).__init__(**kwargs) diff --git a/synapse/api/events/factory.py b/synapse/api/events/factory.py index c2cdcddf41..7c1259d617 100644 --- a/synapse/api/events/factory.py +++ b/synapse/api/events/factory.py @@ -16,6 +16,8 @@ from synapse.api.events.room import ( RoomTopicEvent, MessageEvent, RoomMemberEvent, FeedbackEvent, InviteJoinEvent, RoomConfigEvent, RoomNameEvent, GenericEvent, + RoomPowerLevelsEvent, RoomDefaultLevelEvent, RoomJoinRulesEvent, + RoomCreateEvent, ) from synapse.util.stringutils import random_string @@ -30,7 +32,11 @@ class EventFactory(object): RoomMemberEvent, FeedbackEvent, InviteJoinEvent, - RoomConfigEvent + RoomConfigEvent, + RoomPowerLevelsEvent, + RoomDefaultLevelEvent, + RoomJoinRulesEvent, + RoomCreateEvent, ] def __init__(self, hs): diff --git a/synapse/api/events/room.py b/synapse/api/events/room.py index 9faad57ac0..b63529bb31 100644 --- a/synapse/api/events/room.py +++ b/synapse/api/events/room.py @@ -15,7 +15,7 @@ from synapse.api.constants import Feedback, Membership from synapse.api.errors import SynapseError -from . import SynapseEvent +from . import SynapseEvent, SynapseStateEvent class GenericEvent(SynapseEvent): @@ -132,3 +132,31 @@ class RoomConfigEvent(SynapseEvent): def get_content_template(self): return {} + + +class RoomCreateEvent(SynapseStateEvent): + TYPE = "m.room.create" + + def get_content_template(self): + return {} + + +class RoomJoinRulesEvent(SynapseStateEvent): + TYPE = "m.room.join_rules" + + def get_content_template(self): + return {} + + +class RoomPowerLevelsEvent(SynapseStateEvent): + TYPE = "m.room.power_levels" + + def get_content_template(self): + return {} + + +class RoomDefaultLevelEvent(SynapseStateEvent): + TYPE = "m.room.default_level" + + def get_content_template(self): + return {} diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py index c54e0f963b..11afd34ae2 100644 --- a/synapse/handlers/room.py +++ b/synapse/handlers/room.py @@ -17,10 +17,11 @@ from twisted.internet import defer from synapse.types import UserID, RoomAlias, RoomID -from synapse.api.constants import Membership +from synapse.api.constants import Membership, JoinRules from synapse.api.errors import StoreError, SynapseError from synapse.api.events.room import ( - RoomMemberEvent, RoomConfigEvent + RoomMemberEvent, RoomCreateEvent, RoomPowerLevelsEvent, + RoomJoinRulesEvent, RoomDefaultLevelEvent, ) from synapse.util import stringutils from ._base import BaseRoomHandler @@ -62,6 +63,8 @@ class RoomCreationHandler(BaseRoomHandler): else: room_alias = None + is_public = config.get("visibility", None) == "public" + if room_id: # Ensure room_id is the correct type room_id_obj = RoomID.from_string(room_id, self.hs) @@ -71,7 +74,7 @@ class RoomCreationHandler(BaseRoomHandler): yield self.store.store_room( room_id=room_id, room_creator_user_id=user_id, - is_public=config["visibility"] == "public" + is_public=is_public ) else: # autogen room IDs and try to create it. We may clash, so just @@ -85,7 +88,7 @@ class RoomCreationHandler(BaseRoomHandler): yield self.store.store_room( room_id=gen_room_id.to_string(), room_creator_user_id=user_id, - is_public=config["visibility"] == "public" + is_public=is_public ) room_id = gen_room_id.to_string() break @@ -94,18 +97,10 @@ class RoomCreationHandler(BaseRoomHandler): if not room_id: raise StoreError(500, "Couldn't generate a room ID.") - config_event = self.event_factory.create_event( - etype=RoomConfigEvent.TYPE, - room_id=room_id, - user_id=user_id, - content=config, - ) - snapshot = yield self.store.snapshot_room( - room_id=room_id, - user_id=user_id, - state_type=RoomConfigEvent.TYPE, - state_key="", + user = self.hs.parse_userid(user_id) + creation_events = self._create_events_for_new_room( + user, room_id, is_public=is_public ) if room_alias: @@ -115,11 +110,18 @@ class RoomCreationHandler(BaseRoomHandler): servers=[self.hs.hostname], ) - yield self.state_handler.handle_new_event(config_event, snapshot) - # store_id = persist... - federation_handler = self.hs.get_handlers().federation_handler - yield federation_handler.handle_new_event(config_event, snapshot) + + for event in creation_events: + snapshot = yield self.store.snapshot_room( + room_id=room_id, + user_id=user_id, + ) + + logger.debug("Event: %s", event) + + yield self.state_handler.handle_new_event(event, snapshot) + yield self._on_new_room_event(event, snapshot, extra_users=[user]) content = {"membership": Membership.JOIN} join_event = self.event_factory.create_event( @@ -142,6 +144,39 @@ class RoomCreationHandler(BaseRoomHandler): defer.returnValue(result) + def _create_events_for_new_room(self, creator, room_id, is_public=False): + event_keys = { + "room_id": room_id, + "user_id": creator.to_string(), + } + + creation_event = self.event_factory.create_event( + etype=RoomCreateEvent.TYPE, + content={"creator": creator.to_string()}, + **event_keys + ) + + power_levels_event = self.event_factory.create_event( + etype=RoomPowerLevelsEvent.TYPE, + content={creator.to_string(): 10}, + **event_keys + ) + + default_level_event = self.event_factory.create_event( + etype=RoomDefaultLevelEvent.TYPE, + content={"default_level": 0}, + **event_keys + ) + + join_rule = JoinRules.PUBLIC if is_public else JoinRules.INVITE + join_rules_event = self.event_factory.create_event( + etype=RoomJoinRulesEvent.TYPE, + content={"join_rule": join_rule}, + **event_keys + ) + + return [creation_event, power_levels_event, default_level_event, join_rules_event] + class RoomMemberHandler(BaseRoomHandler): # TODO(paul): This handler currently contains a messy conflation of diff --git a/synapse/storage/__init__.py b/synapse/storage/__init__.py index e8faba3eeb..204a243560 100644 --- a/synapse/storage/__init__.py +++ b/synapse/storage/__init__.py @@ -19,6 +19,9 @@ from synapse.api.events.room import ( RoomMemberEvent, RoomTopicEvent, FeedbackEvent, # RoomConfigEvent, RoomNameEvent, + RoomJoinRulesEvent, + RoomPowerLevelsEvent, + RoomDefaultLevelEvent, ) from synapse.util.logutils import log_function @@ -129,6 +132,12 @@ class DataStore(RoomMemberStore, RoomStore, self._store_room_name_txn(txn, event) elif event.type == RoomTopicEvent.TYPE: self._store_room_topic_txn(txn, event) + elif event.type == RoomJoinRulesEvent.TYPE: + self._store_join_rule(txn, event) + elif event.type == RoomPowerLevelsEvent.TYPE: + self._store_power_levels(txn, event) + elif event.type == RoomDefaultLevelEvent.TYPE: + self._store_default_level(txn, event) vals = { "topological_ordering": event.depth, diff --git a/synapse/storage/room.py b/synapse/storage/room.py index d1f1a232f8..8946ce99f7 100644 --- a/synapse/storage/room.py +++ b/synapse/storage/room.py @@ -129,6 +129,51 @@ class RoomStore(SQLBaseStore): defer.returnValue(ret) + @defer.inlineCallbacks + def get_room_join_rule(self, room_id): + sql = ( + "SELECT join_rule FROM room_join_rules as r " + "INNER JOIN current_state_events as c " + "ON r.event_id = c.event_id " + "WHERE c.room_id = ? " + ) + + rows = yield self._execute(None, sql, room_id) + + if len(rows) == 1: + defer.returnValue(rows[0][0]) + else: + defer.returnValue(None) + + @defer.inlineCallbacks + def get_power_level(self, room_id, user_id): + sql = ( + "SELECT level FROM room_power_levels as r " + "INNER JOIN current_state_events as c " + "ON r.event_id = c.event_id " + "WHERE c.room_id = ? AND r.user_id = ? " + ) + + rows = yield self._execute(None, sql, room_id, user_id) + + if len(rows) == 1: + defer.returnValue(rows[0][0]) + return + + sql = ( + "SELECT level FROM room_default_levels as r " + "INNER JOIN current_state_events as c " + "ON r.event_id = c.event_id " + "WHERE c.room_id = ? " + ) + + rows = yield self._execute(None, sql, room_id) + + if len(rows) == 1: + defer.returnValue(rows[0][0]) + else: + defer.returnValue(None) + def _store_room_topic_txn(self, txn, event): self._simple_insert_txn( txn, @@ -151,6 +196,41 @@ class RoomStore(SQLBaseStore): } ) + def _store_join_rule(txn, event): + self._simple_insert_txn( + txn, + "room_join_rules", + { + "event_id": event.event_id, + "room_id": event.room_id, + "join_rule": event.join_rule, + }, + ) + + def _store_power_levels(txn, event): + for user_id, level in event.content: + self._simple_insert_txn( + txn, + "room_power_levels", + { + "event_id": event.event_id, + "room_id": event.room_id, + "user_id": user_id, + "level": level + }, + ) + + def _store_default_level(txn, event): + self._simple_insert_txn( + txn, + "room_default_levels", + { + "event_id": event.event_id, + "room_id": event.room_id, + "level": level + }, + ) + class RoomsTable(Table): table_name = "rooms" diff --git a/synapse/storage/schema/im.sql b/synapse/storage/schema/im.sql index e92f21ef3b..c20516b7fa 100644 --- a/synapse/storage/schema/im.sql +++ b/synapse/storage/schema/im.sql @@ -96,8 +96,40 @@ CREATE TABLE IF NOT EXISTS rooms( creator TEXT ); +CREATE TABLE IF NOT EXISTS room_join_rules( + event_id TEXT NOT NULL, + room_id TEXT NOT NULL, + join_rule TEXT NOT NULL +); +CREATE INDEX IF NOT EXISTS room_join_rules_event_id ON room_join_rules(event_id); +CREATE INDEX IF NOT EXISTS room_join_rules_room_id ON room_join_rules(room_id); + + +CREATE TABLE IF NOT EXISTS room_power_levels( + event_id TEXT NOT NULL, + room_id TEXT NOT NULL, + user_id TEXT NOT NULL, + level INTEGER NOT NULL +); +CREATE INDEX IF NOT EXISTS room_power_levels_event_id ON room_power_levels(event_id); +CREATE INDEX IF NOT EXISTS room_power_levels_room_id ON room_power_levels(room_id); +CREATE INDEX IF NOT EXISTS room_power_levels_room_user ON room_power_levels(room_id, user_id); + + +CREATE TABLE IF NOT EXISTS room_default_levels( + event_id TEXT NOT NULL, + room_id TEXT NOT NULL, + level INTEGER NOT NULL +); + +CREATE INDEX IF NOT EXISTS room_default_levels_event_id ON room_default_levels(event_id); +CREATE INDEX IF NOT EXISTS room_default_levels_room_id ON room_default_levels(room_id); + + CREATE TABLE IF NOT EXISTS room_hosts( room_id TEXT NOT NULL, host TEXT NOT NULL, CONSTRAINT room_hosts_uniq UNIQUE (room_id, host) ON CONFLICT IGNORE ); + +CREATE INDEX IF NOT EXISTS room_hosts_room_id ON room_hosts (room_id); |