Merge branch 'develop' into storage_transactions
This commit is contained in:
commit
bf05218c4b
|
@ -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"]
|
||||||
|
|
|
@ -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.",
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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$")
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
return (200, "Not implemented")
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
response = yield self.on_POST(request, room_id, event_type)
|
||||||
|
|
||||||
|
self.txns.store_client_transaction(request, txn_id, response)
|
||||||
|
defer.returnValue(response)
|
||||||
|
|
||||||
|
|
||||||
class FeedbackRestServlet(RestServlet):
|
# TODO: Needs unit testing for room ID + alias joins
|
||||||
PATTERN = client_path_pattern(
|
class JoinRoomAliasServlet(RestServlet):
|
||||||
"/rooms/(?P<room_id>[^/]*)/messages/" +
|
|
||||||
"(?P<msg_sender_id>[^/]*)/(?P<msg_id>[^/]*)/feedback/" +
|
def register(self, http_server):
|
||||||
"(?P<sender_id>[^/]*)/(?P<feedback_type>[^/]*)$"
|
# /join/$room_identifier[/$txn_id]
|
||||||
|
PATTERN = ("/join/(?P<room_identifier>[^/]*)")
|
||||||
|
register_txn_path(self, PATTERN, http_server)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_POST(self, request, room_identifier):
|
||||||
|
user = yield self.auth.get_user_by_req(request)
|
||||||
|
|
||||||
|
# the identifier could be a room alias or a room id. Try one then the
|
||||||
|
# other if it fails to parse, without swallowing other valid
|
||||||
|
# SynapseErrors.
|
||||||
|
|
||||||
|
identifier = None
|
||||||
|
is_room_alias = False
|
||||||
|
try:
|
||||||
|
identifier = self.hs.parse_roomalias(
|
||||||
|
urllib.unquote(room_identifier)
|
||||||
|
)
|
||||||
|
is_room_alias = True
|
||||||
|
except SynapseError:
|
||||||
|
identifier = self.hs.parse_roomid(
|
||||||
|
urllib.unquote(room_identifier)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_event_type(self):
|
# TODO: Support for specifying the home server to join with?
|
||||||
return FeedbackEvent.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))
|
|
||||||
|
|
||||||
# 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)))
|
|
||||||
|
|
||||||
@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)
|
|
||||||
|
|
||||||
if feedback_type not in Feedback.LIST:
|
|
||||||
raise SynapseError(400, "Bad feedback type.",
|
|
||||||
errcode=Codes.BAD_JSON)
|
|
||||||
|
|
||||||
content = _parse_json(request)
|
|
||||||
|
|
||||||
|
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(
|
event = self.event_factory.create_event(
|
||||||
etype=self.get_event_type(),
|
etype=RoomMemberEvent.TYPE,
|
||||||
room_id=urllib.unquote(room_id),
|
content={"membership": Membership.JOIN},
|
||||||
msg_sender_id=sender_id,
|
room_id=urllib.unquote(identifier.to_string()),
|
||||||
msg_id=msg_id,
|
user_id=user.to_string(),
|
||||||
user_id=user.to_string(), # user sending the feedback
|
state_key=user.to_string()
|
||||||
feedback_type=feedback_type,
|
|
||||||
content=content
|
|
||||||
)
|
)
|
||||||
|
handler = self.handlers.room_member_handler
|
||||||
msg_handler = self.handlers.message_handler
|
yield handler.change_membership(event)
|
||||||
yield msg_handler.send_feedback(event)
|
|
||||||
|
|
||||||
defer.returnValue((200, ""))
|
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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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))
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue