From cab3095803db0c046f414959d12e3549505f54c4 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 26 Aug 2014 09:26:07 +0100 Subject: [PATCH] Removed member list servlet: now using generic state paths. --- cmdclient/console.py | 6 +- synapse/api/auth.py | 12 ++-- synapse/api/constants.py | 1 + synapse/api/events/room.py | 10 ++-- synapse/api/notifier.py | 4 +- synapse/handlers/federation.py | 2 +- synapse/handlers/room.py | 16 ++--- synapse/rest/room.py | 103 +++++++-------------------------- synapse/storage/roommember.py | 5 +- 9 files changed, 53 insertions(+), 106 deletions(-) diff --git a/cmdclient/console.py b/cmdclient/console.py index 64557a4c4..3c4c69c27 100755 --- a/cmdclient/console.py +++ b/cmdclient/console.py @@ -402,9 +402,7 @@ class SynapseCmd(cmd.Cmd): """Leaves a room: "leave " """ try: args = self._parse(line, ["roomid"], force_keys=True) - path = ("/rooms/%s/members/%s/state" % - (urllib.quote(args["roomid"]), self._usr())) - reactor.callFromThread(self._run_and_pprint, "DELETE", path) + self._do_membership_change(urllib.quote(args["roomid"]), "leave", self._usr()) except Exception as e: print e @@ -567,7 +565,7 @@ class SynapseCmd(cmd.Cmd): alt_text="Sent receipt for %s" % event["msg_id"]) def _do_membership_change(self, roomid, membership, userid): - path = "/rooms/%s/members/%s/state" % (urllib.quote(roomid), userid) + path = "/rooms/%s/state/m.room.member/%s" % (urllib.quote(roomid), urllib.quote(userid)) data = { "membership": membership } diff --git a/synapse/api/auth.py b/synapse/api/auth.py index ae61319a2..385f93763 100644 --- a/synapse/api/auth.py +++ b/synapse/api/auth.py @@ -77,6 +77,8 @@ class Auth(object): @defer.inlineCallbacks def is_membership_change_allowed(self, event): + target_user_id = event.state_key + # does this room even exist room = yield self.store.get_room(event.room_id) if not room: @@ -94,7 +96,7 @@ class Auth(object): # get info about the target try: target = yield self.store.get_room_member( - user_id=event.target_user_id, + user_id=target_user_id, room_id=event.room_id) except: target = None @@ -108,12 +110,12 @@ class Auth(object): raise AuthError(403, "You are not in room %s." % event.room_id) elif target_in_room: # the target is already in the room. raise AuthError(403, "%s is already in the room." % - event.target_user_id) + target_user_id) elif Membership.JOIN == membership: # Joins are valid iff caller == target and they were: # invited: They are accepting the invitation # joined: It's a NOOP - if event.user_id != event.target_user_id: + if event.user_id != target_user_id: raise AuthError(403, "Cannot force another user to join.") elif room.is_public: pass # anyone can join public rooms. @@ -123,10 +125,10 @@ class Auth(object): elif Membership.LEAVE == membership: if not caller_in_room: # trying to leave a room you aren't joined raise AuthError(403, "You are not in room %s." % event.room_id) - elif event.target_user_id != event.user_id: + elif target_user_id != event.user_id: # trying to force another user to leave raise AuthError(403, "Cannot force %s to leave." % - event.target_user_id) + target_user_id) else: raise AuthError(500, "Unknown membership %s" % membership) diff --git a/synapse/api/constants.py b/synapse/api/constants.py index 1ff1af76e..2af542402 100644 --- a/synapse/api/constants.py +++ b/synapse/api/constants.py @@ -23,6 +23,7 @@ class Membership(object): JOIN = u"join" KNOCK = u"knock" LEAVE = u"leave" + LIST = (INVITE, JOIN, KNOCK, LEAVE) class Feedback(object): diff --git a/synapse/api/events/room.py b/synapse/api/events/room.py index 42459f3f2..2a7b5e8ab 100644 --- a/synapse/api/events/room.py +++ b/synapse/api/events/room.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from synapse.api.constants import Membership +from synapse.api.errors import SynapseError from . import SynapseEvent @@ -59,15 +61,15 @@ class RoomMemberEvent(SynapseEvent): TYPE = "m.room.member" valid_keys = SynapseEvent.valid_keys + [ - "target_user_id", # target + # target is the state_key "membership", # action ] def __init__(self, **kwargs): - if "target_user_id" in kwargs: - kwargs["state_key"] = kwargs["target_user_id"] if "membership" not in kwargs: kwargs["membership"] = kwargs.get("content", {}).get("membership") + if not kwargs["membership"] in Membership.LIST: + raise SynapseError(400, "Bad membership value.") super(RoomMemberEvent, self).__init__(**kwargs) def get_content_template(self): @@ -108,7 +110,7 @@ class InviteJoinEvent(SynapseEvent): TYPE = "m.room.invite_join" valid_keys = SynapseEvent.valid_keys + [ - "target_user_id", + # target_user_id is the state_key "target_host", ] diff --git a/synapse/api/notifier.py b/synapse/api/notifier.py index 9f622df6b..ec9c4e513 100644 --- a/synapse/api/notifier.py +++ b/synapse/api/notifier.py @@ -56,11 +56,11 @@ class Notifier(object): # invites MUST prod the person being invited, who won't be in the room. if (event.type == RoomMemberEvent.TYPE and event.content["membership"] == Membership.INVITE): - member_list.append(event.target_user_id) + member_list.append(event.state_key) # similarly, LEAVEs must be sent to the person leaving if (event.type == RoomMemberEvent.TYPE and event.content["membership"] == Membership.LEAVE): - member_list.append(event.target_user_id) + member_list.append(event.state_key) for user_id in member_list: if user_id in self.stored_event_listeners: diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py index aa3bf273f..351bb3c08 100644 --- a/synapse/handlers/federation.py +++ b/synapse/handlers/federation.py @@ -56,7 +56,7 @@ class FederationHandler(BaseHandler): content.update({"membership": Membership.JOIN}) new_event = self.event_factory.create_event( etype=RoomMemberEvent.TYPE, - target_user_id=event.user_id, + state_key=event.user_id, room_id=event.room_id, user_id=event.user_id, membership=Membership.JOIN, diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py index 6229ee9bf..049b4884a 100644 --- a/synapse/handlers/room.py +++ b/synapse/handlers/room.py @@ -374,7 +374,7 @@ class RoomCreationHandler(BaseHandler): content = {"membership": Membership.JOIN} join_event = self.event_factory.create_event( etype=RoomMemberEvent.TYPE, - target_user_id=user_id, + state_key=user_id, room_id=room_id, user_id=user_id, membership=Membership.JOIN, @@ -502,9 +502,10 @@ class RoomMemberHandler(BaseHandler): Raises: SynapseError if there was a problem changing the membership. """ + target_user_id = event.state_key prev_state = yield self.store.get_room_member( - event.target_user_id, event.room_id + target_user_id, event.room_id ) if prev_state: @@ -530,7 +531,7 @@ class RoomMemberHandler(BaseHandler): yield self.auth.check(event, raises=True) prev_state = yield self.store.get_room_member( - event.target_user_id, event.room_id + target_user_id, event.room_id ) if prev_state and prev_state.membership == event.membership: # double same action, treat this event as a NOOP. @@ -563,7 +564,7 @@ class RoomMemberHandler(BaseHandler): content.update({"membership": Membership.JOIN}) new_event = self.event_factory.create_event( etype=RoomMemberEvent.TYPE, - target_user_id=joinee.to_string(), + state_key=joinee.to_string(), room_id=room_id, user_id=joinee.to_string(), membership=Membership.JOIN, @@ -576,7 +577,7 @@ class RoomMemberHandler(BaseHandler): @defer.inlineCallbacks def _do_join(self, event, room_host=None, do_auth=True): - joinee = self.hs.parse_userid(event.target_user_id) + joinee = self.hs.parse_userid(event.state_key) # room_id = RoomID.from_string(event.room_id, self.hs) room_id = event.room_id @@ -685,16 +686,17 @@ class RoomMemberHandler(BaseHandler): # If we're inviting someone, then we should also send it to that # HS. + target_user_id = event.state_key if membership == Membership.INVITE: host = UserID.from_string( - event.target_user_id, self.hs + target_user_id, self.hs ).domain destinations.append(host) # If we are joining a remote HS, include that. if membership == Membership.JOIN: host = UserID.from_string( - event.target_user_id, self.hs + target_user_id, self.hs ).domain destinations.append(host) diff --git a/synapse/rest/room.py b/synapse/rest/room.py index 975246986..a07e03198 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -18,9 +18,10 @@ from twisted.internet import defer from base import RestServlet, client_path_pattern from synapse.api.errors import SynapseError, Codes -from synapse.api.events.room import (RoomTopicEvent, MessageEvent, - RoomMemberEvent, FeedbackEvent) -from synapse.api.constants import Feedback, Membership +from synapse.api.events.room import ( + MessageEvent, RoomMemberEvent, FeedbackEvent +) +from synapse.api.constants import Feedback from synapse.api.streams import PaginationConfig import json @@ -131,8 +132,8 @@ class RoomStateEventRestServlet(RestServlet): data = yield msg_handler.get_room_data( user_id=user.to_string(), room_id=urllib.unquote(room_id), - event_type=event_type, - state_key=state_key, + event_type=urllib.unquote(event_type), + state_key=urllib.unquote(state_key), ) if not data: @@ -142,6 +143,7 @@ class RoomStateEventRestServlet(RestServlet): @defer.inlineCallbacks def on_PUT(self, request, room_id, event_type, state_key): user = yield self.auth.get_user_by_req(request) + event_type = urllib.unquote(event_type) content = _parse_json(request) @@ -150,14 +152,20 @@ class RoomStateEventRestServlet(RestServlet): content=content, room_id=urllib.unquote(room_id), user_id=user.to_string(), - state_key=state_key + state_key=urllib.unquote(state_key) ) - - msg_handler = self.handlers.message_handler - yield msg_handler.store_room_data( - event=event - ) - defer.returnValue((200, "")) + if event_type == RoomMemberEvent.TYPE: + # membership events are special + handler = self.handlers.room_member_handler + yield handler.change_membership(event) + defer.returnValue((200, "")) + else: + # store random bits of state + msg_handler = self.handlers.message_handler + yield msg_handler.store_room_data( + event=event + ) + defer.returnValue((200, "")) class JoinRoomAliasServlet(RestServlet): @@ -180,73 +188,6 @@ class JoinRoomAliasServlet(RestServlet): defer.returnValue((200, ret_dict)) -class RoomMemberRestServlet(RestServlet): - PATTERN = client_path_pattern("/rooms/(?P[^/]*)/members/" - + "(?P[^/]*)/state$") - - def get_event_type(self): - return RoomMemberEvent.TYPE - - @defer.inlineCallbacks - def on_GET(self, request, room_id, target_user_id): - room_id = urllib.unquote(room_id) - user = yield self.auth.get_user_by_req(request) - - handler = self.handlers.room_member_handler - member = yield handler.get_room_member( - room_id, - urllib.unquote(target_user_id), - user.to_string()) - if not member: - raise SynapseError(404, "Member not found.", - errcode=Codes.NOT_FOUND) - defer.returnValue((200, member.content)) - - @defer.inlineCallbacks - def on_DELETE(self, request, roomid, target_user_id): - user = yield self.auth.get_user_by_req(request) - - event = self.event_factory.create_event( - etype=self.get_event_type(), - target_user_id=urllib.unquote(target_user_id), - room_id=urllib.unquote(roomid), - user_id=user.to_string(), - membership=Membership.LEAVE, - content={"membership": Membership.LEAVE} - ) - - handler = self.handlers.room_member_handler - yield handler.change_membership(event) - defer.returnValue((200, "")) - - @defer.inlineCallbacks - def on_PUT(self, request, roomid, target_user_id): - user = yield self.auth.get_user_by_req(request) - - content = _parse_json(request) - if "membership" not in content: - raise SynapseError(400, "No membership key.", - errcode=Codes.BAD_JSON) - - valid_membership_values = [Membership.JOIN, Membership.INVITE] - if (content["membership"] not in valid_membership_values): - raise SynapseError(400, "Membership value must be %s." % ( - valid_membership_values,), errcode=Codes.BAD_JSON) - - event = self.event_factory.create_event( - etype=self.get_event_type(), - target_user_id=urllib.unquote(target_user_id), - room_id=urllib.unquote(roomid), - user_id=user.to_string(), - membership=content["membership"], - content=content - ) - - handler = self.handlers.room_member_handler - yield handler.change_membership(event) - defer.returnValue((200, "")) - - class MessageRestServlet(RestServlet): PATTERN = client_path_pattern("/rooms/(?P[^/]*)/messages/" + "(?P[^/]*)/(?P[^/]*)$") @@ -377,7 +318,7 @@ class RoomMemberListRestServlet(RestServlet): user_id=user.to_string()) for event in members["chunk"]: - target_user = self.hs.parse_userid(event["target_user_id"]) + target_user = self.hs.parse_userid(event["state_key"]) # Presence is an optional cache; don't fail if we can't fetch it try: presence_state = yield self.handlers.presence_handler.get_state( @@ -423,6 +364,7 @@ class RoomTriggerBackfill(RestServlet): res = [event.get_dict() for event in events] defer.returnValue((200, res)) + def _parse_json(request): try: content = json.loads(request.content.read()) @@ -436,7 +378,6 @@ def _parse_json(request): def register_servlets(hs, http_server): RoomStateEventRestServlet(hs).register(http_server) - RoomMemberRestServlet(hs).register(http_server) MessageRestServlet(hs).register(http_server) FeedbackRestServlet(hs).register(http_server) RoomCreateRestServlet(hs).register(http_server) diff --git a/synapse/storage/roommember.py b/synapse/storage/roommember.py index 89c87290c..1f8984b6e 100644 --- a/synapse/storage/roommember.py +++ b/synapse/storage/roommember.py @@ -35,13 +35,14 @@ class RoomMemberStore(SQLBaseStore): def _store_room_member(self, event): """Store a room member in the database. """ - domain = self.hs.parse_userid(event.target_user_id).domain + target_user_id = event.state_key + domain = self.hs.parse_userid(target_user_id).domain yield self._simple_insert( "room_memberships", { "event_id": event.event_id, - "user_id": event.target_user_id, + "user_id": target_user_id, "sender": event.user_id, "room_id": event.room_id, "membership": event.membership,