summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xcmdclient/console.py7
-rw-r--r--synapse/api/constants.py4
-rw-r--r--synapse/api/events/room.py16
-rw-r--r--synapse/rest/initial_sync.py1
-rw-r--r--synapse/rest/room.py158
-rw-r--r--synapse/storage/feedback.py4
-rw-r--r--tests/rest/test_events.py2
-rw-r--r--tests/rest/test_rooms.py35
-rw-r--r--tests/rest/utils.py8
-rw-r--r--webclient/components/matrix/matrix-service.js11
10 files changed, 85 insertions, 161 deletions
diff --git a/cmdclient/console.py b/cmdclient/console.py
index f997b7539c..4cb604e796 100755
--- a/cmdclient/console.py
+++ b/cmdclient/console.py
@@ -409,10 +409,9 @@ class SynapseCmd(cmd.Cmd):
     def do_send(self, line):
         """Sends a message. "send <roomid> <body>" """
         args = self._parse(line, ["roomid", "body"])
-        msg_id = "m%s" % int(time.time())
-        path = "/rooms/%s/messages/%s/%s" % (urllib.quote(args["roomid"]),
-                                             self._usr(),
-                                             msg_id)
+        txn_id = "txn%s" % int(time.time())
+        path = "/rooms/%s/send/m.room.message/%s" % (urllib.quote(args["roomid"]),
+                                             txn_id)
         body_json = {
             "msgtype": "m.text",
             "body": args["body"]
diff --git a/synapse/api/constants.py b/synapse/api/constants.py
index 2af5424029..f69f2445a2 100644
--- a/synapse/api/constants.py
+++ b/synapse/api/constants.py
@@ -31,8 +31,8 @@ class Feedback(object):
     """Represents the types of feedback a user can send in response to a
     message."""
 
-    DELIVERED = u"d"
-    READ = u"r"
+    DELIVERED = u"delivered"
+    READ = u"read"
     LIST = (DELIVERED, READ)
 
 
diff --git a/synapse/api/events/room.py b/synapse/api/events/room.py
index 2a7b5e8aba..9faad57ac0 100644
--- a/synapse/api/events/room.py
+++ b/synapse/api/events/room.py
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from synapse.api.constants import Membership
+from synapse.api.constants import Feedback, Membership
 from synapse.api.errors import SynapseError
 from . import SynapseEvent
 
@@ -93,17 +93,19 @@ class MessageEvent(SynapseEvent):
 class FeedbackEvent(SynapseEvent):
     TYPE = "m.room.message.feedback"
 
-    valid_keys = SynapseEvent.valid_keys + [
-        "msg_id",  # the message ID being acknowledged
-        "msg_sender_id",  # person who is sending the feedback is 'user_id'
-        "feedback_type",  # the type of feedback (delivery, read, etc)
-    ]
+    valid_keys = SynapseEvent.valid_keys
 
     def __init__(self, **kwargs):
         super(FeedbackEvent, self).__init__(**kwargs)
+        if not kwargs["content"]["type"] in Feedback.LIST:
+            raise SynapseError(400, "Bad feedback value.")
 
     def get_content_template(self):
-        return {}
+        return {
+            "type": u"string",
+            "target_event_id": u"string",
+            "msg_sender_id": u"string"
+        }
 
 
 class InviteJoinEvent(SynapseEvent):
diff --git a/synapse/rest/initial_sync.py b/synapse/rest/initial_sync.py
index e5059ff78c..d18c4c0f60 100644
--- a/synapse/rest/initial_sync.py
+++ b/synapse/rest/initial_sync.py
@@ -19,6 +19,7 @@ from synapse.streams.config import PaginationConfig
 from base import RestServlet, client_path_pattern
 
 
+# TODO: Needs unit testing
 class InitialSyncRestServlet(RestServlet):
     PATTERN = client_path_pattern("/initialSync$")
 
diff --git a/synapse/rest/room.py b/synapse/rest/room.py
index ab05a7438d..9363acebed 100644
--- a/synapse/rest/room.py
+++ b/synapse/rest/room.py
@@ -96,6 +96,7 @@ class RoomCreateRestServlet(RestServlet):
         return (200, {})
 
 
+# TODO: Needs unit testing for generic events
 class RoomStateEventRestServlet(RestServlet):
     def register(self, http_server):
         # /room/$roomid/state/$eventtype
@@ -168,143 +169,68 @@ class RoomStateEventRestServlet(RestServlet):
             defer.returnValue((200, ""))
 
 
-class JoinRoomAliasServlet(RestServlet):
-    PATTERN = client_path_pattern("/join/(?P<room_alias>[^/]+)$")
-
-    @defer.inlineCallbacks
-    def on_PUT(self, request, room_alias):
-        user = yield self.auth.get_user_by_req(request)
-
-        if not user:
-            defer.returnValue((403, "Unrecognized user"))
-
-        logger.debug("room_alias: %s", room_alias)
-
-        room_alias = self.hs.parse_roomalias(urllib.unquote(room_alias))
-
-        handler = self.handlers.room_member_handler
-        ret_dict = yield handler.join_room_alias(user, room_alias)
-
-        defer.returnValue((200, ret_dict))
-
-
-class MessageRestServlet(RestServlet):
-    PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/messages/"
-                                  + "(?P<sender_id>[^/]*)/(?P<msg_id>[^/]*)$")
-
-    def get_event_type(self):
-        return MessageEvent.TYPE
-
-    @defer.inlineCallbacks
-    def on_GET(self, request, room_id, sender_id, msg_id):
-        user = yield self.auth.get_user_by_req(request)
-
-        msg_handler = self.handlers.message_handler
-        msg = yield msg_handler.get_message(room_id=urllib.unquote(room_id),
-                                            sender_id=urllib.unquote(sender_id),
-                                            msg_id=msg_id,
-                                            user_id=user.to_string(),
-                                            )
+# TODO: Needs unit testing for generic events + feedback
+class RoomSendEventRestServlet(RestServlet):
 
