Merge branch 'develop' into storage_transactions

This commit is contained in:
Mark Haines 2014-08-27 11:19:37 +01:00
commit bf05218c4b
17 changed files with 189 additions and 171 deletions

View File

@ -409,10 +409,9 @@ class SynapseCmd(cmd.Cmd):
def do_send(self, line): def do_send(self, line):
"""Sends a message. "send <roomid> <body>" """ """Sends a message. "send <roomid> <body>" """
args = self._parse(line, ["roomid", "body"]) args = self._parse(line, ["roomid", "body"])
msg_id = "m%s" % int(time.time()) txn_id = "txn%s" % int(time.time())
path = "/rooms/%s/messages/%s/%s" % (urllib.quote(args["roomid"]), path = "/rooms/%s/send/m.room.message/%s" % (urllib.quote(args["roomid"]),
self._usr(), txn_id)
msg_id)
body_json = { body_json = {
"msgtype": "m.text", "msgtype": "m.text",
"body": args["body"] "body": args["body"]

View File

@ -168,6 +168,8 @@ class Auth(object):
""" """
try: try:
user_id = yield self.store.get_user_by_token(token=token) user_id = yield self.store.get_user_by_token(token=token)
if not user_id:
raise StoreError()
defer.returnValue(self.hs.parse_userid(user_id)) defer.returnValue(self.hs.parse_userid(user_id))
except StoreError: except StoreError:
raise AuthError(403, "Unrecognised access token.", raise AuthError(403, "Unrecognised access token.",

View File

@ -31,8 +31,8 @@ class Feedback(object):
"""Represents the types of feedback a user can send in response to a """Represents the types of feedback a user can send in response to a
message.""" message."""
DELIVERED = u"d" DELIVERED = u"delivered"
READ = u"r" READ = u"read"
LIST = (DELIVERED, READ) LIST = (DELIVERED, READ)

View File

@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from synapse.api.constants import Membership from synapse.api.constants import Feedback, Membership
from synapse.api.errors import SynapseError from synapse.api.errors import SynapseError
from . import SynapseEvent from . import SynapseEvent
@ -93,17 +93,19 @@ class MessageEvent(SynapseEvent):
class FeedbackEvent(SynapseEvent): class FeedbackEvent(SynapseEvent):
TYPE = "m.room.message.feedback" TYPE = "m.room.message.feedback"
valid_keys = SynapseEvent.valid_keys + [ 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)
]
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(FeedbackEvent, self).__init__(**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): def get_content_template(self):
return {} return {
"type": u"string",
"target_event_id": u"string",
"msg_sender_id": u"string"
}
class InviteJoinEvent(SynapseEvent): class InviteJoinEvent(SynapseEvent):

View File

@ -17,7 +17,7 @@ from .register import RegistrationHandler
from .room import ( from .room import (
MessageHandler, RoomCreationHandler, RoomMemberHandler, RoomListHandler MessageHandler, RoomCreationHandler, RoomMemberHandler, RoomListHandler
) )
from .events import EventStreamHandler from .events import EventStreamHandler, EventHandler
from .federation import FederationHandler from .federation import FederationHandler
from .login import LoginHandler from .login import LoginHandler
from .profile import ProfileHandler from .profile import ProfileHandler
@ -39,6 +39,7 @@ class Handlers(object):
self.room_creation_handler = RoomCreationHandler(hs) self.room_creation_handler = RoomCreationHandler(hs)
self.room_member_handler = RoomMemberHandler(hs) self.room_member_handler = RoomMemberHandler(hs)
self.event_stream_handler = EventStreamHandler(hs) self.event_stream_handler = EventStreamHandler(hs)
self.event_handler = EventHandler(hs)
self.federation_handler = FederationHandler(hs) self.federation_handler = FederationHandler(hs)
self.profile_handler = ProfileHandler(hs) self.profile_handler = ProfileHandler(hs)
self.presence_handler = PresenceHandler(hs) self.presence_handler = PresenceHandler(hs)

View File

@ -144,3 +144,29 @@ class EventStreamHandler(BaseHandler):
self._stop_timer_per_user[auth_user] = ( self._stop_timer_per_user[auth_user] = (
self.clock.call_later(5, _later) self.clock.call_later(5, _later)
) )
class EventHandler(BaseHandler):
@defer.inlineCallbacks
def get_event(self, user, event_id):
"""Retrieve a single specified event.
Args:
user (synapse.types.UserID): The user requesting the event
event_id (str): The event ID to obtain.
Returns:
dict: An event, or None if there is no event matching this ID.
Raises:
SynapseError if there was a problem retrieving this event, or
AuthError if the user does not have the rights to inspect this
event.
"""
event = yield self.store.get_event(event_id)
if not event:
defer.returnValue(None)
return
yield self.auth.check(event, raises=True)
defer.returnValue(event)

View File

@ -249,6 +249,10 @@ class MessageHandler(BaseRoomHandler):
# FIXME (erikj): We need to not generate this token, # FIXME (erikj): We need to not generate this token,
now_token = "%s_%s" % (now_rooms_token, now_presence_token) now_token = "%s_%s" % (now_rooms_token, now_presence_token)
limit = pagin_config.limit
if not limit:
limit = 10
for event in room_list: for event in room_list:
d = { d = {
"room_id": event.room_id, "room_id": event.room_id,
@ -265,7 +269,7 @@ class MessageHandler(BaseRoomHandler):
try: try:
messages, token = yield self.store.get_recent_events_for_room( messages, token = yield self.store.get_recent_events_for_room(
event.room_id, event.room_id,
limit=10, limit=limit,
end_token=now_rooms_token, end_token=now_rooms_token,
) )

View File

@ -47,5 +47,22 @@ class EventStreamRestServlet(RestServlet):
return (200, {}) return (200, {})
# TODO: Unit test gets, with and without auth, with different kinds of events.
class EventRestServlet(RestServlet):
PATTERN = client_path_pattern("/events/(?P<event_id>[^/]*)$")
@defer.inlineCallbacks
def on_GET(self, request, event_id):
auth_user = yield self.auth.get_user_by_req(request)
handler = self.handlers.event_handler
event = yield handler.get_event(auth_user, event_id)
if event:
defer.returnValue((200, event.get_dict()))
else:
defer.returnValue((404, "Event not found."))
def register_servlets(hs, http_server): def register_servlets(hs, http_server):
EventStreamRestServlet(hs).register(http_server) EventStreamRestServlet(hs).register(http_server)
EventRestServlet(hs).register(http_server)

View File

@ -19,6 +19,7 @@ from synapse.api.streams import PaginationConfig
from base import RestServlet, client_path_pattern from base import RestServlet, client_path_pattern
# TODO: Needs unit testing
class InitialSyncRestServlet(RestServlet): class InitialSyncRestServlet(RestServlet):
PATTERN = client_path_pattern("/initialSync$") PATTERN = client_path_pattern("/initialSync$")

View File

@ -18,10 +18,8 @@ from twisted.internet import defer
from base import RestServlet, client_path_pattern from base import RestServlet, client_path_pattern
from synapse.api.errors import SynapseError, Codes from synapse.api.errors import SynapseError, Codes
from synapse.api.events.room import ( from synapse.api.events.room import RoomMemberEvent
MessageEvent, RoomMemberEvent, FeedbackEvent from synapse.api.constants import Membership
)
from synapse.api.constants import Feedback
from synapse.api.streams import PaginationConfig from synapse.api.streams import PaginationConfig
import json import json
@ -96,6 +94,7 @@ class RoomCreateRestServlet(RestServlet):
return (200, {}) return (200, {})
# TODO: Needs unit testing for generic events
class RoomStateEventRestServlet(RestServlet): class RoomStateEventRestServlet(RestServlet):
def register(self, http_server): def register(self, http_server):
# /room/$roomid/state/$eventtype # /room/$roomid/state/$eventtype
@ -168,143 +167,107 @@ class RoomStateEventRestServlet(RestServlet):
defer.returnValue((200, "")) defer.returnValue((200, ""))
class JoinRoomAliasServlet(RestServlet): # TODO: Needs unit testing for generic events + feedback
PATTERN = client_path_pattern("/join/(?P<room_alias>[^/]+)$") class RoomSendEventRestServlet(RestServlet):
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 @defer.inlineCallbacks
def on_PUT(self, request, room_alias): def on_POST(self, request, room_id, event_type):
user = yield self.auth.get_user_by_req(request) 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(),
)
if not msg:
raise SynapseError(404, "Message not found.",
errcode=Codes.NOT_FOUND)
defer.returnValue((200, json.loads(msg.content)))
@defer.inlineCallbacks
def on_PUT(self, request, room_id, sender_id, msg_id):
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) content = _parse_json(request)
event = self.event_factory.create_event( event = self.event_factory.create_event(
etype=self.get_event_type(), etype=event_type,
room_id=urllib.unquote(room_id), room_id=urllib.unquote(room_id),
user_id=user.to_string(), user_id=user.to_string(),
msg_id=msg_id,
content=content content=content
) )
msg_handler = self.handlers.message_handler msg_handler = self.handlers.message_handler
yield msg_handler.send_message(event) 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):
class FeedbackRestServlet(RestServlet): return (200, "Not implemented")
PATTERN = client_path_pattern(
"/rooms/(?P<room_id>[^/]*)/messages/" +
"(?P<msg_sender_id>[^/]*)/(?P<msg_id>[^/]*)/feedback/" +
"(?P<sender_id>[^/]*)/(?P<feedback_type>[^/]*)$"
)
def get_event_type(self):
return FeedbackEvent.TYPE
@defer.inlineCallbacks @defer.inlineCallbacks
def on_GET(self, request, room_id, msg_sender_id, msg_id, fb_sender_id, def on_PUT(self, request, room_id, event_type, txn_id):
feedback_type): try:
yield (self.auth.get_user_by_req(request)) defer.returnValue(self.txns.get_client_transaction(request, txn_id))
except KeyError:
pass
# TODO (erikj): Implement this? response = yield self.on_POST(request, room_id, event_type)
raise NotImplementedError("Getting feedback is not supported")
# if feedback_type not in Feedback.LIST: self.txns.store_client_transaction(request, txn_id, response)
# raise SynapseError(400, "Bad feedback type.", defer.returnValue(response)
# errcode=Codes.BAD_JSON)
#
# msg_handler = self.handlers.message_handler # TODO: Needs unit testing for room ID + alias joins
# feedback = yield msg_handler.get_feedback( class JoinRoomAliasServlet(RestServlet):
# room_id=urllib.unquote(room_id),
# msg_sender_id=msg_sender_id, def register(self, http_server):
# msg_id=msg_id, # /join/$room_identifier[/$txn_id]
# user_id=user.to_string(), PATTERN = ("/join/(?P<room_identifier>[^/]*)")
# fb_sender_id=fb_sender_id, register_txn_path(self, PATTERN, http_server)
# fb_type=feedback_type
# )
#
# if not feedback:
# raise SynapseError(404, "Feedback not found.",
# errcode=Codes.NOT_FOUND)
#
# defer.returnValue((200, json.loads(feedback.content)))
@defer.inlineCallbacks @defer.inlineCallbacks
def on_PUT(self, request, room_id, sender_id, msg_id, fb_sender_id, def on_POST(self, request, room_identifier):
feedback_type): user = yield self.auth.get_user_by_req(request)
user = yield (self.auth.get_user_by_req(request))
if user.to_string() != fb_sender_id: # the identifier could be a room alias or a room id. Try one then the
raise SynapseError(403, "Must send feedback as yourself.", # other if it fails to parse, without swallowing other valid
errcode=Codes.FORBIDDEN) # SynapseErrors.
if feedback_type not in Feedback.LIST: identifier = None
raise SynapseError(400, "Bad feedback type.", is_room_alias = False
errcode=Codes.BAD_JSON) try:
identifier = self.hs.parse_roomalias(
content = _parse_json(request) urllib.unquote(room_identifier)
)
event = self.event_factory.create_event( is_room_alias = True
etype=self.get_event_type(), except SynapseError:
room_id=urllib.unquote(room_id), identifier = self.hs.parse_roomid(
msg_sender_id=sender_id, urllib.unquote(room_identifier)
msg_id=msg_id,
user_id=user.to_string(), # user sending the feedback
feedback_type=feedback_type,
content=content
) )
msg_handler = self.handlers.message_handler # TODO: Support for specifying the home server to join with?
yield msg_handler.send_feedback(event)
defer.returnValue((200, "")) if is_room_alias:
handler = self.handlers.room_member_handler
ret_dict = yield handler.join_room_alias(user, identifier)
defer.returnValue((200, ret_dict))
else: # room id
event = self.event_factory.create_event(
etype=RoomMemberEvent.TYPE,
content={"membership": Membership.JOIN},
room_id=urllib.unquote(identifier.to_string()),
user_id=user.to_string(),
state_key=user.to_string()
)
handler = self.handlers.room_member_handler
yield handler.change_membership(event)
defer.returnValue((200, ""))
@defer.inlineCallbacks
def on_PUT(self, request, room_identifier, txn_id):
try:
defer.returnValue(self.txns.get_client_transaction(request, txn_id))
except KeyError:
pass
response = yield self.on_POST(request, room_identifier)
self.txns.store_client_transaction(request, txn_id, response)
defer.returnValue(response)
# TODO: Needs unit testing
class RoomMemberListRestServlet(RestServlet): class RoomMemberListRestServlet(RestServlet):
PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/members$") PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/members$")
@ -332,6 +295,7 @@ class RoomMemberListRestServlet(RestServlet):
defer.returnValue((200, members)) defer.returnValue((200, members))
# TODO: Needs unit testing
class RoomMessageListRestServlet(RestServlet): class RoomMessageListRestServlet(RestServlet):
PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/messages$") PATTERN = client_path_pattern("/rooms/(?P<room_id>[^/]*)/messages$")
@ -366,6 +330,7 @@ class RoomTriggerBackfill(RestServlet):
defer.returnValue((200, res)) defer.returnValue((200, res))
# TODO: Needs unit testing
class RoomMembershipRestServlet(RestServlet): class RoomMembershipRestServlet(RestServlet):
def register(self, http_server): def register(self, http_server):
@ -402,7 +367,7 @@ class RoomMembershipRestServlet(RestServlet):
def on_PUT(self, request, room_id, membership_action, txn_id): def on_PUT(self, request, room_id, membership_action, txn_id):
try: try:
defer.returnValue(self.txns.get_client_transaction(request, txn_id)) defer.returnValue(self.txns.get_client_transaction(request, txn_id))
except: except KeyError:
pass pass
response = yield self.on_POST(request, room_id, membership_action) response = yield self.on_POST(request, room_id, membership_action)
@ -422,7 +387,7 @@ def _parse_json(request):
raise SynapseError(400, "Content not JSON.", errcode=Codes.NOT_JSON) 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. """Registers a transaction-based path.
This registers two paths: This registers two paths:
@ -433,6 +398,7 @@ def register_txn_path(servlet, regex_string, http_server):
regex_string (str): The regex string to register. Must NOT have a regex_string (str): The regex string to register. Must NOT have a
trailing $ as this string will be appended to. trailing $ as this string will be appended to.
http_server : The http_server to register paths with. 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( http_server.register_path(
"POST", "POST",
@ -444,15 +410,20 @@ def register_txn_path(servlet, regex_string, http_server):
client_path_pattern(regex_string + "/(?P<txn_id>[^/]*)$"), client_path_pattern(regex_string + "/(?P<txn_id>[^/]*)$"),
servlet.on_PUT 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): def register_servlets(hs, http_server):
RoomStateEventRestServlet(hs).register(http_server) RoomStateEventRestServlet(hs).register(http_server)
MessageRestServlet(hs).register(http_server)
FeedbackRestServlet(hs).register(http_server)
RoomCreateRestServlet(hs).register(http_server) RoomCreateRestServlet(hs).register(http_server)
RoomMemberListRestServlet(hs).register(http_server) RoomMemberListRestServlet(hs).register(http_server)
RoomMessageListRestServlet(hs).register(http_server) RoomMessageListRestServlet(hs).register(http_server)
JoinRoomAliasServlet(hs).register(http_server) JoinRoomAliasServlet(hs).register(http_server)
RoomTriggerBackfill(hs).register(http_server) RoomTriggerBackfill(hs).register(http_server)
RoomMembershipRestServlet(hs).register(http_server) RoomMembershipRestServlet(hs).register(http_server)
RoomSendEventRestServlet(hs).register(http_server)

View File

@ -27,7 +27,7 @@ from synapse.handlers import Handlers
from synapse.rest import RestServletFactory from synapse.rest import RestServletFactory
from synapse.state import StateHandler from synapse.state import StateHandler
from synapse.storage import DataStore from synapse.storage import DataStore
from synapse.types import UserID, RoomAlias from synapse.types import UserID, RoomAlias, RoomID
from synapse.util import Clock from synapse.util import Clock
from synapse.util.distributor import Distributor from synapse.util.distributor import Distributor
from synapse.util.lockutils import LockManager from synapse.util.lockutils import LockManager
@ -115,6 +115,9 @@ class BaseHomeServer(object):
setattr(BaseHomeServer, "get_%s" % (depname), _get) setattr(BaseHomeServer, "get_%s" % (depname), _get)
# TODO: Why are these parse_ methods so high up along with other globals?
# Surely these should be in a util package or in the api package?
# Other utility methods # Other utility methods
def parse_userid(self, s): def parse_userid(self, s):
"""Parse the string given by 's' as a User ID and return a UserID """Parse the string given by 's' as a User ID and return a UserID
@ -126,6 +129,11 @@ class BaseHomeServer(object):
object.""" object."""
return RoomAlias.from_string(s, hs=self) return RoomAlias.from_string(s, hs=self)
def parse_roomid(self, s):
"""Parse the string given by 's' as a Room ID and return a RoomID
object."""
return RoomID.from_string(s, hs=self)
# Build magic accessors for every dependency # Build magic accessors for every dependency
for depname in BaseHomeServer.DEPENDENCIES: for depname in BaseHomeServer.DEPENDENCIES:
BaseHomeServer._make_dependency_method(depname) BaseHomeServer._make_dependency_method(depname)

View File

@ -88,7 +88,6 @@ class DataStore(RoomMemberStore, RoomStore,
[ [
"event_id", "event_id",
"type", "type",
"sender",
"room_id", "room_id",
"content", "content",
"unrecognized_keys" "unrecognized_keys"

View File

@ -23,9 +23,9 @@ class FeedbackStore(SQLBaseStore):
def _store_feedback_txn(self, txn, event): def _store_feedback_txn(self, txn, event):
self._simple_insert_txn(txn, "feedback", { self._simple_insert_txn(txn, "feedback", {
"event_id": event.event_id, "event_id": event.event_id,
"feedback_type": event.feedback_type, "feedback_type": event.content["type"],
"room_id": event.room_id, "room_id": event.room_id,
"target_event_id": event.target_event, "target_event_id": event.content["target_event_id"],
"sender": event.user_id, "sender": event.user_id,
}) })

View File

@ -182,7 +182,7 @@ class EventStreamPermissionsTestCase(RestTestCase):
room_id = "!rid1:test" room_id = "!rid1:test"
yield self.create_room_as(room_id, self.other_user, yield self.create_room_as(room_id, self.other_user,
tok=self.other_token) 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) # invited to room (expect no content for room)
yield self.invite(room_id, src=self.other_user, targ=self.user_id, yield self.invite(room_id, src=self.other_user, targ=self.user_id,

View File

@ -83,8 +83,8 @@ class RoomPermissionsTestCase(RestTestCase):
is_public=True) is_public=True)
# send a message in one of the rooms # send a message in one of the rooms
self.created_rmid_msg_path = ("/rooms/%s/messages/%s/midaaa1" % self.created_rmid_msg_path = ("/rooms/%s/send/m.room.message/a1" %
(self.created_rmid, self.rmcreator_id)) (self.created_rmid))
(code, response) = yield self.mock_resource.trigger( (code, response) = yield self.mock_resource.trigger(
"PUT", "PUT",
self.created_rmid_msg_path, self.created_rmid_msg_path,
@ -138,14 +138,14 @@ class RoomPermissionsTestCase(RestTestCase):
@defer.inlineCallbacks @defer.inlineCallbacks
def test_send_message(self): def test_send_message(self):
msg_content = '{"msgtype":"m.text","body":"hello"}' msg_content = '{"msgtype":"m.text","body":"hello"}'
send_msg_path = ("/rooms/%s/messages/%s/mid1" % send_msg_path = ("/rooms/%s/send/m.room.message/mid1" %
(self.created_rmid, self.user_id)) (self.created_rmid))
# send message in uncreated room, expect 403 # send message in uncreated room, expect 403
(code, response) = yield self.mock_resource.trigger( (code, response) = yield self.mock_resource.trigger(
"PUT", "PUT",
"/rooms/%s/messages/%s/mid1" % "/rooms/%s/send/m.room.message/mid2" %
(self.uncreated_rmid, self.user_id), msg_content) (self.uncreated_rmid), msg_content)
self.assertEquals(403, code, msg=str(response)) self.assertEquals(403, code, msg=str(response))
# send message in created room not joined (no state), expect 403 # send message in created room not joined (no state), expect 403
@ -875,9 +875,8 @@ class RoomMessagesTestCase(RestTestCase):
@defer.inlineCallbacks @defer.inlineCallbacks
def test_invalid_puts(self): def test_invalid_puts(self):
path = "/rooms/%s/messages/%s/mid1" % ( path = "/rooms/%s/send/m.room.message/mid1" % (
urllib.quote(self.room_id), self.user_id urllib.quote(self.room_id))
)
# missing keys or invalid json # missing keys or invalid json
(code, response) = yield self.mock_resource.trigger("PUT", (code, response) = yield self.mock_resource.trigger("PUT",
path, '{}') path, '{}')
@ -905,9 +904,8 @@ class RoomMessagesTestCase(RestTestCase):
@defer.inlineCallbacks @defer.inlineCallbacks
def test_rooms_messages_sent(self): def test_rooms_messages_sent(self):
path = "/rooms/%s/messages/%s/mid1" % ( path = "/rooms/%s/send/m.room.message/mid1" % (
urllib.quote(self.room_id), self.user_id urllib.quote(self.room_id))
)
content = '{"body":"test","msgtype":{"type":"a"}}' content = '{"body":"test","msgtype":{"type":"a"}}'
(code, response) = yield self.mock_resource.trigger("PUT", path, content) (code, response) = yield self.mock_resource.trigger("PUT", path, content)
@ -923,9 +921,8 @@ class RoomMessagesTestCase(RestTestCase):
# self.assert_dict(json.loads(content), response) # self.assert_dict(json.loads(content), response)
# m.text message type # m.text message type
path = "/rooms/%s/messages/%s/mid2" % ( path = "/rooms/%s/send/m.room.message/mid2" % (
urllib.quote(self.room_id), self.user_id urllib.quote(self.room_id))
)
content = '{"body":"test2","msgtype":"m.text"}' content = '{"body":"test2","msgtype":"m.text"}'
(code, response) = yield self.mock_resource.trigger("PUT", path, content) (code, response) = yield self.mock_resource.trigger("PUT", path, content)
self.assertEquals(200, code, msg=str(response)) self.assertEquals(200, code, msg=str(response))
@ -933,11 +930,3 @@ class RoomMessagesTestCase(RestTestCase):
# (code, response) = yield self.mock_resource.trigger("GET", path, None) # (code, response) = yield self.mock_resource.trigger("GET", path, None)
# self.assertEquals(200, code, msg=str(response)) # self.assertEquals(200, code, msg=str(response))
# self.assert_dict(json.loads(content), 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))

View File

@ -99,14 +99,14 @@ class RestTestCase(unittest.TestCase):
defer.returnValue(response) defer.returnValue(response)
@defer.inlineCallbacks @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): expect_code=200):
if msg_id is None: if txn_id is None:
msg_id = "m%s" % (str(time.time())) txn_id = "m%s" % (str(time.time()))
if body is None: if body is None:
body = "body_text_here" 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 content = '{"msgtype":"m.text","body":"%s"}' % body
if tok: if tok:
path = path + "?access_token=%s" % tok path = path + "?access_token=%s" % tok

View File

@ -162,12 +162,12 @@ angular.module('matrixService', [])
return doRequest("GET", path, undefined, {}); return doRequest("GET", path, undefined, {});
}, },
sendMessage: function(room_id, msg_id, content) { sendMessage: function(room_id, txn_id, content) {
// The REST path spec // 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) { if (!txn_id) {
msg_id = "m" + new Date().getTime(); txn_id = "m" + new Date().getTime();
} }
// Like the cmd client, escape room ids // Like the cmd client, escape room ids
@ -175,8 +175,7 @@ angular.module('matrixService', [])
// Customize it // Customize it
path = path.replace("$room_id", room_id); path = path.replace("$room_id", room_id);
path = path.replace("$from", config.user_id); path = path.replace("$txn_id", txn_id);
path = path.replace("$msg_id", msg_id);
return doRequest("PUT", path, undefined, content); return doRequest("PUT", path, undefined, content);
}, },