smart-bot-factory 0.3.7__py3-none-any.whl → 0.3.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of smart-bot-factory might be problematic. Click here for more details.
- smart_bot_factory/admin/__init__.py +7 -7
- smart_bot_factory/admin/admin_events.py +483 -383
- smart_bot_factory/admin/admin_logic.py +234 -158
- smart_bot_factory/admin/admin_manager.py +68 -53
- smart_bot_factory/admin/admin_tester.py +46 -40
- smart_bot_factory/admin/timeout_checker.py +201 -153
- smart_bot_factory/aiogram_calendar/__init__.py +11 -3
- smart_bot_factory/aiogram_calendar/common.py +12 -18
- smart_bot_factory/aiogram_calendar/dialog_calendar.py +126 -64
- smart_bot_factory/aiogram_calendar/schemas.py +49 -28
- smart_bot_factory/aiogram_calendar/simple_calendar.py +94 -50
- smart_bot_factory/analytics/analytics_manager.py +414 -392
- smart_bot_factory/cli.py +204 -148
- smart_bot_factory/config.py +123 -102
- smart_bot_factory/core/bot_utils.py +474 -332
- smart_bot_factory/core/conversation_manager.py +287 -200
- smart_bot_factory/core/decorators.py +1200 -755
- smart_bot_factory/core/message_sender.py +287 -266
- smart_bot_factory/core/router.py +170 -100
- smart_bot_factory/core/router_manager.py +121 -83
- smart_bot_factory/core/states.py +4 -3
- smart_bot_factory/creation/__init__.py +1 -1
- smart_bot_factory/creation/bot_builder.py +320 -242
- smart_bot_factory/creation/bot_testing.py +440 -365
- smart_bot_factory/dashboard/__init__.py +1 -3
- smart_bot_factory/event/__init__.py +2 -7
- smart_bot_factory/handlers/handlers.py +676 -472
- smart_bot_factory/integrations/openai_client.py +218 -168
- smart_bot_factory/integrations/supabase_client.py +948 -637
- smart_bot_factory/message/__init__.py +18 -22
- smart_bot_factory/router/__init__.py +2 -2
- smart_bot_factory/setup_checker.py +162 -126
- smart_bot_factory/supabase/__init__.py +1 -1
- smart_bot_factory/supabase/client.py +631 -515
- smart_bot_factory/utils/__init__.py +2 -3
- smart_bot_factory/utils/debug_routing.py +38 -27
- smart_bot_factory/utils/prompt_loader.py +153 -120
- smart_bot_factory/utils/user_prompt_loader.py +55 -56
- smart_bot_factory/utm_link_generator.py +123 -116
- {smart_bot_factory-0.3.7.dist-info → smart_bot_factory-0.3.9.dist-info}/METADATA +3 -1
- smart_bot_factory-0.3.9.dist-info/RECORD +59 -0
- smart_bot_factory-0.3.7.dist-info/RECORD +0 -59
- {smart_bot_factory-0.3.7.dist-info → smart_bot_factory-0.3.9.dist-info}/WHEEL +0 -0
- {smart_bot_factory-0.3.7.dist-info → smart_bot_factory-0.3.9.dist-info}/entry_points.txt +0 -0
- {smart_bot_factory-0.3.7.dist-info → smart_bot_factory-0.3.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,45 +1,51 @@
|
|
|
1
1
|
# Исправленный admin_logic.py с правильной обработкой диалогов
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
|
|
5
|
-
from aiogram import
|
|
4
|
+
|
|
5
|
+
from aiogram import F, Router
|
|
6
6
|
from aiogram.filters import Command, StateFilter
|
|
7
7
|
from aiogram.fsm.context import FSMContext
|
|
8
|
-
from aiogram.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger(__name__)
|
|
8
|
+
from aiogram.types import (CallbackQuery, InlineKeyboardButton,
|
|
9
|
+
InlineKeyboardMarkup, Message)
|
|
12
10
|
|
|
13
11
|
# Импортируем состояния
|
|
14
|
-
from ..core.states import
|
|
12
|
+
from ..core.states import AdminStates
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
15
|
|
|
16
16
|
# Создаем роутер для админских обработчиков
|
|
17
17
|
admin_router = Router()
|
|
18
18
|
|
|
19
|
+
|
|
19
20
|
def setup_admin_handlers(dp):
|
|
20
21
|
"""Настройка админских обработчиков"""
|
|
21
22
|
dp.include_router(admin_router)
|
|
22
23
|
|
|
24
|
+
|
|
23
25
|
@admin_router.message(Command(commands=["отмена", "cancel"]))
|
|
24
26
|
async def cancel_handler(message: Message, state: FSMContext):
|
|
25
27
|
"""Отмена текущего действия и очистка state"""
|
|
26
28
|
from ..handlers.handlers import get_global_var
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
|
|
30
|
+
admin_manager = get_global_var("admin_manager")
|
|
31
|
+
|
|
29
32
|
# Получаем текущий state
|
|
30
33
|
current_state = await state.get_state()
|
|
31
|
-
|
|
34
|
+
|
|
32
35
|
# Очищаем временные файлы если это создание события
|
|
33
|
-
if current_state and current_state.startswith(
|
|
36
|
+
if current_state and current_state.startswith("AdminStates:create_event"):
|
|
34
37
|
from .admin_events import cleanup_temp_files
|
|
38
|
+
|
|
35
39
|
await cleanup_temp_files(state)
|
|
36
|
-
|
|
40
|
+
|
|
37
41
|
# Очищаем state
|
|
38
42
|
await state.clear()
|
|
39
|
-
|
|
43
|
+
|
|
40
44
|
if current_state:
|
|
41
|
-
logger.info(
|
|
42
|
-
|
|
45
|
+
logger.info(
|
|
46
|
+
f"State очищен для пользователя {message.from_user.id}: {current_state}"
|
|
47
|
+
)
|
|
48
|
+
|
|
43
49
|
# Если это админ, возвращаем в админ режим
|
|
44
50
|
if admin_manager.is_admin(message.from_user.id):
|
|
45
51
|
await state.set_state(AdminStates.admin_mode)
|
|
@@ -47,36 +53,47 @@ async def cancel_handler(message: Message, state: FSMContext):
|
|
|
47
53
|
"✅ Текущее действие отменено\n"
|
|
48
54
|
"Вы вернулись в админ режим\n\n"
|
|
49
55
|
"Используйте /admin для просмотра доступных команд",
|
|
50
|
-
parse_mode=
|
|
56
|
+
parse_mode="Markdown",
|
|
51
57
|
)
|
|
52
58
|
else:
|
|
53
59
|
await message.answer(
|
|
54
60
|
"✅ Текущее действие отменено\n\n"
|
|
55
61
|
"Используйте /start для начала работы",
|
|
56
|
-
parse_mode=
|
|
62
|
+
parse_mode="Markdown",
|
|
57
63
|
)
|
|
58
64
|
else:
|
|
59
65
|
await message.answer(
|
|
60
|
-
"ℹ️ Нет активных действий для отмены",
|
|
61
|
-
parse_mode='Markdown'
|
|
66
|
+
"ℹ️ Нет активных действий для отмены", parse_mode="Markdown"
|
|
62
67
|
)
|
|
63
68
|
|
|
69
|
+
|
|
64
70
|
async def admin_start_handler(message: Message, state: FSMContext):
|
|
65
71
|
"""Обработчик /start для админов в режиме администратора"""
|
|
66
72
|
from ..handlers.handlers import get_global_var
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
|
|
74
|
+
admin_manager = get_global_var("admin_manager")
|
|
75
|
+
|
|
69
76
|
await state.set_state(AdminStates.admin_mode)
|
|
70
|
-
|
|
77
|
+
|
|
71
78
|
admin_status = admin_manager.get_admin_mode_text(message.from_user.id)
|
|
72
|
-
|
|
79
|
+
|
|
73
80
|
# Основное меню админа
|
|
74
|
-
keyboard = InlineKeyboardMarkup(
|
|
75
|
-
[
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
keyboard = InlineKeyboardMarkup(
|
|
82
|
+
inline_keyboard=[
|
|
83
|
+
[InlineKeyboardButton(text="📊 Статистика", callback_data="admin_stats")],
|
|
84
|
+
[
|
|
85
|
+
InlineKeyboardButton(
|
|
86
|
+
text="💬 Активные чаты", callback_data="admin_active_chats"
|
|
87
|
+
)
|
|
88
|
+
],
|
|
89
|
+
[
|
|
90
|
+
InlineKeyboardButton(
|
|
91
|
+
text="🔄 Режим польз.", callback_data="admin_toggle_mode"
|
|
92
|
+
)
|
|
93
|
+
],
|
|
94
|
+
]
|
|
95
|
+
)
|
|
96
|
+
|
|
80
97
|
welcome_text = f"""
|
|
81
98
|
{admin_status}
|
|
82
99
|
|
|
@@ -97,119 +114,134 @@ async def admin_start_handler(message: Message, state: FSMContext):
|
|
|
97
114
|
• `/удалить_событие название` - отменить событие
|
|
98
115
|
"""
|
|
99
116
|
|
|
100
|
-
await message.answer(welcome_text, reply_markup=keyboard, parse_mode=
|
|
117
|
+
await message.answer(welcome_text, reply_markup=keyboard, parse_mode="Markdown")
|
|
118
|
+
|
|
101
119
|
|
|
102
120
|
@admin_router.message(Command(commands=["стат", "stats"]))
|
|
103
121
|
async def admin_stats_handler(message: Message, state: FSMContext):
|
|
104
122
|
"""Статистика воронки"""
|
|
105
123
|
from ..handlers.handlers import get_global_var
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
124
|
+
|
|
125
|
+
admin_manager = get_global_var("admin_manager")
|
|
126
|
+
analytics_manager = get_global_var("analytics_manager")
|
|
127
|
+
|
|
109
128
|
if not admin_manager.is_admin(message.from_user.id):
|
|
110
129
|
return
|
|
111
|
-
|
|
130
|
+
|
|
112
131
|
try:
|
|
113
132
|
# Получаем статистику
|
|
114
133
|
funnel_stats = await analytics_manager.get_funnel_stats(7)
|
|
115
134
|
events_stats = await analytics_manager.get_events_stats(7)
|
|
116
|
-
|
|
135
|
+
|
|
117
136
|
# Форматируем ответ
|
|
118
137
|
funnel_text = analytics_manager.format_funnel_stats(funnel_stats)
|
|
119
138
|
events_text = analytics_manager.format_events_stats(events_stats)
|
|
120
|
-
|
|
139
|
+
|
|
121
140
|
full_text = f"{funnel_text}\n\n{events_text}"
|
|
122
|
-
|
|
141
|
+
|
|
123
142
|
await message.answer(full_text)
|
|
124
|
-
|
|
143
|
+
|
|
125
144
|
except Exception as e:
|
|
126
145
|
logger.error(f"Ошибка получения статистики: {e}")
|
|
127
146
|
await message.answer("❌ Ошибка получения статистики")
|
|
128
147
|
|
|
148
|
+
|
|
129
149
|
@admin_router.message(Command(commands=["история", "history"]))
|
|
130
150
|
async def admin_history_handler(message: Message, state: FSMContext):
|
|
131
151
|
"""История пользователя"""
|
|
132
152
|
from ..handlers.handlers import get_global_var
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
153
|
+
|
|
154
|
+
admin_manager = get_global_var("admin_manager")
|
|
155
|
+
analytics_manager = get_global_var("analytics_manager")
|
|
156
|
+
|
|
136
157
|
if not admin_manager.is_admin(message.from_user.id):
|
|
137
158
|
return
|
|
138
|
-
|
|
159
|
+
|
|
139
160
|
try:
|
|
140
161
|
parts = message.text.split()
|
|
141
162
|
if len(parts) < 2:
|
|
142
163
|
await message.answer("Укажите ID пользователя: /история 123456789")
|
|
143
164
|
return
|
|
144
|
-
|
|
165
|
+
|
|
145
166
|
user_id = int(parts[1])
|
|
146
|
-
|
|
167
|
+
|
|
147
168
|
# Получаем историю (та же функция что использует кнопка)
|
|
148
169
|
journey = await analytics_manager.get_user_journey(user_id)
|
|
149
|
-
|
|
170
|
+
|
|
150
171
|
if not journey:
|
|
151
172
|
await message.answer(f"❌ У пользователя {user_id} нет активной сессии")
|
|
152
173
|
return
|
|
153
|
-
|
|
174
|
+
|
|
154
175
|
# Используем ту же функцию форматирования что и кнопка
|
|
155
176
|
history_text = analytics_manager.format_user_journey(user_id, journey)
|
|
156
|
-
|
|
177
|
+
|
|
157
178
|
await message.answer(history_text)
|
|
158
|
-
|
|
179
|
+
|
|
159
180
|
except ValueError:
|
|
160
181
|
await message.answer("❌ Неверный формат ID пользователя")
|
|
161
182
|
except Exception as e:
|
|
162
183
|
logger.error(f"Ошибка получения истории: {e}")
|
|
163
184
|
await message.answer("❌ Ошибка получения истории")
|
|
164
185
|
|
|
186
|
+
|
|
165
187
|
@admin_router.message(Command(commands=["чат", "chat"]))
|
|
166
188
|
async def admin_chat_handler(message: Message, state: FSMContext):
|
|
167
189
|
"""Начать диалог с пользователем"""
|
|
168
190
|
from ..handlers.handlers import get_global_var
|
|
169
|
-
|
|
170
|
-
admin_manager = get_global_var(
|
|
171
|
-
supabase_client = get_global_var(
|
|
172
|
-
conversation_manager = get_global_var(
|
|
173
|
-
|
|
191
|
+
|
|
192
|
+
admin_manager = get_global_var("admin_manager")
|
|
193
|
+
supabase_client = get_global_var("supabase_client")
|
|
194
|
+
conversation_manager = get_global_var("conversation_manager")
|
|
195
|
+
|
|
174
196
|
if not admin_manager.is_admin(message.from_user.id):
|
|
175
197
|
return
|
|
176
|
-
|
|
198
|
+
|
|
177
199
|
try:
|
|
178
200
|
# Парсим user_id из команды
|
|
179
201
|
parts = message.text.split()
|
|
180
202
|
if len(parts) < 2:
|
|
181
203
|
await message.answer("Укажите ID пользователя: /чат 123456789")
|
|
182
204
|
return
|
|
183
|
-
|
|
205
|
+
|
|
184
206
|
user_id = int(parts[1])
|
|
185
207
|
admin_id = message.from_user.id
|
|
186
|
-
|
|
187
|
-
logger.info(
|
|
188
|
-
|
|
208
|
+
|
|
209
|
+
logger.info(
|
|
210
|
+
f"👑 Админ {admin_id} хочет начать диалог с пользователем {user_id}"
|
|
211
|
+
)
|
|
212
|
+
|
|
189
213
|
# Проверяем, есть ли активная сессия у пользователя
|
|
190
214
|
session_info = await supabase_client.get_active_session(user_id)
|
|
191
215
|
if not session_info:
|
|
192
216
|
await message.answer(f"❌ У пользователя {user_id} нет активной сессии")
|
|
193
217
|
logger.warning(f"❌ У пользователя {user_id} нет активной сессии")
|
|
194
218
|
return
|
|
195
|
-
|
|
196
|
-
logger.info(
|
|
197
|
-
|
|
219
|
+
|
|
220
|
+
logger.info(
|
|
221
|
+
f"✅ У пользователя {user_id} есть активная сессия: {session_info['id']}"
|
|
222
|
+
)
|
|
223
|
+
|
|
198
224
|
# Начинаем диалог
|
|
199
|
-
logger.info(
|
|
225
|
+
logger.info("🚀 Запускаем создание диалога...")
|
|
200
226
|
success = await conversation_manager.start_admin_conversation(admin_id, user_id)
|
|
201
|
-
|
|
227
|
+
|
|
202
228
|
if success:
|
|
203
229
|
# ✅ ИСПРАВЛЕНИЕ: Правильно переключаем состояние админа
|
|
204
230
|
await state.set_state(AdminStates.in_conversation)
|
|
205
231
|
await state.update_data(conversation_user_id=user_id)
|
|
206
|
-
|
|
207
|
-
await message.answer(
|
|
208
|
-
|
|
232
|
+
|
|
233
|
+
await message.answer(
|
|
234
|
+
f"✅ Диалог с пользователем {user_id} начат\n💬 Ваши сообщения будут переданы пользователю\n⏹️ Используйте /стоп для завершения"
|
|
235
|
+
)
|
|
236
|
+
logger.info(
|
|
237
|
+
"✅ Диалог успешно создан, админ переключен в состояние in_conversation"
|
|
238
|
+
)
|
|
209
239
|
else:
|
|
210
|
-
await message.answer(
|
|
211
|
-
|
|
212
|
-
|
|
240
|
+
await message.answer(
|
|
241
|
+
f"❌ Не удалось начать диалог с пользователем {user_id}"
|
|
242
|
+
)
|
|
243
|
+
logger.error("❌ Не удалось создать диалог")
|
|
244
|
+
|
|
213
245
|
except ValueError:
|
|
214
246
|
await message.answer("❌ Неверный формат ID пользователя")
|
|
215
247
|
logger.error(f"❌ Неверный формат ID пользователя: {message.text}")
|
|
@@ -217,168 +249,187 @@ async def admin_chat_handler(message: Message, state: FSMContext):
|
|
|
217
249
|
logger.error(f"❌ Ошибка начала диалога: {e}")
|
|
218
250
|
await message.answer("❌ Ошибка начала диалога")
|
|
219
251
|
|
|
252
|
+
|
|
220
253
|
@admin_router.message(Command(commands=["чаты", "chats"]))
|
|
221
254
|
async def admin_active_chats_command(message: Message, state: FSMContext):
|
|
222
255
|
"""Показать активные диалоги админов"""
|
|
223
256
|
from ..handlers.handlers import get_global_var
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
257
|
+
|
|
258
|
+
admin_manager = get_global_var("admin_manager")
|
|
259
|
+
conversation_manager = get_global_var("conversation_manager")
|
|
260
|
+
|
|
227
261
|
if not admin_manager.is_admin(message.from_user.id):
|
|
228
262
|
return
|
|
229
|
-
|
|
263
|
+
|
|
230
264
|
try:
|
|
231
265
|
conversations = await conversation_manager.get_active_conversations()
|
|
232
266
|
formatted_text = conversation_manager.format_active_conversations(conversations)
|
|
233
|
-
|
|
267
|
+
|
|
234
268
|
# ✅ ИСПРАВЛЕНИЕ: Убираем parse_mode='Markdown' чтобы избежать ошибок парсинга
|
|
235
269
|
await message.answer(formatted_text)
|
|
236
|
-
|
|
270
|
+
|
|
237
271
|
except Exception as e:
|
|
238
272
|
logger.error(f"Ошибка получения активных чатов: {e}")
|
|
239
273
|
await message.answer("❌ Ошибка получения активных диалогов")
|
|
240
274
|
|
|
275
|
+
|
|
241
276
|
@admin_router.message(Command(commands=["стоп", "stop"]))
|
|
242
277
|
async def admin_stop_handler(message: Message, state: FSMContext):
|
|
243
278
|
"""Завершить диалог"""
|
|
244
279
|
from ..handlers.handlers import get_global_var
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
280
|
+
|
|
281
|
+
admin_manager = get_global_var("admin_manager")
|
|
282
|
+
conversation_manager = get_global_var("conversation_manager")
|
|
283
|
+
|
|
248
284
|
if not admin_manager.is_admin(message.from_user.id):
|
|
249
285
|
return
|
|
250
|
-
|
|
286
|
+
|
|
251
287
|
try:
|
|
252
288
|
admin_id = message.from_user.id
|
|
253
|
-
|
|
289
|
+
|
|
254
290
|
# Проверяем есть ли активный диалог
|
|
255
|
-
conversation = await conversation_manager.get_admin_active_conversation(
|
|
256
|
-
|
|
291
|
+
conversation = await conversation_manager.get_admin_active_conversation(
|
|
292
|
+
admin_id
|
|
293
|
+
)
|
|
294
|
+
|
|
257
295
|
if conversation:
|
|
258
|
-
user_id = conversation[
|
|
259
|
-
logger.info(
|
|
260
|
-
|
|
296
|
+
user_id = conversation["user_id"]
|
|
297
|
+
logger.info(
|
|
298
|
+
f"🛑 Завершаем диалог админа {admin_id} с пользователем {user_id}"
|
|
299
|
+
)
|
|
300
|
+
|
|
261
301
|
success = await conversation_manager.end_admin_conversation(admin_id)
|
|
262
|
-
|
|
302
|
+
|
|
263
303
|
if success:
|
|
264
304
|
# ✅ ИСПРАВЛЕНИЕ: Правильно переключаем состояние обратно
|
|
265
305
|
await state.set_state(AdminStates.admin_mode)
|
|
266
306
|
await state.update_data(conversation_user_id=None)
|
|
267
|
-
|
|
307
|
+
|
|
268
308
|
await message.answer(f"✅ Диалог с пользователем {user_id} завершен")
|
|
269
|
-
logger.info(
|
|
309
|
+
logger.info("✅ Диалог завершен, админ переключен в admin_mode")
|
|
270
310
|
else:
|
|
271
311
|
await message.answer("❌ Ошибка завершения диалога")
|
|
272
312
|
else:
|
|
273
313
|
await message.answer("❌ Нет активного диалога")
|
|
274
314
|
logger.info(f"❌ У админа {admin_id} нет активного диалога")
|
|
275
|
-
|
|
315
|
+
|
|
276
316
|
except Exception as e:
|
|
277
317
|
logger.error(f"Ошибка завершения диалога: {e}")
|
|
278
318
|
await message.answer("❌ Ошибка завершения диалога")
|
|
279
319
|
|
|
320
|
+
|
|
280
321
|
@admin_router.message(Command(commands=["админ", "admin"]))
|
|
281
322
|
async def admin_toggle_handler(message: Message, state: FSMContext):
|
|
282
323
|
"""Переключение режима админа"""
|
|
283
324
|
from ..handlers.handlers import get_global_var
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
325
|
+
|
|
326
|
+
admin_manager = get_global_var("admin_manager")
|
|
327
|
+
|
|
287
328
|
if not admin_manager.is_admin(message.from_user.id):
|
|
288
329
|
return
|
|
289
|
-
|
|
330
|
+
|
|
290
331
|
new_mode = admin_manager.toggle_admin_mode(message.from_user.id)
|
|
291
|
-
|
|
332
|
+
|
|
292
333
|
if new_mode:
|
|
293
334
|
# Переключились в режим админа
|
|
294
335
|
await admin_start_handler(message, state)
|
|
295
336
|
else:
|
|
296
337
|
# Переключились в режим пользователя
|
|
297
338
|
await state.clear()
|
|
298
|
-
await message.answer(
|
|
339
|
+
await message.answer(
|
|
340
|
+
"🔄 Переключен в режим пользователя\nНапишите /start для начала диалога"
|
|
341
|
+
)
|
|
342
|
+
|
|
299
343
|
|
|
300
344
|
@admin_router.message(Command("debug_chat"))
|
|
301
345
|
async def debug_chat_handler(message: Message, state: FSMContext):
|
|
302
346
|
"""Отладка диалогов админов"""
|
|
303
347
|
from ..handlers.handlers import get_global_var
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
348
|
+
|
|
349
|
+
admin_manager = get_global_var("admin_manager")
|
|
350
|
+
conversation_manager = get_global_var("conversation_manager")
|
|
351
|
+
supabase_client = get_global_var("supabase_client")
|
|
352
|
+
|
|
308
353
|
if not admin_manager.is_admin(message.from_user.id):
|
|
309
354
|
return
|
|
310
|
-
|
|
355
|
+
|
|
311
356
|
parts = message.text.split()
|
|
312
357
|
if len(parts) < 2:
|
|
313
358
|
await message.answer("Использование: /debug_chat USER_ID")
|
|
314
359
|
return
|
|
315
|
-
|
|
360
|
+
|
|
316
361
|
try:
|
|
317
362
|
user_id = int(parts[1])
|
|
318
|
-
|
|
363
|
+
|
|
319
364
|
# 1. Проверяем запись в БД
|
|
320
365
|
conversation = await conversation_manager.is_user_in_admin_chat(user_id)
|
|
321
|
-
|
|
366
|
+
|
|
322
367
|
debug_info = [
|
|
323
368
|
f"🔍 ОТЛАДКА ДИАЛОГА С {user_id}",
|
|
324
369
|
"",
|
|
325
370
|
f"📊 Диалог в БД: {'✅' if conversation else '❌'}",
|
|
326
371
|
]
|
|
327
|
-
|
|
372
|
+
|
|
328
373
|
if conversation:
|
|
329
|
-
debug_info.extend(
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
374
|
+
debug_info.extend(
|
|
375
|
+
[
|
|
376
|
+
f"👑 Админ: {conversation['admin_id']}",
|
|
377
|
+
f"🕐 Начат: {conversation['started_at']}",
|
|
378
|
+
]
|
|
379
|
+
)
|
|
380
|
+
|
|
334
381
|
# 2. Проверяем активную сессию пользователя
|
|
335
382
|
session_info = await supabase_client.get_active_session(user_id)
|
|
336
383
|
debug_info.append(f"🎯 Активная сессия: {'✅' if session_info else '❌'}")
|
|
337
|
-
|
|
384
|
+
|
|
338
385
|
if session_info:
|
|
339
386
|
debug_info.append(f"📝 ID сессии: {session_info['id']}")
|
|
340
|
-
|
|
387
|
+
|
|
341
388
|
# 3. Проверяем состояние пользователя (если он онлайн)
|
|
342
|
-
debug_info.append(
|
|
343
|
-
debug_info.append(
|
|
344
|
-
|
|
389
|
+
debug_info.append("")
|
|
390
|
+
debug_info.append(
|
|
391
|
+
"ℹ️ Для проверки состояния пользователь должен написать что-то"
|
|
392
|
+
)
|
|
393
|
+
|
|
345
394
|
await message.answer("\n".join(debug_info))
|
|
346
|
-
|
|
395
|
+
|
|
347
396
|
except Exception as e:
|
|
348
397
|
await message.answer(f"❌ Ошибка: {e}")
|
|
349
398
|
logger.error(f"Ошибка отладки: {e}")
|
|
350
399
|
|
|
400
|
+
|
|
351
401
|
@admin_router.callback_query(F.data.startswith("admin_"))
|
|
352
402
|
async def admin_callback_handler(callback: CallbackQuery, state: FSMContext):
|
|
353
403
|
"""Обработчик callback кнопок админов"""
|
|
354
404
|
from ..handlers.handlers import get_global_var
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
405
|
+
|
|
406
|
+
admin_manager = get_global_var("admin_manager")
|
|
407
|
+
analytics_manager = get_global_var("analytics_manager")
|
|
408
|
+
conversation_manager = get_global_var("conversation_manager")
|
|
409
|
+
|
|
359
410
|
if not admin_manager.is_admin(callback.from_user.id):
|
|
360
411
|
await callback.answer("Нет доступа")
|
|
361
412
|
return
|
|
362
|
-
|
|
413
|
+
|
|
363
414
|
data = callback.data
|
|
364
|
-
|
|
415
|
+
|
|
365
416
|
try:
|
|
366
417
|
if data == "admin_stats":
|
|
367
418
|
# Показываем статистику
|
|
368
419
|
funnel_stats = await analytics_manager.get_funnel_stats(7)
|
|
369
420
|
events_stats = await analytics_manager.get_events_stats(7)
|
|
370
|
-
|
|
421
|
+
|
|
371
422
|
funnel_text = analytics_manager.format_funnel_stats(funnel_stats)
|
|
372
423
|
events_text = analytics_manager.format_events_stats(events_stats)
|
|
373
|
-
|
|
424
|
+
|
|
374
425
|
await callback.message.answer(f"{funnel_text}\n\n{events_text}")
|
|
375
|
-
|
|
426
|
+
|
|
376
427
|
elif data == "admin_toggle_mode":
|
|
377
428
|
# Переключаем режим
|
|
378
429
|
new_mode = admin_manager.toggle_admin_mode(callback.from_user.id)
|
|
379
430
|
mode_text = "администратор" if new_mode else "пользователь"
|
|
380
431
|
await callback.answer(f"Режим переключен: {mode_text}")
|
|
381
|
-
|
|
432
|
+
|
|
382
433
|
if not new_mode:
|
|
383
434
|
await state.clear()
|
|
384
435
|
await callback.message.answer("🔄 Теперь вы в режиме пользователя")
|
|
@@ -386,80 +437,103 @@ async def admin_callback_handler(callback: CallbackQuery, state: FSMContext):
|
|
|
386
437
|
elif data == "admin_active_chats":
|
|
387
438
|
# Показываем активные диалоги
|
|
388
439
|
conversations = await conversation_manager.get_active_conversations()
|
|
389
|
-
formatted_text = conversation_manager.format_active_conversations(
|
|
390
|
-
|
|
440
|
+
formatted_text = conversation_manager.format_active_conversations(
|
|
441
|
+
conversations
|
|
442
|
+
)
|
|
443
|
+
|
|
391
444
|
# ✅ ИСПРАВЛЕНИЕ: Убираем parse_mode='Markdown'
|
|
392
445
|
await callback.message.answer(formatted_text)
|
|
393
|
-
|
|
446
|
+
|
|
394
447
|
elif data.startswith("admin_history_"):
|
|
395
448
|
user_id = int(data.split("_")[2])
|
|
396
449
|
journey = await analytics_manager.get_user_journey(user_id)
|
|
397
450
|
history_text = analytics_manager.format_user_journey(user_id, journey)
|
|
398
451
|
await callback.message.answer(history_text)
|
|
399
|
-
|
|
452
|
+
|
|
400
453
|
elif data.startswith("admin_end_"):
|
|
401
454
|
user_id = int(data.split("_")[2])
|
|
402
|
-
|
|
455
|
+
|
|
403
456
|
# Проверяем есть ли активный диалог
|
|
404
|
-
conversation = await conversation_manager.get_admin_active_conversation(
|
|
405
|
-
|
|
406
|
-
|
|
457
|
+
conversation = await conversation_manager.get_admin_active_conversation(
|
|
458
|
+
callback.from_user.id
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
if conversation and conversation["user_id"] == user_id:
|
|
407
462
|
await conversation_manager.end_admin_conversation(callback.from_user.id)
|
|
408
|
-
|
|
463
|
+
|
|
409
464
|
# ✅ ИСПРАВЛЕНИЕ: Правильно переключаем состояние
|
|
410
465
|
await state.set_state(AdminStates.admin_mode)
|
|
411
466
|
await state.update_data(conversation_user_id=None)
|
|
412
|
-
|
|
467
|
+
|
|
413
468
|
await callback.answer("Диалог завершен")
|
|
414
|
-
await callback.message.answer(
|
|
415
|
-
|
|
469
|
+
await callback.message.answer(
|
|
470
|
+
f"✅ Диалог с пользователем {user_id} завершен"
|
|
471
|
+
)
|
|
472
|
+
logger.info(
|
|
473
|
+
"✅ Диалог завершен через кнопку, админ переключен в admin_mode"
|
|
474
|
+
)
|
|
416
475
|
else:
|
|
417
476
|
await callback.answer("Диалог не найден")
|
|
418
477
|
|
|
419
478
|
elif data.startswith("admin_chat_"):
|
|
420
479
|
user_id = int(data.split("_")[2])
|
|
421
480
|
admin_id = callback.from_user.id
|
|
422
|
-
|
|
423
|
-
success = await conversation_manager.start_admin_conversation(
|
|
481
|
+
|
|
482
|
+
success = await conversation_manager.start_admin_conversation(
|
|
483
|
+
admin_id, user_id
|
|
484
|
+
)
|
|
424
485
|
if success:
|
|
425
486
|
# ✅ ИСПРАВЛЕНИЕ: Правильно переключаем состояние
|
|
426
487
|
await state.set_state(AdminStates.in_conversation)
|
|
427
488
|
await state.update_data(conversation_user_id=user_id)
|
|
428
|
-
|
|
489
|
+
|
|
429
490
|
await callback.answer("Диалог начат")
|
|
430
|
-
await callback.message.answer(
|
|
431
|
-
|
|
491
|
+
await callback.message.answer(
|
|
492
|
+
f"✅ Диалог с пользователем {user_id} начат"
|
|
493
|
+
)
|
|
494
|
+
logger.info(
|
|
495
|
+
"✅ Диалог начат через кнопку, админ переключен в in_conversation"
|
|
496
|
+
)
|
|
432
497
|
else:
|
|
433
|
-
await callback.answer("Не удалось начать диалог")
|
|
498
|
+
await callback.answer("Не удалось начать диалог")
|
|
434
499
|
|
|
435
500
|
await callback.answer()
|
|
436
|
-
|
|
501
|
+
|
|
437
502
|
except Exception as e:
|
|
438
503
|
logger.error(f"Ошибка обработки callback {data}: {e}")
|
|
439
504
|
await callback.answer("Ошибка")
|
|
440
505
|
|
|
441
|
-
|
|
506
|
+
|
|
507
|
+
@admin_router.message(
|
|
508
|
+
StateFilter(AdminStates.admin_mode, AdminStates.in_conversation),
|
|
509
|
+
F.text,
|
|
510
|
+
lambda message: not message.text.startswith("/"),
|
|
511
|
+
)
|
|
442
512
|
async def admin_message_handler(message: Message, state: FSMContext):
|
|
443
513
|
"""Обработчик сообщений админов"""
|
|
444
514
|
from ..handlers.handlers import get_global_var
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
515
|
+
|
|
516
|
+
admin_manager = get_global_var("admin_manager")
|
|
517
|
+
conversation_manager = get_global_var("conversation_manager")
|
|
518
|
+
|
|
448
519
|
if not admin_manager.is_admin(message.from_user.id):
|
|
449
520
|
return
|
|
450
|
-
|
|
521
|
+
|
|
451
522
|
try:
|
|
452
|
-
logger.info(
|
|
453
|
-
|
|
523
|
+
logger.info(
|
|
524
|
+
f"👑 Получено сообщение от админа {message.from_user.id}: '{message.text}'"
|
|
525
|
+
)
|
|
526
|
+
|
|
454
527
|
# Пытаемся обработать как админское сообщение
|
|
455
528
|
handled = await conversation_manager.route_admin_message(message, state)
|
|
456
|
-
|
|
529
|
+
|
|
457
530
|
if handled:
|
|
458
|
-
logger.info(
|
|
531
|
+
logger.info("✅ Сообщение админа обработано и переслано пользователю")
|
|
459
532
|
else:
|
|
460
533
|
# Не админское сообщение - показываем справку
|
|
461
|
-
logger.info(
|
|
462
|
-
await message.answer(
|
|
534
|
+
logger.info("❌ Сообщение админа не обработано, показываем справку")
|
|
535
|
+
await message.answer(
|
|
536
|
+
"""
|
|
463
537
|
👑 **Режим администратора**
|
|
464
538
|
|
|
465
539
|
Доступные команды:
|
|
@@ -470,8 +544,10 @@ async def admin_message_handler(message: Message, state: FSMContext):
|
|
|
470
544
|
• `/админ` - переключить режим
|
|
471
545
|
|
|
472
546
|
💡 Если вы в диалоге с пользователем, просто напишите сообщение - оно будет переслано пользователю.
|
|
473
|
-
""",
|
|
474
|
-
|
|
547
|
+
""",
|
|
548
|
+
parse_mode="Markdown",
|
|
549
|
+
)
|
|
550
|
+
|
|
475
551
|
except Exception as e:
|
|
476
552
|
logger.error(f"Ошибка обработки сообщения админа: {e}")
|
|
477
|
-
await message.answer("❌ Ошибка обработки команды")
|
|
553
|
+
await message.answer("❌ Ошибка обработки команды")
|