From 8be5efa71d2a73c82b1df57049402e086a8b768b Mon Sep 17 00:00:00 2001 From: Markov Andrey Date: Tue, 30 Jun 2026 21:43:03 +0000 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B4=D0=B0=D0=BA=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20global=5Fremove.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bots/commands/global_remove.py | 98 ++++++---------------------------- 1 file changed, 16 insertions(+), 82 deletions(-) diff --git a/bots/commands/global_remove.py b/bots/commands/global_remove.py index cb7214c..c69f531 100644 --- a/bots/commands/global_remove.py +++ b/bots/commands/global_remove.py @@ -1,107 +1,41 @@ -# -*- coding: utf-8 -*- -""" -Команда !global_remove – удаление документа из глобальной базы знаний по его названию. -Только для администраторов, работает только в личном чате. - -Изменения для PostgreSQL (asyncpg): -- Замена курсоров на прямые запросы conn.fetch / conn.execute. -- Использование параметризованных запросов с $1, $2 и ANY($1) для массовых операций. -- Удаление синтаксиса, специфичного для MySQL/MariaDB. -""" - import logging from core.commands.base import Command logger = logging.getLogger(__name__) - class GlobalRemoveCommand(Command): - """Удаляет глобальный документ по точному совпадению source_name.""" - name = "!global_remove" aliases = ["/global_remove"] permission = "admin" async def execute(self, msg, args: str, user_jid: str, room_jid: str = None): - """ - Алгоритм: - 1. Проверка прав администратора. - 2. Проверка, что команда вызвана в личном чате (room_jid is None). - 3. Разбор аргументов, извлечение названия документа (в кавычках или без). - 4. Поиск всех глобальных документов с таким source_name. - 5. Удаление найденных документов из Qdrant (по doc_id). - 6. Удаление записей из таблиц document_access и documents в PostgreSQL. - """ - # 1. Проверка прав администратора if not self.check_permission(user_jid): - reply = msg.reply("⛔ У вас нет прав на удаление глобальных документов.") - if reply: - reply.send() # исправлено - else: - logger.error("Не удалось отправить сообщение о недостатке прав для global_remove") + reply = msg.reply("⛔ Нет прав.") + if reply: reply.send() return - - # 2. Команда работает только в личном чате if room_jid: - reply = msg.reply("⚠️ Команда !global_remove работает только в личном чате.") - if reply: - reply.send() # исправлено - else: - logger.error("Не удалось отправить сообщение об ограничении !global_remove") + reply = msg.reply("⚠️ Команда работает только в личном чате.") + if reply: reply.send() return - - # 3. Разбор аргументов команды _, flags, pos = self.parse_args(args) if not pos: - reply = msg.reply("❌ Укажите название документа для удаления. Пример: `!global_remove \"ГОСТ Р 12345\"`") - if reply: - reply.send() # исправлено - else: - logger.error("Не удалось отправить сообщение о необходимости указать название документа") + reply = msg.reply("❌ Укажите название документа.") + if reply: reply.send() return - source_name = " ".join(pos).strip() - # Удаляем возможные кавычки, если пользователь заключил название в них if source_name.startswith('"') and source_name.endswith('"'): source_name = source_name[1:-1] - - # 4. Поиск глобальных документов с указанным названием - async with self.bot.db.pool.acquire() as conn: - rows = await conn.fetch( - "SELECT id FROM documents WHERE is_global = TRUE AND source_name = $1", - source_name - ) - doc_ids = [row['id'] for row in rows] - - if not doc_ids: - reply = msg.reply(f"📭 Глобальный документ с названием '{source_name}' не найден.") - if reply: - reply.send() # исправлено + try: + result = await self.bot.rag_client.delete_global(source_name) + if result.get('status') == 'ok': + reply = msg.reply(f"✅ Глобальный документ '{source_name}' удалён.") else: - logger.error("Не удалось отправить сообщение о ненайденном глобальном документе") - return - - # 5. Удаление из Qdrant (по каждому doc_id) - for doc_id in doc_ids: - self.bot.qdrant.delete_by_doc_id(doc_id) - logger.debug(f"Удалён из Qdrant doc_id={doc_id}") - - # 6. Удаление из PostgreSQL (сначала связанные права доступа, затем сам документ) - async with self.bot.db.pool.acquire() as conn: - # Удаляем записи о доступе (если есть) - await conn.execute("DELETE FROM document_access WHERE doc_id = ANY($1)", doc_ids) - # Удаляем сами документы - await conn.execute("DELETE FROM documents WHERE id = ANY($1)", doc_ids) - - logger.info(f"Администратор {user_jid} удалил глобальный документ '{source_name}' (doc_ids: {doc_ids})") - reply = msg.reply(f"✅ Глобальный документ '{source_name}' удалён из базы знаний.") + reply = msg.reply(f"❌ Ошибка удаления: {result}") + except Exception as e: + logger.exception(f"Ошибка в !global_remove: {e}") + reply = msg.reply(f"❌ Ошибка: {e}") if reply: - reply.send() # исправлено - else: - logger.error("Не удалось отправить подтверждение удаления глобального документа") + reply.send() def get_help(self) -> str: - return ( - "Удаляет глобальный документ по названию (админ, только в личном чате). " - "Использование: `!global_remove \"Название документа\"`" - ) \ No newline at end of file + return "Удаляет глобальный документ по названию (админ, только в личном чате)." \ No newline at end of file