diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py
index 3e41d7a46b..53aa77405c 100644
--- a/synapse/handlers/room.py
+++ b/synapse/handlers/room.py
@@ -17,10 +17,12 @@
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, RoomAddStateLevelEvent, RoomTopicEvent,
+ RoomSendEventLevelEvent, RoomOpsPowerLevelsEvent, RoomNameEvent,
)
from synapse.util import stringutils
from ._base import BaseRoomHandler
@@ -62,6 +64,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 +75,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 +89,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 +98,9 @@ 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,46 @@ 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)
+
+ @defer.inlineCallbacks
+ def handle_event(event):
+ 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])
+
+ for event in creation_events:
+ yield handle_event(event)
+
+ if "name" in config:
+ name = config["name"]
+ name_event = self.event_factory.create_event(
+ etype=RoomNameEvent.TYPE,
+ room_id=room_id,
+ user_id=user_id,
+ required_power_level=5,
+ content={"name": name},
+ )
+
+ yield handle_event(name_event)
+
+ if "topic" in config:
+ topic = config["topic"]
+ topic_event = self.event_factory.create_event(
+ etype=RoomTopicEvent.TYPE,
+ room_id=room_id,
+ user_id=user_id,
+ required_power_level=5,
+ content={"topic": topic},
+ )
+
+ yield handle_event(topic_event)
content = {"membership": Membership.JOIN}
join_event = self.event_factory.create_event(
@@ -142,6 +172,62 @@ 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(),
+ "required_power_level": 10,
+ }
+
+ def create(etype, **content):
+ return self.event_factory.create_event(
+ etype=etype,
+ content=content,
+ **event_keys
+ )
+
+ creation_event = create(
+ etype=RoomCreateEvent.TYPE,
+ creator=creator.to_string(),
+ )
+
+ power_levels_event = self.event_factory.create_event(
+ etype=RoomPowerLevelsEvent.TYPE,
+ content={creator.to_string(): 10, "default": 0},
+ **event_keys
+ )
+
+ join_rule = JoinRules.PUBLIC if is_public else JoinRules.INVITE
+ join_rules_event = create(
+ etype=RoomJoinRulesEvent.TYPE,
+ join_rule=join_rule,
+ )
+
+ add_state_event = create(
+ etype=RoomAddStateLevelEvent.TYPE,
+ level=10,
+ )
+
+ send_event = create(
+ etype=RoomSendEventLevelEvent.TYPE,
+ level=0,
+ )
+
+ ops = create(
+ etype=RoomOpsPowerLevelsEvent.TYPE,
+ ban_level=5,
+ kick_level=5,
+ )
+
+ return [
+ creation_event,
+ power_levels_event,
+ join_rules_event,
+ add_state_event,
+ send_event,
+ ops,
+ ]
+
class RoomMemberHandler(BaseRoomHandler):
# TODO(paul): This handler currently contains a messy conflation of
@@ -285,6 +371,16 @@ class RoomMemberHandler(BaseRoomHandler):
if do_auth:
yield self.auth.check(event, snapshot, raises=True)
+ # If we're banning someone, set a req power level
+ if event.membership == Membership.BAN:
+ if not hasattr(event, "required_power_level") or event.required_power_level is None:
+ # Add some default required_power_level
+ user_level = yield self.store.get_power_level(
+ event.room_id,
+ event.user_id,
+ )
+ event.required_power_level = user_level
+
if prev_state and prev_state.membership == event.membership:
# double same action, treat this event as a NOOP.
defer.returnValue({})
@@ -445,10 +541,9 @@ class RoomMemberHandler(BaseRoomHandler):
host = target_user.domain
destinations.append(host)
- # If we are joining a remote HS, include that.
- if membership == Membership.JOIN:
- host = target_user.domain
- destinations.append(host)
+ # Always include target domain
+ host = target_user.domain
+ destinations.append(host)
return self._on_new_room_event(
event, snapshot, extra_destinations=destinations,
@@ -462,3 +557,49 @@ class RoomListHandler(BaseRoomHandler):
chunk = yield self.store.get_rooms(is_public=True)
# FIXME (erikj): START is no longer a valid value
defer.returnValue({"start": "START", "end": "END", "chunk": chunk})
+
+
+class RoomEventSource(object):
+ def __init__(self, hs):
+ self.store = hs.get_datastore()
+
+ @defer.inlineCallbacks
+ def get_new_events_for_user(self, user, from_key, limit):
+ # We just ignore the key for now.
+
+ to_key = yield self.get_current_key()
+
+ events, end_key = yield self.store.get_room_events_stream(
+ user_id=user.to_string(),
+ from_key=from_key,
+ to_key=to_key,
+ room_id=None,
+ limit=limit,
+ )
+
+ defer.returnValue((events, end_key))
+
+ def get_current_key(self):
+ return self.store.get_room_events_max_id()
+
+ @defer.inlineCallbacks
+ def get_pagination_rows(self, user, pagination_config, key):
+ from_token = pagination_config.from_token
+ to_token = pagination_config.to_token
+ limit = pagination_config.limit
+ direction = pagination_config.direction
+
+ to_key = to_token.room_key if to_token else None
+
+ events, next_key = yield self.store.paginate_room_events(
+ room_id=key,
+ from_key=from_token.room_key,
+ to_key=to_key,
+ direction=direction,
+ limit=limit,
+ with_feedback=True
+ )
+
+ next_token = from_token.copy_and_replace("room_key", next_key)
+
+ defer.returnValue((events, next_token))
|