diff --git a/src/dutylog/application/__main__.py b/src/dutylog/application/__main__.py
index d88336b..059be71 100644
--- a/src/dutylog/application/__main__.py
+++ b/src/dutylog/application/__main__.py
@@ -12,6 +12,7 @@ from dutylog.application.bot.user_handlers import router as user_router
from dutylog.application.bot.user_dialogs import main_menu_dialog
from dutylog.application.bot.admin_dialogs import admin_menu_dialog
from dutylog.application.bot.user_dialogs.registration_dialog import registration_dialog
+from dutylog.application.bot.user_dialogs.user_menu.feedback import feedback_router
from dutylog.infrastructure.ioc import (
ConfigProvider,
DatabaseProvider,
@@ -46,6 +47,7 @@ async def main():
)
dp.include_router(user_router)
+ dp.include_router(feedback_router)
dp.include_router(main_menu_dialog)
dp.include_router(admin_menu_dialog)
dp.include_router(registration_dialog)
diff --git a/src/dutylog/application/bot/user_dialogs/user_menu/feedback.py b/src/dutylog/application/bot/user_dialogs/user_menu/feedback.py
index ddb8c19..6dab73b 100644
--- a/src/dutylog/application/bot/user_dialogs/user_menu/feedback.py
+++ b/src/dutylog/application/bot/user_dialogs/user_menu/feedback.py
@@ -1,5 +1,7 @@
-from aiogram import Bot
-from aiogram.types import Message
+from aiogram import Bot, Router, F
+from aiogram.fsm.context import FSMContext
+from aiogram.fsm.state import State, StatesGroup
+from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
from aiogram_dialog import Window, DialogManager
from aiogram_dialog.widgets.text import Const
from aiogram_dialog.widgets.kbd import SwitchTo
@@ -13,6 +15,13 @@ from dutylog.infrastructure.database.repositories.residents_repository import Re
from dutylog.infrastructure.utils.config import Config
+class FeedbackReplySG(StatesGroup):
+ waiting_reply = State()
+
+
+feedback_router = Router()
+
+
@inject
async def on_feedback_message(
message: Message,
@@ -22,8 +31,7 @@ async def on_feedback_message(
residents_repository: FromDishka[ResidentsRepository],
config: FromDishka[Config],
) -> None:
- assert message.bot
- bot: Bot = message.bot
+ bot: Bot = dialog_manager.middleware_data["bot"]
user = await users_repository.get_user_by_id(message.from_user.id)
resident = await residents_repository.get_resident_by_user_id(message.from_user.id)
@@ -31,13 +39,21 @@ async def on_feedback_message(
username = f"@{user.username}" if user and user.username else "без username"
name = resident.real_name if resident and resident.real_name else (user.first_name if user and user.first_name else "Неизвестно")
- meta = (
+ reply_markup = InlineKeyboardMarkup(inline_keyboard=[[
+ InlineKeyboardButton(
+ text="↩️ Ответить",
+ callback_data=f"feedback_reply:{message.from_user.id}",
+ )
+ ]])
+
+ await bot.send_message(
+ config.bot.creator_id,
f"📬 Обратная связь\n\n"
f"👤 {name} ({username})\n"
- f"🆔 {message.from_user.id}"
+ f"🆔 {message.from_user.id}",
+ reply_markup=reply_markup,
)
- await bot.send_message(config.bot.creator_id, meta)
await bot.copy_message(
chat_id=config.bot.creator_id,
from_chat_id=message.chat.id,
@@ -48,11 +64,31 @@ async def on_feedback_message(
await dialog_manager.switch_to(MainMenuSG.main)
+@feedback_router.callback_query(F.data.startswith("feedback_reply:"))
+async def on_reply_click(callback: CallbackQuery, state: FSMContext) -> None:
+ user_id = int(callback.data.split(":")[1])
+ await state.set_state(FeedbackReplySG.waiting_reply)
+ await state.update_data(reply_to_user_id=user_id)
+ await callback.message.answer("✏️ Напишите ответ пользователю:")
+ await callback.answer()
+
+
+@feedback_router.message(FeedbackReplySG.waiting_reply)
+async def on_reply_message(message: Message, state: FSMContext) -> None:
+ data = await state.get_data()
+ user_id = data["reply_to_user_id"]
+
+ await message.bot.send_message(user_id, "✅ Ответ от администрации ⬇️")
+ await message.copy_to(user_id)
+ await state.clear()
+ await message.answer("✅ Ответ отправлен пользователю.")
+
+
feedback_window = Window(
Const(
- "💬 Обратная связь\n\n"
+ "📬 Обратная связь\n\n"
"Напишите ваше сообщение — предложение по улучшению, вопрос, жалоба или что угодно ещё.\n\n"
- "🔒 Сообщение полностью анонимно."
+ "🔒 Сообщение анонимно для других пользователей и передаётся только администрации."
),
MessageInput(on_feedback_message),
SwitchTo(Const("◀️ Назад"), id="back_from_feedback", state=MainMenuSG.main),