From b0872922ece60c0ef30286e0a94b47687290d79b Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Mon, 5 Mar 2018 23:38:14 +0100 Subject: [PATCH] Implement /kick. --- main.py | 3 ++- matrix/api.py | 41 +++++++++++++++++++++++++++++++++++++++++ matrix/commands.py | 41 +++++++++++++++++++++++++++++++++++++++-- matrix/events.py | 20 ++++++++++++++++++++ matrix/rooms.py | 12 +++++++----- 5 files changed, 109 insertions(+), 8 deletions(-) diff --git a/main.py b/main.py index e37cd8c..64a0168 100644 --- a/main.py +++ b/main.py @@ -43,7 +43,8 @@ from matrix.commands import (hook_commands, hook_page_up, matrix_command_cb, matrix_command_join_cb, matrix_command_part_cb, matrix_command_invite_cb, matrix_command_topic_cb, matrix_command_pgup_cb, matrix_redact_command_cb, - matrix_command_buf_clear_cb, matrix_me_command_cb) + matrix_command_buf_clear_cb, matrix_me_command_cb, + matrix_command_kick_cb) from matrix.server import ( MatrixServer, diff --git a/matrix/api.py b/matrix/api.py index 1725a4f..f9e4a83 100644 --- a/matrix/api.py +++ b/matrix/api.py @@ -207,6 +207,23 @@ class MatrixClient: return HttpRequest(RequestType.POST, self.host, path, content) + def room_kick(self, room_id, user_id, reason=None): + query_parameters = {"access_token": self.access_token} + + content = {"user_id": user_id} + + if reason: + content["reason"] = reason + + path = ("{api}/rooms/{room_id}/kick?" + "{query_parameters}").format( + api=MATRIX_API_PATH, + room_id=quote(room_id), + query_parameters=urlencode(query_parameters)) + + h = HttpRequest(RequestType.POST, self.host, path, content) + return h + def mxc_to_http(self, mxc): # type: (str) -> str url = urlparse(mxc) @@ -469,3 +486,27 @@ class MatrixInviteMessage(MatrixMessage): self.room_id, self.user_id) return self._decode(server, object_hook) + + +class MatrixKickMessage(MatrixMessage): + + def __init__(self, client, room_id, user_id, reason=None): + self.room_id = room_id + self.user_id = user_id + self.reason = reason + + data = {"room_id": self.room_id, + "user_id": self.user_id, + "reason": reason} + + MatrixMessage.__init__(self, client.room_kick, data) + + def decode_body(self, server): + object_hook = partial( + MatrixEvents.MatrixKickEvent.from_dict, + server, + self.room_id, + self.user_id, + self.reason) + + return self._decode(server, object_hook) diff --git a/matrix/commands.py b/matrix/commands.py index 0a5806c..5821aa6 100644 --- a/matrix/commands.py +++ b/matrix/commands.py @@ -27,7 +27,7 @@ from matrix.utf import utf8_decode from matrix.api import (MatrixTopicMessage, MatrixRedactMessage, MatrixBacklogMessage, MatrixJoinMessage, MatrixPartMessage, MatrixInviteMessage, - MatrixEmoteMessage) + MatrixEmoteMessage, MatrixKickMessage) from matrix.utils import key_from_value, tags_from_line_data from matrix.plugin_options import DebugType from matrix.server import MatrixServer @@ -103,6 +103,7 @@ def hook_commands(): W.hook_command_run('/join', 'matrix_command_join_cb', '') W.hook_command_run('/part', 'matrix_command_part_cb', '') W.hook_command_run('/invite', 'matrix_command_invite_cb', '') + W.hook_command_run('/kick', 'matrix_command_kick_cb', '') if OPTIONS.enable_backlog: hook_page_up() @@ -309,6 +310,42 @@ def matrix_command_invite_cb(data, buffer, command): return W.WEECHAT_RC_OK +@utf8_decode +def matrix_command_kick_cb(data, buffer, command): + + def kick(server, buf, args): + split_args = args.split(" ", 1)[1:] + + if (len(split_args) < 1 or + split_args[0].startswith("#") and len(split_args) < 2): + error_msg = ( + '{prefix}Error with command "/kick" (help on ' + 'command: /help kick)').format(prefix=W.prefix("error")) + W.prnt("", error_msg) + return + + if split_args[0].startswith("#"): + assert len(split_args) >= 2 + room_id = split_args[0] + kicked_user = split_args[1] + reason = split_args[2:] or None + else: + room_id = key_from_value(server.buffers, buf) + kicked_user = split_args[0] + reason = split_args[1:] or None + + message = MatrixKickMessage( + server.client, room_id=room_id, user_id=kicked_user, reason=reason) + server.send_or_queue(message) + + for server in SERVERS.values(): + if buffer in server.buffers.values(): + kick(server, buffer, command) + return W.WEECHAT_RC_OK_EAT + + return W.WEECHAT_RC_OK + + def event_id_from_line(buf, target_number): # type: (weechat.buffer, int) -> str own_lines = W.hdata_pointer(W.hdata_get('buffer'), buf, 'own_lines') @@ -918,7 +955,7 @@ def matrix_command_topic_cb(data, buffer, command): elif buffer == server.server_buffer: message = ("{prefix}matrix: command \"topic\" must be " "executed on a Matrix channel buffer" - ).format(prefix=W.prefix("error")) + ).format(prefix=W.prefix("error")) W.prnt(buffer, message) return W.WEECHAT_RC_OK_EAT diff --git a/matrix/events.py b/matrix/events.py index 8b1f985..c3d2b65 100644 --- a/matrix/events.py +++ b/matrix/events.py @@ -246,6 +246,26 @@ class MatrixInviteEvent(MatrixEvent): False, parsed_dict) +class MatrixKickEvent(MatrixEvent): + + def __init__(self, server, room_id, user_id, reason): + self.room_id = room_id + self.user_id = user_id + self.reason = reason + MatrixEvent.__init__(self, server) + + @classmethod + def from_dict(cls, server, room_id, user_id, reason, parsed_dict): + try: + if parsed_dict == {}: + return cls(server, room_id, user_id, reason) + + raise KeyError + except KeyError: + return MatrixErrorEvent.from_dict(server, "Error kicking user", + False, parsed_dict) + + class MatrixBacklogEvent(MatrixEvent): def __init__(self, server, room_id, end_token, events): diff --git a/matrix/rooms.py b/matrix/rooms.py index f97f98b..ed2e0e3 100644 --- a/matrix/rooms.py +++ b/matrix/rooms.py @@ -465,25 +465,27 @@ class RoomMemberJoin(RoomEvent): class RoomMemberLeave(RoomEvent): - def __init__(self, event_id, sender, age): + def __init__(self, event_id, sender, leaving_user, age): + self.leaving_user = leaving_user RoomEvent.__init__(self, event_id, sender, age) @classmethod def from_dict(cls, event_dict): event_id = sanitize_id(event_dict["event_id"]) sender = sanitize_id(event_dict["sender"]) + leaving_user = sanitize_id(event_dict["state_key"]) age = sanitize_age(event_dict["unsigned"]["age"]) - return cls(event_id, sender, age) + return cls(event_id, sender, leaving_user, age) def execute(self, server, room, buff, tags): - if self.sender in room.users: - nick_pointer = W.nicklist_search_nick(buff, "", self.sender) + if self.leaving_user in room.users: + nick_pointer = W.nicklist_search_nick(buff, "", self.leaving_user) if nick_pointer: W.nicklist_remove_nick(buff, nick_pointer) - del room.users[self.sender] + del room.users[self.leaving_user] class RoomPowerLevels(RoomEvent):