-        if not msg:
-            raise SynapseError(404, "Message not found.",
-                               errcode=Codes.NOT_FOUND)
-
-        defer.returnValue((200, json.loads(msg.content)))
+    def register(self, http_server):
+        # /rooms/$roomid/send/$event_type[/$txn_id]
+        PATTERN = ("/rooms/(?P<room_id>[^/]*)/send/(?P<event_type>[^/]*)")
+        register_txn_path(self, PATTERN, http_server, with_get=True)
 
     @defer.inlineCallbacks
-    def on_PUT(self, request, room_id, sender_id, msg_id):
+    def on_POST(self, request, room_id, event_type):
         user = yield self.auth.get_user_by_req(request)
-
-        if user.to_string() != urllib.unquote(sender_id):
-            raise SynapseError(403, "Must send messages as yourself.",
-                               errcode=Codes.FORBIDDEN)
-
         content = _parse_json(request)
 
         event = self.event_factory.create_event(
-            etype=self.get_event_type(),
+            etype=event_type,
             room_id=urllib.unquote(room_id),
             user_id=user.to_string(),
-            msg_id=msg_id,
             content=content
-            )
+        )
 
         msg_handler = self.handlers.message_handler
         yield msg_handler.send_message(event)
 
-        defer.returnValue((200, ""))
+        defer.returnValue((200, {"event_id": event.event_id}))
 
+    def on_GET(self, request, room_id, event_type, txn_id):
+        return (200, "Not implemented")
 
-class FeedbackRestServlet(RestServlet):
-    PATTERN = client_path_pattern(
-        "/rooms/(?P<room_id>[^/]*)/messages/" +
-        "(?P<msg_sender_id>[^/]*)/(?P<msg_id>[^/]*)/feedback/" +
-        "(?P<sender_id>[^/]*)/(?P<feedback_type>[^/]*)$"
-    )
+    @defer.inlineCallbacks
+    def on_PUT(self, request, room_id, event_type, txn_id):
+        try:
+            defer.returnValue(self.txns.get_client_transaction(request, txn_id))
+        except KeyError:
+            pass
 
-    def get_event_type(self):
-        return FeedbackEvent.TYPE
+        response = yield self.on_POST(request, room_id, event_type)
 
-    @defer.inlineCallbacks
-    def on_GET(self, request, room_id, msg_sender_id, msg_id, fb_sender_id,
-               feedback_type):
-        yield (self.auth.get_user_by_req(request))
+        self.txns.store_client_transaction(request, txn_id, response)
+        defer.returnValue(response)
 
-        # TODO (erikj): Implement this?
-        raise NotImplementedError("Getting feedback is not supported")
 
