Merge branch 'develop' of github.com:matrix-org/synapse into postgres
This commit is contained in:
commit
6ba2e3df4e
|
@ -0,0 +1,93 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
import sys
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
def _mkurl(template, kws):
|
||||||
|
for key in kws:
|
||||||
|
template = template.replace(key, kws[key])
|
||||||
|
return template
|
||||||
|
|
||||||
|
def main(hs, room_id, access_token, user_id_prefix, why):
|
||||||
|
if not why:
|
||||||
|
why = "Automated kick."
|
||||||
|
print "Kicking members on %s in room %s matching %s" % (hs, room_id, user_id_prefix)
|
||||||
|
room_state_url = _mkurl(
|
||||||
|
"$HS/_matrix/client/api/v1/rooms/$ROOM/state?access_token=$TOKEN",
|
||||||
|
{
|
||||||
|
"$HS": hs,
|
||||||
|
"$ROOM": room_id,
|
||||||
|
"$TOKEN": access_token
|
||||||
|
}
|
||||||
|
)
|
||||||
|
print "Getting room state => %s" % room_state_url
|
||||||
|
res = requests.get(room_state_url)
|
||||||
|
print "HTTP %s" % res.status_code
|
||||||
|
state_events = res.json()
|
||||||
|
if "error" in state_events:
|
||||||
|
print "FATAL"
|
||||||
|
print state_events
|
||||||
|
return
|
||||||
|
|
||||||
|
kick_list = []
|
||||||
|
room_name = room_id
|
||||||
|
for event in state_events:
|
||||||
|
if not event["type"] == "m.room.member":
|
||||||
|
if event["type"] == "m.room.name":
|
||||||
|
room_name = event["content"].get("name")
|
||||||
|
continue
|
||||||
|
if not event["content"].get("membership") == "join":
|
||||||
|
continue
|
||||||
|
if event["state_key"].startswith(user_id_prefix):
|
||||||
|
kick_list.append(event["state_key"])
|
||||||
|
|
||||||
|
if len(kick_list) == 0:
|
||||||
|
print "No user IDs match the prefix '%s'" % user_id_prefix
|
||||||
|
return
|
||||||
|
|
||||||
|
print "The following user IDs will be kicked from %s" % room_name
|
||||||
|
for uid in kick_list:
|
||||||
|
print uid
|
||||||
|
doit = raw_input("Continue? [Y]es\n")
|
||||||
|
if len(doit) > 0 and doit.lower() == 'y':
|
||||||
|
print "Kicking members..."
|
||||||
|
# encode them all
|
||||||
|
kick_list = [urllib.quote(uid) for uid in kick_list]
|
||||||
|
for uid in kick_list:
|
||||||
|
kick_url = _mkurl(
|
||||||
|
"$HS/_matrix/client/api/v1/rooms/$ROOM/state/m.room.member/$UID?access_token=$TOKEN",
|
||||||
|
{
|
||||||
|
"$HS": hs,
|
||||||
|
"$UID": uid,
|
||||||
|
"$ROOM": room_id,
|
||||||
|
"$TOKEN": access_token
|
||||||
|
}
|
||||||
|
)
|
||||||
|
kick_body = {
|
||||||
|
"membership": "leave",
|
||||||
|
"reason": why
|
||||||
|
}
|
||||||
|
print "Kicking %s" % uid
|
||||||
|
res = requests.put(kick_url, data=json.dumps(kick_body))
|
||||||
|
if res.status_code != 200:
|
||||||
|
print "ERROR: HTTP %s" % res.status_code
|
||||||
|
if res.json().get("error"):
|
||||||
|
print "ERROR: JSON %s" % res.json()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = ArgumentParser("Kick members in a room matching a certain user ID prefix.")
|
||||||
|
parser.add_argument("-u","--user-id",help="The user ID prefix e.g. '@irc_'")
|
||||||
|
parser.add_argument("-t","--token",help="Your access_token")
|
||||||
|
parser.add_argument("-r","--room",help="The room ID to kick members in")
|
||||||
|
parser.add_argument("-s","--homeserver",help="The base HS url e.g. http://matrix.org")
|
||||||
|
parser.add_argument("-w","--why",help="Reason for the kick. Optional.")
|
||||||
|
args = parser.parse_args()
|
||||||
|
if not args.room or not args.token or not args.user_id or not args.homeserver:
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
main(args.homeserver, args.room, args.token, args.user_id, args.why)
|
|
@ -215,17 +215,20 @@ class Auth(object):
|
||||||
else:
|
else:
|
||||||
ban_level = 50 # FIXME (erikj): What should we do here?
|
ban_level = 50 # FIXME (erikj): What should we do here?
|
||||||
|
|
||||||
if Membership.INVITE == membership:
|
if Membership.JOIN != membership:
|
||||||
# TODO (erikj): We should probably handle this more intelligently
|
# JOIN is the only action you can perform if you're not in the room
|
||||||
# PRIVATE join rules.
|
|
||||||
|
|
||||||
# Invites are valid iff caller is in the room and target isn't.
|
|
||||||
if not caller_in_room: # caller isn't joined
|
if not caller_in_room: # caller isn't joined
|
||||||
raise AuthError(
|
raise AuthError(
|
||||||
403,
|
403,
|
||||||
"%s not in room %s." % (event.user_id, event.room_id,)
|
"%s not in room %s." % (event.user_id, event.room_id,)
|
||||||
)
|
)
|
||||||
elif target_banned:
|
|
||||||
|
if Membership.INVITE == membership:
|
||||||
|
# TODO (erikj): We should probably handle this more intelligently
|
||||||
|
# PRIVATE join rules.
|
||||||
|
|
||||||
|
# Invites are valid iff caller is in the room and target isn't.
|
||||||
|
if target_banned:
|
||||||
raise AuthError(
|
raise AuthError(
|
||||||
403, "%s is banned from the room" % (target_user_id,)
|
403, "%s is banned from the room" % (target_user_id,)
|
||||||
)
|
)
|
||||||
|
@ -251,13 +254,7 @@ class Auth(object):
|
||||||
raise AuthError(403, "You are not allowed to join this room")
|
raise AuthError(403, "You are not allowed to join this room")
|
||||||
elif Membership.LEAVE == membership:
|
elif Membership.LEAVE == membership:
|
||||||
# TODO (erikj): Implement kicks.
|
# TODO (erikj): Implement kicks.
|
||||||
|
if target_banned and user_level < ban_level:
|
||||||
if not caller_in_room: # trying to leave a room you aren't joined
|
|
||||||
raise AuthError(
|
|
||||||
403,
|
|
||||||
"%s not in room %s." % (target_user_id, event.room_id,)
|
|
||||||
)
|
|
||||||
elif target_banned and user_level < ban_level:
|
|
||||||
raise AuthError(
|
raise AuthError(
|
||||||
403, "You cannot unban user &s." % (target_user_id,)
|
403, "You cannot unban user &s." % (target_user_id,)
|
||||||
)
|
)
|
||||||
|
|
|
@ -223,6 +223,7 @@ class TypingNotificationEventSource(object):
|
||||||
def __init__(self, hs):
|
def __init__(self, hs):
|
||||||
self.hs = hs
|
self.hs = hs
|
||||||
self._handler = None
|
self._handler = None
|
||||||
|
self._room_member_handler = None
|
||||||
|
|
||||||
def handler(self):
|
def handler(self):
|
||||||
# Avoid cyclic dependency in handler setup
|
# Avoid cyclic dependency in handler setup
|
||||||
|
@ -230,6 +231,11 @@ class TypingNotificationEventSource(object):
|
||||||
self._handler = self.hs.get_handlers().typing_notification_handler
|
self._handler = self.hs.get_handlers().typing_notification_handler
|
||||||
return self._handler
|
return self._handler
|
||||||
|
|
||||||
|
def room_member_handler(self):
|
||||||
|
if not self._room_member_handler:
|
||||||
|
self._room_member_handler = self.hs.get_handlers().room_member_handler
|
||||||
|
return self._room_member_handler
|
||||||
|
|
||||||
def _make_event_for(self, room_id):
|
def _make_event_for(self, room_id):
|
||||||
typing = self.handler()._room_typing[room_id]
|
typing = self.handler()._room_typing[room_id]
|
||||||
return {
|
return {
|
||||||
|
@ -240,19 +246,25 @@ class TypingNotificationEventSource(object):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
def get_new_events_for_user(self, user, from_key, limit):
|
def get_new_events_for_user(self, user, from_key, limit):
|
||||||
from_key = int(from_key)
|
from_key = int(from_key)
|
||||||
handler = self.handler()
|
handler = self.handler()
|
||||||
|
|
||||||
|
joined_room_ids = (
|
||||||
|
yield self.room_member_handler().get_joined_rooms_for_user(user)
|
||||||
|
)
|
||||||
|
|
||||||
events = []
|
events = []
|
||||||
for room_id in handler._room_serials:
|
for room_id in handler._room_serials:
|
||||||
|
if room_id not in joined_room_ids:
|
||||||
|
continue
|
||||||
if handler._room_serials[room_id] <= from_key:
|
if handler._room_serials[room_id] <= from_key:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# TODO: check if user is in room
|
|
||||||
events.append(self._make_event_for(room_id))
|
events.append(self._make_event_for(room_id))
|
||||||
|
|
||||||
return (events, handler._latest_room_serial)
|
defer.returnValue((events, handler._latest_room_serial))
|
||||||
|
|
||||||
def get_current_key(self):
|
def get_current_key(self):
|
||||||
return self.handler()._latest_room_serial
|
return self.handler()._latest_room_serial
|
||||||
|
|
|
@ -131,6 +131,13 @@ class TypingNotificationsTestCase(unittest.TestCase):
|
||||||
return defer.succeed([])
|
return defer.succeed([])
|
||||||
self.room_member_handler.get_room_members = get_room_members
|
self.room_member_handler.get_room_members = get_room_members
|
||||||
|
|
||||||
|
def get_joined_rooms_for_user(user):
|
||||||
|
if user in self.room_members:
|
||||||
|
return defer.succeed([self.room_id])
|
||||||
|
else:
|
||||||
|
return defer.succeed([])
|
||||||
|
self.room_member_handler.get_joined_rooms_for_user = get_joined_rooms_for_user
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def fetch_room_distributions_into(room_id, localusers=None,
|
def fetch_room_distributions_into(room_id, localusers=None,
|
||||||
remotedomains=None, ignore_user=None):
|
remotedomains=None, ignore_user=None):
|
||||||
|
@ -180,8 +187,9 @@ class TypingNotificationsTestCase(unittest.TestCase):
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertEquals(self.event_source.get_current_key(), 1)
|
self.assertEquals(self.event_source.get_current_key(), 1)
|
||||||
|
events = yield self.event_source.get_new_events_for_user(self.u_apple, 0, None)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.event_source.get_new_events_for_user(self.u_apple, 0, None)[0],
|
events[0],
|
||||||
[
|
[
|
||||||
{"type": "m.typing",
|
{"type": "m.typing",
|
||||||
"room_id": self.room_id,
|
"room_id": self.room_id,
|
||||||
|
@ -242,8 +250,9 @@ class TypingNotificationsTestCase(unittest.TestCase):
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertEquals(self.event_source.get_current_key(), 1)
|
self.assertEquals(self.event_source.get_current_key(), 1)
|
||||||
|
events = yield self.event_source.get_new_events_for_user(self.u_apple, 0, None)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.event_source.get_new_events_for_user(self.u_apple, 0, None)[0],
|
events[0],
|
||||||
[
|
[
|
||||||
{"type": "m.typing",
|
{"type": "m.typing",
|
||||||
"room_id": self.room_id,
|
"room_id": self.room_id,
|
||||||
|
@ -297,8 +306,9 @@ class TypingNotificationsTestCase(unittest.TestCase):
|
||||||
yield put_json.await_calls()
|
yield put_json.await_calls()
|
||||||
|
|
||||||
self.assertEquals(self.event_source.get_current_key(), 1)
|
self.assertEquals(self.event_source.get_current_key(), 1)
|
||||||
|
events = yield self.event_source.get_new_events_for_user(self.u_apple, 0, None)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.event_source.get_new_events_for_user(self.u_apple, 0, None)[0],
|
events[0],
|
||||||
[
|
[
|
||||||
{"type": "m.typing",
|
{"type": "m.typing",
|
||||||
"room_id": self.room_id,
|
"room_id": self.room_id,
|
||||||
|
@ -327,8 +337,9 @@ class TypingNotificationsTestCase(unittest.TestCase):
|
||||||
self.on_new_user_event.reset_mock()
|
self.on_new_user_event.reset_mock()
|
||||||
|
|
||||||
self.assertEquals(self.event_source.get_current_key(), 1)
|
self.assertEquals(self.event_source.get_current_key(), 1)
|
||||||
|
events = yield self.event_source.get_new_events_for_user(self.u_apple, 0, None)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.event_source.get_new_events_for_user(self.u_apple, 0, None)[0],
|
events[0],
|
||||||
[
|
[
|
||||||
{"type": "m.typing",
|
{"type": "m.typing",
|
||||||
"room_id": self.room_id,
|
"room_id": self.room_id,
|
||||||
|
@ -345,8 +356,9 @@ class TypingNotificationsTestCase(unittest.TestCase):
|
||||||
])
|
])
|
||||||
|
|
||||||
self.assertEquals(self.event_source.get_current_key(), 2)
|
self.assertEquals(self.event_source.get_current_key(), 2)
|
||||||
|
events = yield self.event_source.get_new_events_for_user(self.u_apple, 1, None)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.event_source.get_new_events_for_user(self.u_apple, 1, None)[0],
|
events[0],
|
||||||
[
|
[
|
||||||
{"type": "m.typing",
|
{"type": "m.typing",
|
||||||
"room_id": self.room_id,
|
"room_id": self.room_id,
|
||||||
|
@ -371,8 +383,9 @@ class TypingNotificationsTestCase(unittest.TestCase):
|
||||||
self.on_new_user_event.reset_mock()
|
self.on_new_user_event.reset_mock()
|
||||||
|
|
||||||
self.assertEquals(self.event_source.get_current_key(), 3)
|
self.assertEquals(self.event_source.get_current_key(), 3)
|
||||||
|
events = yield self.event_source.get_new_events_for_user(self.u_apple, 0, None)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.event_source.get_new_events_for_user(self.u_apple, 0, None)[0],
|
events[0],
|
||||||
[
|
[
|
||||||
{"type": "m.typing",
|
{"type": "m.typing",
|
||||||
"room_id": self.room_id,
|
"room_id": self.room_id,
|
||||||
|
|
|
@ -34,6 +34,8 @@ class RoomTypingTestCase(RestTestCase):
|
||||||
""" Tests /rooms/$room_id/typing/$user_id REST API. """
|
""" Tests /rooms/$room_id/typing/$user_id REST API. """
|
||||||
user_id = "@sid:red"
|
user_id = "@sid:red"
|
||||||
|
|
||||||
|
user = UserID.from_string(user_id)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.clock = MockClock()
|
self.clock = MockClock()
|
||||||
|
@ -75,7 +77,7 @@ class RoomTypingTestCase(RestTestCase):
|
||||||
|
|
||||||
def get_room_members(room_id):
|
def get_room_members(room_id):
|
||||||
if room_id == self.room_id:
|
if room_id == self.room_id:
|
||||||
return defer.succeed([UserID.from_string(self.user_id)])
|
return defer.succeed([self.user])
|
||||||
else:
|
else:
|
||||||
return defer.succeed([])
|
return defer.succeed([])
|
||||||
|
|
||||||
|
@ -115,8 +117,9 @@ class RoomTypingTestCase(RestTestCase):
|
||||||
self.assertEquals(200, code)
|
self.assertEquals(200, code)
|
||||||
|
|
||||||
self.assertEquals(self.event_source.get_current_key(), 1)
|
self.assertEquals(self.event_source.get_current_key(), 1)
|
||||||
|
events = yield self.event_source.get_new_events_for_user(self.user, 0, None)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
self.event_source.get_new_events_for_user(self.user_id, 0, None)[0],
|
events[0],
|
||||||
[
|
[
|
||||||
{"type": "m.typing",
|
{"type": "m.typing",
|
||||||
"room_id": self.room_id,
|
"room_id": self.room_id,
|
||||||
|
|
Loading…
Reference in New Issue