update
This commit is contained in:
parent
d6ae214cfb
commit
1d0c3b2e6e
@ -1,7 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from src.domain.admin.entities import Admin
|
from src.domain.admin.entities import Admin
|
||||||
from src.domain.admin.ports import CommandSymbolsRepository, RoomRepository
|
from src.domain.admin.ports import CommandSymbolsRepository, MucJidResolver, RoomRepository
|
||||||
from src.domain.admin.usecases import (
|
from src.domain.admin.usecases import (
|
||||||
HandleCmd,
|
HandleCmd,
|
||||||
HandleExit,
|
HandleExit,
|
||||||
@ -38,6 +38,7 @@ class CommandHandler:
|
|||||||
bot_nick: str,
|
bot_nick: str,
|
||||||
cmd_symbols_repo: CommandSymbolsRepository,
|
cmd_symbols_repo: CommandSymbolsRepository,
|
||||||
room_repo: RoomRepository,
|
room_repo: RoomRepository,
|
||||||
|
jid_resolver: MucJidResolver,
|
||||||
handle_join: HandleJoin,
|
handle_join: HandleJoin,
|
||||||
handle_exit: HandleExit,
|
handle_exit: HandleExit,
|
||||||
handle_list: HandleList,
|
handle_list: HandleList,
|
||||||
@ -53,6 +54,7 @@ class CommandHandler:
|
|||||||
self._bot_nick = bot_nick.lower()
|
self._bot_nick = bot_nick.lower()
|
||||||
self._cmd_symbols_repo = cmd_symbols_repo
|
self._cmd_symbols_repo = cmd_symbols_repo
|
||||||
self._room_repo = room_repo
|
self._room_repo = room_repo
|
||||||
|
self._jid_resolver = jid_resolver
|
||||||
self._handle_join = handle_join
|
self._handle_join = handle_join
|
||||||
self._handle_exit = handle_exit
|
self._handle_exit = handle_exit
|
||||||
self._handle_list = handle_list
|
self._handle_list = handle_list
|
||||||
@ -115,23 +117,24 @@ class CommandHandler:
|
|||||||
|
|
||||||
async def _handle_room(self, msg) -> None:
|
async def _handle_room(self, msg) -> None:
|
||||||
room_jid = msg["from"].bare
|
room_jid = msg["from"].bare
|
||||||
# full JID участника в MUC: room@conf/nick → берём nick как идентификатор
|
|
||||||
# но для проверки прав нужен реальный JID — slixmpp предоставляет его через MUC
|
|
||||||
sender_nick = msg["from"].resource
|
sender_nick = msg["from"].resource
|
||||||
body = msg["body"].strip() if msg["body"] else ""
|
body = msg["body"].strip() if msg["body"] else ""
|
||||||
|
|
||||||
if not body:
|
if not body:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
logger.debug("Сообщение в комнате %s от %s: %r", room_jid, sender_nick, body)
|
||||||
|
|
||||||
# Получаем реальный JID отправителя через MUC plugin
|
# Получаем реальный JID отправителя через MUC plugin
|
||||||
caller_jid = self._get_real_jid(msg)
|
caller_jid = self._get_real_jid(room_jid, sender_nick)
|
||||||
|
logger.debug("Реальный JID отправителя: %s", caller_jid)
|
||||||
|
|
||||||
# Проверяем обращение по нику бота
|
# Проверяем обращение по нику бота
|
||||||
bot_nick_lower = self._bot_nick
|
|
||||||
body_lower = body.lower()
|
body_lower = body.lower()
|
||||||
if body_lower.startswith(bot_nick_lower + ",") or body_lower.startswith(
|
if body_lower.startswith(self._bot_nick + ",") or body_lower.startswith(
|
||||||
bot_nick_lower + ":"
|
self._bot_nick + ":"
|
||||||
):
|
):
|
||||||
|
logger.debug("Обращение к боту по нику в %s", room_jid)
|
||||||
await self._handle_room_help.execute(room_jid, caller_jid or sender_nick)
|
await self._handle_room_help.execute(room_jid, caller_jid or sender_nick)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -148,13 +151,18 @@ class CommandHandler:
|
|||||||
command = parts[0].lower()
|
command = parts[0].lower()
|
||||||
arg = parts[1].strip() if len(parts) > 1 else ""
|
arg = parts[1].strip() if len(parts) > 1 else ""
|
||||||
|
|
||||||
|
logger.info("Команда в комнате %s от %s: %s %r", room_jid, caller_jid or sender_nick, command, arg)
|
||||||
|
|
||||||
# help доступен всем
|
# help доступен всем
|
||||||
if command == "help":
|
if command == "help":
|
||||||
await self._handle_room_help.execute(room_jid, caller_jid or sender_nick)
|
await self._handle_room_help.execute(room_jid, caller_jid or sender_nick)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Остальные команды — только для админа комнаты
|
# Остальные команды — только для админа комнаты
|
||||||
if not await self._is_room_admin(room_jid, caller_jid):
|
is_admin = await self._is_room_admin(room_jid, caller_jid)
|
||||||
|
logger.debug("Проверка прав: %s admin=%s в %s", caller_jid, is_admin, room_jid)
|
||||||
|
if not is_admin:
|
||||||
|
logger.info("Отклонено: %s не является админом %s", caller_jid, room_jid)
|
||||||
return
|
return
|
||||||
|
|
||||||
if command == "subscribe":
|
if command == "subscribe":
|
||||||
@ -163,6 +171,8 @@ class CommandHandler:
|
|||||||
elif command == "unsubscribe":
|
elif command == "unsubscribe":
|
||||||
if arg:
|
if arg:
|
||||||
await self._handle_unsubscribe.execute(room_jid, arg)
|
await self._handle_unsubscribe.execute(room_jid, arg)
|
||||||
|
else:
|
||||||
|
logger.warning("subscribe без аргумента в %s", room_jid)
|
||||||
|
|
||||||
elif command == "list":
|
elif command == "list":
|
||||||
await self._handle_list_subs.execute(room_jid)
|
await self._handle_list_subs.execute(room_jid)
|
||||||
@ -170,11 +180,17 @@ class CommandHandler:
|
|||||||
elif command == "cmd":
|
elif command == "cmd":
|
||||||
if arg:
|
if arg:
|
||||||
await self._handle_cmd.execute(room_jid, arg)
|
await self._handle_cmd.execute(room_jid, arg)
|
||||||
|
else:
|
||||||
|
logger.warning("cmd без аргумента в %s", room_jid)
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.debug("Неизвестная команда %r в %s", command, room_jid)
|
||||||
|
|
||||||
async def _parse_subscribe(self, room_jid: str, arg: str) -> None:
|
async def _parse_subscribe(self, room_jid: str, arg: str) -> None:
|
||||||
"""Парсит: <url> [interval_minutes]"""
|
"""Парсит: <url> [interval_minutes]"""
|
||||||
parts = arg.split()
|
parts = arg.split()
|
||||||
if not parts:
|
if not parts:
|
||||||
|
logger.warning("subscribe без URL в %s", room_jid)
|
||||||
return
|
return
|
||||||
source = parts[0]
|
source = parts[0]
|
||||||
interval = Subscription.DEFAULT_INTERVAL_MINUTES
|
interval = Subscription.DEFAULT_INTERVAL_MINUTES
|
||||||
@ -182,7 +198,8 @@ class CommandHandler:
|
|||||||
try:
|
try:
|
||||||
interval = int(parts[1])
|
interval = int(parts[1])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
logger.warning("Неверный интервал %r, используется %d", parts[1], interval)
|
||||||
|
logger.info("subscribe %s interval=%d в %s", source, interval, room_jid)
|
||||||
await self._handle_subscribe.execute(room_jid, source, interval)
|
await self._handle_subscribe.execute(room_jid, source, interval)
|
||||||
|
|
||||||
async def _is_room_admin(self, room_jid: str, caller_jid: str | None) -> bool:
|
async def _is_room_admin(self, room_jid: str, caller_jid: str | None) -> bool:
|
||||||
@ -193,14 +210,6 @@ class CommandHandler:
|
|||||||
return False
|
return False
|
||||||
return room.admin_jid == caller_jid
|
return room.admin_jid == caller_jid
|
||||||
|
|
||||||
def _get_real_jid(self, msg) -> str | None:
|
def _get_real_jid(self, room_jid: str, nick: str) -> str | None:
|
||||||
"""Получает реальный JID участника через MUC plugin."""
|
"""Получает реальный JID участника MUC через resolver."""
|
||||||
try:
|
return self._jid_resolver.get_real_jid(room_jid, nick)
|
||||||
muc = msg.get_plugin("xep_0045", None)
|
|
||||||
if muc is None:
|
|
||||||
return None
|
|
||||||
room_jid = msg["from"].bare
|
|
||||||
nick = msg["from"].resource
|
|
||||||
return str(muc.get_jid_property(room_jid, nick, "jid"))
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
|
|||||||
@ -5,14 +5,14 @@ from typing import Callable, Awaitable, List, Optional
|
|||||||
from slixmpp import ClientXMPP
|
from slixmpp import ClientXMPP
|
||||||
from slixmpp.exceptions import IqError, IqTimeout
|
from slixmpp.exceptions import IqError, IqTimeout
|
||||||
|
|
||||||
from src.domain.admin.ports import JabberRoomJoiner, JabberRoomLeaver
|
from src.domain.admin.ports import JabberRoomJoiner, JabberRoomLeaver, MucJidResolver
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
MessageCallback = Callable[["slixmpp.stanza.Message"], Awaitable[None]]
|
MessageCallback = Callable[["slixmpp.stanza.Message"], Awaitable[None]]
|
||||||
|
|
||||||
|
|
||||||
class JabberConnection(ClientXMPP, JabberRoomJoiner, JabberRoomLeaver):
|
class JabberConnection(ClientXMPP, JabberRoomJoiner, JabberRoomLeaver, MucJidResolver):
|
||||||
"""
|
"""
|
||||||
Единственный владелец XMPP-соединения.
|
Единственный владелец XMPP-соединения.
|
||||||
Реализует JabberRoomJoiner и JabberRoomLeaver для домена.
|
Реализует JabberRoomJoiner и JabberRoomLeaver для домена.
|
||||||
@ -29,7 +29,6 @@ class JabberConnection(ClientXMPP, JabberRoomJoiner, JabberRoomLeaver):
|
|||||||
|
|
||||||
self.add_event_handler("session_start", self._on_session_start)
|
self.add_event_handler("session_start", self._on_session_start)
|
||||||
self.add_event_handler("message", self._on_message)
|
self.add_event_handler("message", self._on_message)
|
||||||
self.add_event_handler("groupchat_message", self._on_message)
|
|
||||||
self.add_event_handler("failed_auth", self._on_failed_auth)
|
self.add_event_handler("failed_auth", self._on_failed_auth)
|
||||||
|
|
||||||
def set_message_callback(self, callback: MessageCallback) -> None:
|
def set_message_callback(self, callback: MessageCallback) -> None:
|
||||||
@ -53,9 +52,12 @@ class JabberConnection(ClientXMPP, JabberRoomJoiner, JabberRoomLeaver):
|
|||||||
logger.exception("Не удалось зайти в комнату %s при старте", room_jid)
|
logger.exception("Не удалось зайти в комнату %s при старте", room_jid)
|
||||||
|
|
||||||
async def _on_message(self, msg) -> None:
|
async def _on_message(self, msg) -> None:
|
||||||
# Игнорируем собственные сообщения
|
# Игнорируем собственные сообщения (1:1 чат)
|
||||||
if msg["from"].bare == self.boundjid.bare:
|
if msg["from"].bare == self.boundjid.bare:
|
||||||
return
|
return
|
||||||
|
# Игнорируем собственные сообщения в MUC (отражённые сервером)
|
||||||
|
if msg["type"] == "groupchat" and msg["from"].resource == self._nick:
|
||||||
|
return
|
||||||
if self._message_callback is not None:
|
if self._message_callback is not None:
|
||||||
try:
|
try:
|
||||||
await self._message_callback(msg)
|
await self._message_callback(msg)
|
||||||
@ -95,6 +97,18 @@ class JabberConnection(ClientXMPP, JabberRoomJoiner, JabberRoomLeaver):
|
|||||||
logger.warning("Не удалось отправить сообщение в %s", room_jid)
|
logger.warning("Не удалось отправить сообщение в %s", room_jid)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_real_jid(self, room_jid: str, nick: str) -> str | None:
|
||||||
|
"""Возвращает реальный JID участника MUC по нику, или None если недоступен."""
|
||||||
|
try:
|
||||||
|
muc = self.plugin["xep_0045"]
|
||||||
|
jid = muc.get_jid_property(room_jid, nick, "jid")
|
||||||
|
result = str(jid) if jid else None
|
||||||
|
logger.debug("Реальный JID %s/%s → %s", room_jid, nick, result)
|
||||||
|
return result
|
||||||
|
except Exception:
|
||||||
|
logger.debug("Не удалось получить реальный JID для %s/%s", room_jid, nick)
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nick(self) -> str:
|
def nick(self) -> str:
|
||||||
return self._nick
|
return self._nick
|
||||||
|
|||||||
@ -79,3 +79,11 @@ class JabberRoomLeaver(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def leave_room(self, room_jid: str) -> None:
|
async def leave_room(self, room_jid: str) -> None:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class MucJidResolver(ABC):
|
||||||
|
"""Порт для получения реального JID участника MUC по нику."""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_real_jid(self, room_jid: str, nick: str) -> "str | None":
|
||||||
|
...
|
||||||
|
|||||||
@ -90,6 +90,7 @@ async def setup() -> tuple:
|
|||||||
bot_nick=bot_nick,
|
bot_nick=bot_nick,
|
||||||
cmd_symbols_repo=cmd_sym_repo,
|
cmd_symbols_repo=cmd_sym_repo,
|
||||||
room_repo=room_repo,
|
room_repo=room_repo,
|
||||||
|
jid_resolver=connection,
|
||||||
handle_join=handle_join,
|
handle_join=handle_join,
|
||||||
handle_exit=handle_exit,
|
handle_exit=handle_exit,
|
||||||
handle_list=handle_list,
|
handle_list=handle_list,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user