diff --git a/photo_bot/__pycache__/handlers.cpython-313.pyc b/photo_bot/__pycache__/handlers.cpython-313.pyc index 3e6d474..681a76c 100644 Binary files a/photo_bot/__pycache__/handlers.cpython-313.pyc and b/photo_bot/__pycache__/handlers.cpython-313.pyc differ diff --git a/photo_bot/handlers.py b/photo_bot/handlers.py index 16d74c5..3240af9 100644 --- a/photo_bot/handlers.py +++ b/photo_bot/handlers.py @@ -30,7 +30,7 @@ from utils.texts import ( photo_cancel_text, photo_preview_ready, photo_moderation_pending, - photo_rejected_notice, + photo_welcome_with_status, PHOTO_TEST_ENTRY_TEXT, PHOTO_TEST_WELCOME_TEXT, PHOTO_TEST_PREVIEW_TEXT, @@ -158,14 +158,16 @@ async def check_moderation_status(user_id: str) -> dict: async def send_dynamic_photo_main_menu(msg: Message, user_id: str): """Вход в раздел фото (паттерн ЛК): модуль сам запрашивает данные и показывает их. - - pending — показать инфо «фото на модерации» и НЕ вводить в модуль + - pending — отдельное сообщение «фото на модерации», модуль НЕ открывается (кнопок загрузки фото нет); - - rejected — показать причину отказа, кнопки остаются (новое фото); - - иначе/ошибка API — штатный вход в модуль. + - rejected — ОДНО сообщение: меню + причина отказа (кнопки на месте); + - иначе/ошибка API — штатное меню входа. """ + status = None if not config.PHOTO_TEST_MODE: status = await check_moderation_status(user_id) if status.get("status") == "ok" and status.get("moderation_status") == "pending": + # Фото на модерации — не вводим в модуль (кнопок загрузки нет) photo_id = status.get("photo_id", "???") log_menu_stats(user_id, "Photo Bot", "Вход заблокирован — фото на модерации") await msg.answer( @@ -173,22 +175,22 @@ async def send_dynamic_photo_main_menu(msg: Message, user_id: str): parse_mode="html" ) return - elif status.get("status") == "ok" and status.get("moderation_status") == "rejected": - reason = (status.get("rejection_reason") or "Причина не указана.").strip() + if status.get("status") == "ok" and status.get("moderation_status") == "rejected": log_menu_stats(user_id, "Photo Bot", "Вход — фото отклонено, показана причина") - await msg.answer(photo_rejected_notice(reason), parse_mode="html") - # Меню показывается ниже: кнопки остаются, пользователь шлёт новое фото elif status.get("status") != "ok": logger.warning( f"Не удалось проверить статус модерации для {user_id}: {status.get('reason')}" ) + status = None states.set_state(user_id, "PHOTO_MODE") log_menu_stats(user_id, "Photo Bot (TEST)" if config.PHOTO_TEST_MODE else "Photo Bot", "Вход") - await msg.answer( - PHOTO_TEST_ENTRY_TEXT if config.PHOTO_TEST_MODE else PHOTO_MAIN_MENU_TEXT, - parse_mode="html" - ) + # Одно универсальное сообщение: меню + (если нужно) причина отказа + if config.PHOTO_TEST_MODE: + entry_text = PHOTO_TEST_ENTRY_TEXT + else: + entry_text = photo_welcome_with_status(status) + await msg.answer(entry_text, parse_mode="html") # ========================================================= diff --git a/utils/__pycache__/texts.cpython-313.pyc b/utils/__pycache__/texts.cpython-313.pyc new file mode 100644 index 0000000..b2b7bdf Binary files /dev/null and b/utils/__pycache__/texts.cpython-313.pyc differ diff --git a/utils/texts.py b/utils/texts.py index e7385bd..2c90526 100644 --- a/utils/texts.py +++ b/utils/texts.py @@ -202,13 +202,17 @@ def sd_file_upload_error() -> str: # --- Private functions (Internal logic) --- -def _photo_welcome(emojis: dict, show_test: bool = False) -> str: +def _photo_welcome(emojis: dict, show_test: bool = False, info: str = None) -> str: + """Входное сообщение фото-режима. info — необязательный блок о статусе + модерации (отказ/ожидание) — вставляется перед списком кнопок.""" text = ( f"🖼 Режим обновления фото профиля\n\n" f"📸 Пришлите мне вашу фотографию.\n\n" f"Бот автоматически найдёт лицо, покажет превью\n" f"и отправит фото на публикацию в ваши корпоративные сервисы.\n\n" ) + if info: + text += info + "\n\n" if show_test: text += f"{emojis['1']} — тест проверка фото\n" return text + f"{emojis['0']} — В главное меню" @@ -245,12 +249,25 @@ def _photo_moderation_pending(photo_id: str, emojis: dict) -> str: f"{emojis['0']} — В главное меню" ) -def _photo_rejected_notice(reason: str, emojis: dict) -> str: - return ( - f"⚠️ Ваше предыдущее фото было отклонено.\n\n" - f"📝 Причина: {reason}\n\n" - f"Пожалуйста, отправьте новое фото." - ) +def _photo_status_info(status: dict = None, emojis: dict = None) -> str | None: + """Блок о статусе модерации для входного сообщения. Универсальный для всех + случаев: rejected → причина отказа, pending → ожидание, прочее → пусто.""" + if not status or status.get("status") != "ok": + return None + ms = status.get("moderation_status") + if ms == "rejected": + reason = (status.get("rejection_reason") or "Причина не указана.").strip() + return ( + f"⚠️ Ваше предыдущее фото было отклонено.\n" + f"📝 Причина: {reason}\n\n" + f"Пожалуйста, отправьте новое фото." + ) + if ms == "pending": + return ( + f"⏳ У вас уже есть фото на модерации.\n" + f"Ожидайте решения модератора." + ) + return None def _photo_test_welcome(emojis: dict) -> str: return ( @@ -378,8 +395,11 @@ def photo_cancel_text() -> str: def photo_moderation_pending(photo_id: str) -> str: return _photo_moderation_pending(photo_id, EMOJI_DIGITS) -def photo_rejected_notice(reason: str) -> str: - return _photo_rejected_notice(reason, EMOJI_DIGITS) +def photo_welcome_with_status(status: dict = None) -> str: + """Универсальное входное сообщение фото-режима: меню + статус модерации, + если он требует внимания (отказ с причиной).""" + info = _photo_status_info(status, EMOJI_DIGITS) + return _photo_welcome(EMOJI_DIGITS, info=info) PHOTO_TEST_WELCOME_TEXT = _photo_test_welcome(EMOJI_DIGITS) PHOTO_TEST_PREVIEW_TEXT = _photo_test_preview(EMOJI_DIGITS)