-#        if feedback_type not in Feedback.LIST:
-#            raise SynapseError(400, "Bad feedback type.",
-#                               errcode=Codes.BAD_JSON)
-#
-#        msg_handler = self.handlers.message_handler
-#        feedback = yield msg_handler.get_feedback(
-#            room_id=urllib.unquote(room_id),
-#            msg_sender_id=msg_sender_id,
-#            msg_id=msg_id,
-#            user_id=user.to_string(),
-#            fb_sender_id=fb_sender_id,
-#            fb_type=feedback_type
-#        )
-#
-#        if not feedback:
-#            raise SynapseError(404, "Feedback not found.",
-#                               errcode=Codes.NOT_FOUND)
-#
-#        defer.returnValue((200, json.loads(feedback.content)))
+class JoinRoomAliasServlet(RestServlet):
+    PATTERN = client_path_pattern("/join/(?P<room_alias>[^/]+)$")
 
     @defer.inlineCallbacks
-    def on_PUT(self, request, room_id, sender_id, msg_id, fb_sender_id,
-               feedback_type):
-        user = yield (self.auth.get_user_by_req(request))
-
-        if user.to_string() != fb_sender_id:
-            raise SynapseError(403, "Must send feedback as yourself.",
-                               errcode=Codes.FORBIDDEN)
+    def on_PUT(self, request, room_alias):
+        user = yield self.auth.get_user_by_req(request)
 
-        if feedback_type not in Feedback.LIST:
-            raise SynapseError(400, "Bad feedback type.",
-                               errcode=Codes.BAD_JSON)
+        if not user:
+            defer.returnValue((403, "Unrecognized user"))
 
-        content = _parse_json(request)
+        logger.debug("room_alias: %s", room_alias)
 
-        event = self.event_factory.create_event(
-            etype=self.get_event_type(),
-            room_id=urllib.unquote(room_id),
-            msg_sender_id=sender_id,
-            msg_id=msg_id,
-            user_id=user.to_string(),  # user sending the feedback
-            feedback_type=feedback_type,
-            content=content
-            )
+        room_alias = self.hs.parse_roomalias(urllib.unquote(room_alias))
 
-        msg_handler = self.handlers.message_handler
-        yield msg_handler.send_feedback(event)
+        handler = self.handlers.room_member_handler
+        ret_dict = yield handler.join_room_alias(user, room_alias)
 
-        defer.returnValue((200, ""))
+        defer.returnValue((200, ret_dict))
 
 
+# TODO: Needs unit testing
 class RoomMemberListRestServlet(RestServlet):
     PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/members$")
 
@@ -332,6 +258,7 @@ class RoomMemberListRestServlet(RestServlet):
         defer.returnValue((200, members))
 
 
+# TODO: Needs unit testing
 class RoomMessageListRestServlet(RestServlet):
     PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/messages$")
 
@@ -366,6 +293,7 @@ class RoomTriggerBackfill(RestServlet):
         defer.returnValue((200, res))
 
 
+# TODO: Needs unit testing
 class RoomMembershipRestServlet(RestServlet):
 
     def register(self, http_server):
@@ -402,7 +330,7 @@ class RoomMembershipRestServlet(RestServlet):
     def on_PUT(self, request, room_id, membership_action, txn_id):
         try:
             defer.returnValue(self.txns.get_client_transaction(request, txn_id))
-        except:
+        except KeyError:
             pass
 
         response = yield self.on_POST(request, room_id, membership_action)
@@ -422,7 +350,7 @@ def _parse_json(request):
         raise SynapseError(400, "Content not JSON.", errcode=Codes.NOT_JSON)
 
 
-def register_txn_path(servlet, regex_string, http_server):
+def register_txn_path(servlet, regex_string, http_server, with_get=False):
     """Registers a transaction-based path.
 
     This registers two paths:
@@ -433,6 +361,7 @@ def register_txn_path(servlet, regex_string, http_server):
         regex_string (str): The regex string to register. Must NOT have a
         trailing $ as this string will be appended to.
         http_server : The http_server to register paths with.
+        with_get: True to also register respective GET paths for the PUTs.
     """
     http_server.register_path(
         "POST",
@@ -444,15 +373,20 @@ def register_txn_path(servlet, regex_string, http_server):
         client_path_pattern(regex_string + "/(?P<txn_id>[^/]*)$"),
         servlet.on_PUT
     )
+    if with_get:
+        http_server.register_path(
+        "GET",
+        client_path_pattern(regex_string + "/(?P<txn_id>[^/]*)$"),
+        servlet.on_GET
+    )
 
 
 def register_servlets(hs, http_server):
     RoomStateEventRestServlet(hs).register(http_server)
-    MessageRestServlet(hs).register(http_server)
-    FeedbackRestServlet(hs).register(http_server)
     RoomCreateRestServlet(hs).register(http_server)
     RoomMemberListRestServlet(hs).register(http_server)
     RoomMessageListRestServlet(hs).register(http_server)
     JoinRoomAliasServlet(hs).register(http_server)
     RoomTriggerBackfill(hs).register(http_server)
     RoomMembershipRestServlet(hs).register(http_server)
+    RoomSendEventRestServlet(hs).register(http_server)
diff --git a/synapse/storage/feedback.py b/synapse/storage/feedback.py
index cdc6670116..513b72d279 100644
--- a/synapse/storage/feedback.py
+++ b/synapse/storage/feedback.py
@@ -23,9 +23,9 @@ class FeedbackStore(SQLBaseStore):
     def _store_feedback(self, event):
         return self._simple_insert("feedback", {
             "event_id": event.event_id,
-            "feedback_type": event.feedback_type,
+            "feedback_type": event.content["type"],
             "room_id": event.room_id,
-            "target_event_id": event.target_event,
+            "target_event_id": event.content["target_event_id"],
             "sender": event.user_id,
         })
 
diff --git a/tests/rest/test_events.py b/tests/rest/test_events.py
index 4025e14581..7bc05dc2b6 100644
--- a/tests/rest/test_events.py
+++ b/tests/rest/test_events.py
@@ -181,7 +181,7 @@ class EventStreamPermissionsTestCase(RestTestCase):
         room_id = "!rid1:test"
         yield self.create_room_as(room_id, self.other_user,
                                   tok=self.other_token)
-        yield self.send(room_id, self.other_user, tok=self.other_token)
+        yield self.send(room_id, tok=self.other_token)
 
         # invited to room (expect no content for room)
         yield self.invite(room_id, src=self.other_user, targ=self.user_id,
diff --git a/tests/rest/test_rooms.py b/tests/rest/test_rooms.py
index 8514d6ba21..f18c506a7d 100644
--- a/tests/rest/test_rooms.py
+++ b/tests/rest/test_rooms.py
@@ -83,8 +83,8 @@ class RoomPermissionsTestCase(RestTestCase):
                                   is_public=True)
 
         # send a message in one of the rooms
-        self.created_rmid_msg_path = ("/rooms/%s/messages/%s/midaaa1" %
-                                (self.created_rmid, self.rmcreator_id))
+        self.created_rmid_msg_path = ("/rooms/%s/send/m.room.message/a1" %
+                                (self.created_rmid))
         (code, response) = yield self.mock_resource.trigger(
                            "PUT",
                            self.created_rmid_msg_path,
@@ -138,14 +138,14 @@ class RoomPermissionsTestCase(RestTestCase):
     @defer.inlineCallbacks
     def test_send_message(self):
         msg_content = '{"msgtype":"m.text","body":"hello"}'
-        send_msg_path = ("/rooms/%s/messages/%s/mid1" %
-                        (self.created_rmid, self.user_id))
+        send_msg_path = ("/rooms/%s/send/m.room.message/mid1" %
+                        (self.created_rmid))
 
         # send message in uncreated room, expect 403
         (code, response) = yield self.mock_resource.trigger(
                            "PUT",
-                           "/rooms/%s/messages/%s/mid1" %
-                           (self.uncreated_rmid, self.user_id), msg_content)
+                           "/rooms/%s/send/m.room.message/mid2" %
+                           (self.uncreated_rmid), msg_content)
         self.assertEquals(403, code, msg=str(response))
 
         # send message in created room not joined (no state), expect 403
@@ -875,9 +875,8 @@ class RoomMessagesTestCase(RestTestCase):
 
     @defer.inlineCallbacks
     def test_invalid_puts(self):
-        path = "/rooms/%s/messages/%s/mid1" % (
-            urllib.quote(self.room_id), self.user_id
-        )
+        path = "/rooms/%s/send/m.room.message/mid1" % (
+            urllib.quote(self.room_id))
         # missing keys or invalid json
         (code, response) = yield self.mock_resource.trigger("PUT",
                            path, '{}')
@@ -905,9 +904,8 @@ class RoomMessagesTestCase(RestTestCase):
 
     @defer.inlineCallbacks
     def test_rooms_messages_sent(self):
-        path = "/rooms/%s/messages/%s/mid1" % (
-            urllib.quote(self.room_id), self.user_id
-        )
+        path = "/rooms/%s/send/m.room.message/mid1" % (
+            urllib.quote(self.room_id))
 
         content = '{"body":"test","msgtype":{"type":"a"}}'
         (code, response) = yield self.mock_resource.trigger("PUT", path, content)
@@ -923,9 +921,8 @@ class RoomMessagesTestCase(RestTestCase):
 #        self.assert_dict(json.loads(content), response)
 
         # m.text message type
-        path = "/rooms/%s/messages/%s/mid2" % (
-            urllib.quote(self.room_id), self.user_id
-        )
+        path = "/rooms/%s/send/m.room.message/mid2" % (
+            urllib.quote(self.room_id))
         content = '{"body":"test2","msgtype":"m.text"}'
         (code, response) = yield self.mock_resource.trigger("PUT", path, content)
         self.assertEquals(200, code, msg=str(response))
@@ -933,11 +930,3 @@ class RoomMessagesTestCase(RestTestCase):
 #        (code, response) = yield self.mock_resource.trigger("GET", path, None)
 #        self.assertEquals(200, code, msg=str(response))
 #        self.assert_dict(json.loads(content), response)
-
-        # trying to send message in different user path
-        path = "/rooms/%s/messages/%s/mid2" % (
-            urllib.quote(self.room_id), "invalid" + self.user_id
-        )
-        content = '{"body":"test2","msgtype":"m.text"}'
-        (code, response) = yield self.mock_resource.trigger("PUT", path, content)
-        self.assertEquals(403, code, msg=str(response))
diff --git a/tests/rest/utils.py b/tests/rest/utils.py
index bc8bff0f1a..590d12f155 100644
--- a/tests/rest/utils.py
+++ b/tests/rest/utils.py
@@ -99,14 +99,14 @@ class RestTestCase(unittest.TestCase):
         defer.returnValue(response)
 
     @defer.inlineCallbacks
-    def send(self, room_id, sender_id, body=None, msg_id=None, tok=None,
+    def send(self, room_id, body=None, txn_id=None, tok=None,
              expect_code=200):
-        if msg_id is None:
-            msg_id = "m%s" % (str(time.time()))
+        if txn_id is None:
+            txn_id = "m%s" % (str(time.time()))
         if body is None:
             body = "body_text_here"
 
-        path = "/rooms/%s/messages/%s/%s" % (room_id, sender_id, msg_id)
+        path = "/rooms/%s/send/m.room.message/%s" % (room_id, txn_id)
         content = '{"msgtype":"m.text","body":"%s"}' % body
         if tok:
             path = path + "?access_token=%s" % tok
diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js
index fe5f120aaf..2286485605 100644
--- a/webclient/components/matrix/matrix-service.js
+++ b/webclient/components/matrix/matrix-service.js
@@ -162,12 +162,12 @@ angular.module('matrixService', [])
             return doRequest("GET", path, undefined, {});
         },
 
-        sendMessage: function(room_id, msg_id, content) {
+        sendMessage: function(room_id, txn_id, content) {
             // The REST path spec
-            var path = "/rooms/$room_id/messages/$from/$msg_id";
+            var path = "/rooms/$room_id/send/m.room.message/$txn_id";
 
-            if (!msg_id) {
-                msg_id = "m" + new Date().getTime();
+            if (!txn_id) {
+                txn_id = "m" + new Date().getTime();
             }
 
             // Like the cmd client, escape room ids
@@ -175,8 +175,7 @@ angular.module('matrixService', [])
 
             // Customize it
             path = path.replace("$room_id", room_id);
-            path = path.replace("$from", config.user_id);
-            path = path.replace("$msg_id", msg_id);
+            path = path.replace("$txn_id", txn_id);
 
             return doRequest("PUT", path, undefined, content);
         },