📌 snapshot before scheduled posts feature - v1.2 prep
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
1e61eca60c
commit
1825d26230
10 changed files with 430 additions and 11 deletions
BIN
data/broadcast_Gemini_Generated_Image_7v4paw7v4paw7v4p.png
Normal file
BIN
data/broadcast_Gemini_Generated_Image_7v4paw7v4paw7v4p.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
BIN
data/service_images/masters_0d95ea9537e4480b82da5b475c34dfe2.png
Normal file
BIN
data/service_images/masters_0d95ea9537e4480b82da5b475c34dfe2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
BIN
data/service_images/masters_715a0073539c410daae24f5b59c07b74.png
Normal file
BIN
data/service_images/masters_715a0073539c410daae24f5b59c07b74.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
|
|
@ -206,8 +206,7 @@ async def cmd_help(message: Message):
|
||||||
<b>📱 Доступные команды:</b>
|
<b>📱 Доступные команды:</b>
|
||||||
|
|
||||||
<b>Для всех:</b>
|
<b>Для всех:</b>
|
||||||
📞 /телефон — Экстренные службы
|
📞 /телефон — Экстренные службы (включая мастеров)
|
||||||
👷 /мастера — Сантехники, электрики
|
|
||||||
👮 /участковый — Контакты полиции
|
👮 /участковый — Контакты полиции
|
||||||
📜 /правила — Правила чата
|
📜 /правила — Правила чата
|
||||||
❓ /помощь — Эта справка
|
❓ /помощь — Эта справка
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,7 @@ def get_main_menu(verified: bool = False, is_ig: bool = False, is_admin: bool =
|
||||||
builder.row(
|
builder.row(
|
||||||
InlineKeyboardButton(text=f'{level_emoji} 📞 Экстренные телефоны', callback_data='phones'),
|
InlineKeyboardButton(text=f'{level_emoji} 📞 Экстренные телефоны', callback_data='phones'),
|
||||||
)
|
)
|
||||||
builder.row(
|
|
||||||
InlineKeyboardButton(text=f'{level_emoji} 👷 Мастера', callback_data='masters'),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Только для верифицированных
|
# Только для верифицированных
|
||||||
if verified:
|
if verified:
|
||||||
builder.row(
|
builder.row(
|
||||||
|
|
@ -207,7 +204,6 @@ def get_unverified_menu() -> InlineKeyboardMarkup:
|
||||||
InlineKeyboardButton(text=f'{emoji} 📞 Экстренные телефоны', callback_data='phones'),
|
InlineKeyboardButton(text=f'{emoji} 📞 Экстренные телефоны', callback_data='phones'),
|
||||||
)
|
)
|
||||||
builder.row(
|
builder.row(
|
||||||
InlineKeyboardButton(text=f'{emoji} 👷 Мастера', callback_data='masters'),
|
|
||||||
InlineKeyboardButton(text=f'{emoji} 👮 Участковый', callback_data='police'),
|
InlineKeyboardButton(text=f'{emoji} 👮 Участковый', callback_data='police'),
|
||||||
)
|
)
|
||||||
builder.row(
|
builder.row(
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,14 @@ def get_reply_menu() -> ReplyKeyboardMarkup:
|
||||||
Используется редко, в основном для важных действий
|
Используется редко, в основном для важных действий
|
||||||
"""
|
"""
|
||||||
builder = ReplyKeyboardBuilder()
|
builder = ReplyKeyboardBuilder()
|
||||||
|
|
||||||
builder.row(
|
builder.row(
|
||||||
KeyboardButton(text='📞 Телефоны'),
|
KeyboardButton(text='📞 Телефоны'),
|
||||||
KeyboardButton(text='👷 Мастера'),
|
|
||||||
)
|
)
|
||||||
builder.row(
|
builder.row(
|
||||||
KeyboardButton(text='❓ Помощь'),
|
KeyboardButton(text='❓ Помощь'),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Resize keyboard чтобы не занимал много места
|
# Resize keyboard чтобы не занимал много места
|
||||||
return builder.as_markup(resize_keyboard=True, one_time_keyboard=False)
|
return builder.as_markup(resize_keyboard=True, one_time_keyboard=False)
|
||||||
|
|
||||||
|
|
|
||||||
136
send_forum_capabilities.py
Normal file
136
send_forum_capabilities.py
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Отправка подробного отчёта о возможностях рассылки бота
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent
|
||||||
|
sys.path.insert(0, str(BASE_DIR))
|
||||||
|
|
||||||
|
from aiogram import Bot
|
||||||
|
from aiogram.client.default import DefaultBotProperties
|
||||||
|
from aiogram.enums import ParseMode
|
||||||
|
from aiogram.client.session.aiohttp import AiohttpSession
|
||||||
|
|
||||||
|
from config import BOT_TOKEN, ADMIN_USER_ID, get_proxy_url
|
||||||
|
|
||||||
|
async def send_report():
|
||||||
|
"""Отправка отчёта админу"""
|
||||||
|
proxy_url = get_proxy_url()
|
||||||
|
|
||||||
|
if proxy_url:
|
||||||
|
session = AiohttpSession(proxy=proxy_url)
|
||||||
|
bot = Bot(token=BOT_TOKEN, session=session, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
|
||||||
|
else:
|
||||||
|
bot = Bot(token=BOT_TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
|
||||||
|
|
||||||
|
message = """
|
||||||
|
📊 <b>АНАЛИЗ ВОЗМОЖНОСТЕЙ РАССЫЛКИ ДОМОВОГО БОТА</b>
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
🎯 <b>ОТВЕТЫ НА ТВОИ ВОПРОСЫ:</b>
|
||||||
|
|
||||||
|
✅ <b>1. МОЖЕТ ЛИ БОТ ПИСАТЬ В ОТДЕЛЬНУЮ ТЕМУ?</b>
|
||||||
|
|
||||||
|
Да! Бот уже настроен для работы с темами форума Telegram.
|
||||||
|
|
||||||
|
📋 <b>Настроенные темы:</b>
|
||||||
|
├ 1️⃣ Общий чат (ID: 1)
|
||||||
|
├ 2️⃣ Важные объявления (ID: 6258)
|
||||||
|
├ 3️⃣ Ссылки (ID: 6265)
|
||||||
|
├ 4️⃣ Мемы (ID: 6262)
|
||||||
|
├ 5️⃣ Для автовладельцев (ID: 6266)
|
||||||
|
├ 6️⃣ Потеряшки (ID: 6263)
|
||||||
|
├ 7️⃣ Собрания собственников (ID: 6261)
|
||||||
|
├ 8️⃣ Вывоз КГМ (ID: 6264)
|
||||||
|
├ 9️⃣ Переписка с УО (ID: 6260)
|
||||||
|
└ 🔟 Важные телефоны (ID: 6259)
|
||||||
|
|
||||||
|
💡 <b>Как работает:</b>
|
||||||
|
Бот использует параметр message_thread_id при отправке:
|
||||||
|
• send_message(chat_id=CHAT_ID, message_thread_id=TOPIC_ID)
|
||||||
|
• Это позволяет писать в КОНКРЕТНУЮ тему!
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
✅ <b>2. МОЖЕТ ЛИ БОТ ПИСАТЬ В ОБЩИЙ ЧАТ?</b>
|
||||||
|
|
||||||
|
Да! Уже реализовано в нескольких местах:
|
||||||
|
|
||||||
|
📤 <b>Способы рассылки:</b>
|
||||||
|
|
||||||
|
<b>1️⃣ Через админку в Telegram:</b>
|
||||||
|
/admin → кнопка «📤 Рассылка»
|
||||||
|
→ Отправляет в ОБЩУЮ ТЕМУ + всем жильцам в личку
|
||||||
|
|
||||||
|
<b>2️⃣ Через веб-панель (порт 8000):</b>
|
||||||
|
http://localhost:8000/broadcast
|
||||||
|
→ Выбор получателей:
|
||||||
|
• Все верифицированные + чат
|
||||||
|
• Только ИГ
|
||||||
|
• Только чат
|
||||||
|
→ Отправка в ОБЩУЮ ТЕМУ чата
|
||||||
|
|
||||||
|
<b>3️⃣ Через команды:</b>
|
||||||
|
• /ig_broadcast — рассылка только ИГ
|
||||||
|
• Рассылка админа — всем жильцам
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
🎭 <b>ДЛЯ ТВОЕЙ ЗАДАЧИ (ЮМОР ПРО МУСОР + ДОНАТ):</b>
|
||||||
|
|
||||||
|
<b>Вариант 1: Общий чат</b>
|
||||||
|
• Писать в тему «Общий чат» (ID: 1)
|
||||||
|
• Увидят ВСЕ жильцы
|
||||||
|
• Подходит для доната на суд
|
||||||
|
|
||||||
|
<b>Вариант 2: Тема Мемы</b>
|
||||||
|
• Писать в тему «Мемы» (ID: 6262)
|
||||||
|
• Идеально для юмора про мусор!
|
||||||
|
|
||||||
|
<b>Вариант 3: Тема Объявления</b>
|
||||||
|
• Писать в тему «Важные объявления» (ID: 6258)
|
||||||
|
• Для серьёзных постов про донат
|
||||||
|
|
||||||
|
<b>Вариант 4: Тема Собрания</b>
|
||||||
|
• Писать в тему «Собрания собственников» (ID: 6261)
|
||||||
|
• Для важных решений по УК
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
🔧 <b>КАК ЭТО БУДЕТ РАБОТАТЬ:</b>
|
||||||
|
|
||||||
|
Создам скрипт, который:
|
||||||
|
✅ Пишет пост в КОНКРЕТНУЮ тему
|
||||||
|
✅ Использует прокси (VPN Германия)
|
||||||
|
✅ Форматирует текст с emoji
|
||||||
|
✅ Может добавить картинку
|
||||||
|
✅ Постит серию постов с интервалом
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
🚀 <b>ГОТОВО К РАБОТЕ!</b>
|
||||||
|
|
||||||
|
Бот уже имеет ВСЕ необходимые функции:
|
||||||
|
✅ Отправка в конкретную тему
|
||||||
|
✅ Отправка в общий чат
|
||||||
|
✅ Рассылка всем жильцам
|
||||||
|
✅ Поддержка фото
|
||||||
|
✅ Работа через прокси
|
||||||
|
|
||||||
|
<i>Нужно только создать скрипт для постинга серии сообщений!</i>
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
await bot.send_message(ADMIN_USER_ID, message)
|
||||||
|
print("✅ Подробный отчёт отправлен!")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Ошибка: {e}")
|
||||||
|
finally:
|
||||||
|
await bot.session.close()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(send_report())
|
||||||
204
send_scheduler_analysis.py
Normal file
204
send_scheduler_analysis.py
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Отправка анализа возможности планировщика постов
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent
|
||||||
|
sys.path.insert(0, str(BASE_DIR))
|
||||||
|
|
||||||
|
from aiogram import Bot
|
||||||
|
from aiogram.client.default import DefaultBotProperties
|
||||||
|
from aiogram.enums import ParseMode
|
||||||
|
from aiogram.client.session.aiohttp import AiohttpSession
|
||||||
|
|
||||||
|
from config import BOT_TOKEN, ADMIN_USER_ID, get_proxy_url
|
||||||
|
|
||||||
|
async def send_analysis():
|
||||||
|
"""Отправка анализа планировщика постов"""
|
||||||
|
proxy_url = get_proxy_url()
|
||||||
|
|
||||||
|
if proxy_url:
|
||||||
|
session = AiohttpSession(proxy=proxy_url)
|
||||||
|
bot = Bot(token=BOT_TOKEN, session=session, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
|
||||||
|
else:
|
||||||
|
bot = Bot(token=BOT_TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
|
||||||
|
|
||||||
|
message = """
|
||||||
|
📅 <b>АНАЛИЗ: ПЛАНИРОВЩИК ПОСТОВ ДЛЯ ВЕБ-ПАНЕЛИ</b>
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
🎯 <b>МОЖЕМ ЛИ РЕАЛИЗОВАТЬ?</b>
|
||||||
|
|
||||||
|
✅ <b>ДА! Полностью реализуемо!</b>
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
📋 <b>ЧТО УЖЕ ЕСТЬ В КОДЕ:</b>
|
||||||
|
|
||||||
|
✅ <b>1. Планировщик (Scheduler)</b>
|
||||||
|
• Файл: services/scheduler.py
|
||||||
|
• Использует APScheduler
|
||||||
|
• Уже работает с cron-задачами
|
||||||
|
• Запускается при старте бота
|
||||||
|
|
||||||
|
✅ <b>2. Веб-панель (FastAPI)</b>
|
||||||
|
• Файл: web/app.py (911 строк)
|
||||||
|
• Есть страница /broadcast
|
||||||
|
• Уже умеет: текст + фото
|
||||||
|
• Уже есть выбор получателей
|
||||||
|
|
||||||
|
✅ <b>3. База данных (SQLAlchemy)</b>
|
||||||
|
• Есть модели для всего
|
||||||
|
• Нужно добавить: ScheduledPost
|
||||||
|
• Хранить: текст, фото, тему, время
|
||||||
|
|
||||||
|
✅ <b>4. Темы форума</b>
|
||||||
|
• Настроены 10 тем
|
||||||
|
• message_thread_id работает
|
||||||
|
• config.get_topic_id('topic_name')
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
🔧 <b>ЧТО НУЖНО ДОБАВИТЬ:</b>
|
||||||
|
|
||||||
|
<b>1️⃣ Новая модель в БД:</b>
|
||||||
|
ScheduledPost
|
||||||
|
• id
|
||||||
|
• text (текст поста)
|
||||||
|
• photo_file_id (опционально)
|
||||||
|
• topic_id (тема: 1, 6258, 6262...)
|
||||||
|
• topic_name ('general', 'memes'...)
|
||||||
|
• scheduled_time (когда отправить)
|
||||||
|
• status ('pending', 'sent', 'failed')
|
||||||
|
• created_at (когда создан)
|
||||||
|
• error_message (если ошибка)
|
||||||
|
|
||||||
|
<b>2️⃣ Новая страница в веб-панели:</b>
|
||||||
|
/scheduled_posts
|
||||||
|
• Текстовое поле (с HTML поддержкой)
|
||||||
|
• Загрузка фото
|
||||||
|
• Выпадающий список тем
|
||||||
|
• Датапикер (календарь)
|
||||||
|
• Время (часы:минуты)
|
||||||
|
• Кнопка "Запланировать"
|
||||||
|
• Таблица запланированных
|
||||||
|
• Кнопки: удалить, редактировать
|
||||||
|
|
||||||
|
<b>3️⃣ API endpoints:</b>
|
||||||
|
• GET /scheduled_posts - страница
|
||||||
|
• POST /api/scheduled_posts/create
|
||||||
|
• POST /api/scheduled_posts/cancel
|
||||||
|
• GET /api/scheduled_posts/list
|
||||||
|
• DELETE /api/scheduled_posts/{id}
|
||||||
|
|
||||||
|
<b>4️⃣ Фоновая задача в Scheduler:</b>
|
||||||
|
• Проверка каждую минуту
|
||||||
|
• SELECT * FROM scheduled_posts
|
||||||
|
WHERE scheduled_time <= NOW()
|
||||||
|
AND status = 'pending'
|
||||||
|
• Отправка в нужную тему
|
||||||
|
• Обновление status = 'sent'
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
🎨 <b>КАК БУДЕТ ВЫГЛЯДЕТЬ:</b>
|
||||||
|
|
||||||
|
<b>Форма создания поста:</b>
|
||||||
|
|
||||||
|
📝 Текст: [большое поле]
|
||||||
|
📷 Фото: [выбрать файл]
|
||||||
|
📂 Тема: [выпадающий список ▼]
|
||||||
|
• Общий чат
|
||||||
|
• Мемы
|
||||||
|
• Объявления
|
||||||
|
• Собрания
|
||||||
|
• ...
|
||||||
|
📅 Дата: [🗓️ 2026-04-07]
|
||||||
|
⏰ Время: [14:30]
|
||||||
|
|
||||||
|
[✅ Запланировать пост]
|
||||||
|
|
||||||
|
<b>Таблица запланированных:</b>
|
||||||
|
|
||||||
|
| # | Тема | Когда | Статус | Действия |
|
||||||
|
|---|------|-------|--------|----------|
|
||||||
|
| 1 | Мемы | 07.04 10:00 | ⏳ | ❌ ✏️ |
|
||||||
|
| 2 | Общий | 08.04 15:00 | ⏳ | ❌ ✏️ |
|
||||||
|
| 3 | КГМ | 09.04 09:00 | ✅ | - |
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
🛡️ <b>БЕЗОПАСНОСТЬ (НЕ ИСПОРТИМ ТЕКУЩЕЕ):</b>
|
||||||
|
|
||||||
|
✅ <b>Изолированные изменения:</b>
|
||||||
|
• Новая модель - отдельная таблица
|
||||||
|
• Новый endpoint - новый URL
|
||||||
|
• Новая страница - новый файл HTML
|
||||||
|
• Новая задача в scheduler - отдельный job
|
||||||
|
|
||||||
|
✅ <b>Миграция БД:</b>
|
||||||
|
• ALTER TABLE (добавление таблицы)
|
||||||
|
• Не меняем существующие таблицы
|
||||||
|
• Без риска для текущих данных
|
||||||
|
|
||||||
|
✅ <b>Тестирование:</b>
|
||||||
|
• Можно тестировать на одном посте
|
||||||
|
• Отмена без последствий
|
||||||
|
• Логи всех действий
|
||||||
|
|
||||||
|
✅ <b>Откат:</b>
|
||||||
|
• Если что-то не так - удаляем таблицу
|
||||||
|
• Новый код не трогает старый
|
||||||
|
• Старый функционал не изменится
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
🚀 <b>ПЛАН РЕАЛИЗАЦИИ:</b>
|
||||||
|
|
||||||
|
<b>Шаг 1:</b> Добавить модель ScheduledPost в БД
|
||||||
|
<b>Шаг 2:</b> Создать страницу /scheduled_posts
|
||||||
|
<b>Шаг 3:</b> Создать API endpoints
|
||||||
|
<b>Шаг 4:</b> Добавить задачу в Scheduler
|
||||||
|
<b>Шаг 5:</b> Тестирование на 1-2 постах
|
||||||
|
<b>Шаг 6:</b> Коммит в Gitea
|
||||||
|
|
||||||
|
<b>⚠️ ВАЖНО:</b>
|
||||||
|
Ни один существующий файл НЕ будет изменён критично!
|
||||||
|
Только добавления нового кода.
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
💡 <b>СЦЕНАРИЙ ИСПОЛЬЗОВАНИЯ:</b>
|
||||||
|
|
||||||
|
1. Заходишь в веб-панель (порт 8000)
|
||||||
|
2. Кликаешь "📅 Запланированные посты"
|
||||||
|
3. Заполняешь форму:
|
||||||
|
• Текст про юмор/мусор
|
||||||
|
• Прикладываешь картинку
|
||||||
|
• Выбираешь тему "Мемы"
|
||||||
|
• Ставишь: 07.04.2026 10:00
|
||||||
|
4. Жмёшь "Запланировать"
|
||||||
|
5. Повторяешь для 5-6 постов
|
||||||
|
6. Бот сам отправит их по расписанию!
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
✅ <b>ГОТОВО К РЕАЛИЗАЦИИ!</b>
|
||||||
|
|
||||||
|
<i>Можем начинать? Никакой текущий функционал не пострадает!</i>
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
await bot.send_message(ADMIN_USER_ID, message)
|
||||||
|
print("✅ Анализ планировщика отправлен!")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Ошибка: {e}")
|
||||||
|
finally:
|
||||||
|
await bot.session.close()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(send_analysis())
|
||||||
68
send_status_notification.py
Normal file
68
send_status_notification.py
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Отправка уведомления через Домовой Бот
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Добавляем путь к проекту
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent
|
||||||
|
sys.path.insert(0, str(BASE_DIR))
|
||||||
|
|
||||||
|
from aiogram import Bot
|
||||||
|
from aiogram.client.default import DefaultBotProperties
|
||||||
|
from aiogram.enums import ParseMode
|
||||||
|
from aiogram.client.session.aiohttp import AiohttpSession
|
||||||
|
|
||||||
|
from config import BOT_TOKEN, ADMIN_USER_ID, get_proxy_url
|
||||||
|
|
||||||
|
async def send_notification():
|
||||||
|
"""Отправка уведомления админу"""
|
||||||
|
proxy_url = get_proxy_url()
|
||||||
|
|
||||||
|
if proxy_url:
|
||||||
|
session = AiohttpSession(proxy=proxy_url)
|
||||||
|
bot = Bot(token=BOT_TOKEN, session=session, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
|
||||||
|
else:
|
||||||
|
bot = Bot(token=BOT_TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
|
||||||
|
|
||||||
|
message = """
|
||||||
|
✅ <b>Домовой Бот — Статус системы</b>
|
||||||
|
|
||||||
|
🟢 <b>VPN (Xray):</b> РАБОТАЕТ
|
||||||
|
├ Сервер: 🇩🇪 Германия (138.124.228.10)
|
||||||
|
├ Протокол: VLESS + Reality
|
||||||
|
├ SOCKS5: 127.0.0.1:10808 ✅
|
||||||
|
└ HTTP: 127.0.0.1:10809 ✅
|
||||||
|
|
||||||
|
🤖 <b>Бот:</b> ГОТОВ К РАБОТЕ
|
||||||
|
├ Версия: v2.1
|
||||||
|
├ Прокси: подключён
|
||||||
|
└ Веб-интерфейс: порт 8000
|
||||||
|
|
||||||
|
📋 <b>Доступные функции:</b>
|
||||||
|
• 📊 Управление жильцами
|
||||||
|
• 📢 Доска объявлений
|
||||||
|
• 📅 Календарь событий
|
||||||
|
• 📝 Опросы и голосования
|
||||||
|
• 🏆 Рейтинг и достижения
|
||||||
|
• 🔔 Напоминания о платежах
|
||||||
|
• 🛡️ Анти-спам система
|
||||||
|
• 📱 Веб-админка
|
||||||
|
|
||||||
|
🎯 <b>Готов к публикации постов!</b>
|
||||||
|
|
||||||
|
<i>Система работает стабильно ✓</i>
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
await bot.send_message(ADMIN_USER_ID, message)
|
||||||
|
print("✅ Уведомление отправлено!")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Ошибка: {e}")
|
||||||
|
finally:
|
||||||
|
await session.close() if proxy_url else await bot.session.close()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(send_notification())
|
||||||
19
web/app.py
19
web/app.py
|
|
@ -10,6 +10,7 @@ from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
|
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy import select, func, update, delete, desc
|
from sqlalchemy import select, func, update, delete, desc
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
@ -18,13 +19,23 @@ import config
|
||||||
|
|
||||||
from database.db import AsyncSessionLocal
|
from database.db import AsyncSessionLocal
|
||||||
from database.models import (
|
from database.models import (
|
||||||
User, Message, Poll, Ad, PaymentReminder, Schedule,
|
User, Message, Poll, Ad, PaymentReminder, Schedule,
|
||||||
VerificationRequest, Service, Announcement, Event
|
VerificationRequest, Service, Announcement, Event
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
app = FastAPI(title="Домовой Бот - MEGA Admin Panel", version="3.0.0")
|
app = FastAPI(title="Домовой Бот - MEGA Admin Panel", version="3.0.0")
|
||||||
|
|
||||||
|
# Добавляем CORS middleware
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=["*"], # Разрешаем все origins (для локального использования)
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
templates = Jinja2Templates(directory="web/templates")
|
templates = Jinja2Templates(directory="web/templates")
|
||||||
app.mount("/static", StaticFiles(directory="web/static"), name="static")
|
app.mount("/static", StaticFiles(directory="web/static"), name="static")
|
||||||
app.mount("/static/service_images", StaticFiles(directory="data/service_images"), name="service_images")
|
app.mount("/static/service_images", StaticFiles(directory="data/service_images"), name="service_images")
|
||||||
|
|
@ -538,6 +549,9 @@ async def api_send_broadcast(
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from services.initiative_group import InitiativeGroupService
|
from services.initiative_group import InitiativeGroupService
|
||||||
|
|
||||||
|
# Логируем начало рассылки
|
||||||
|
logger.info(f"📬 НАЧАЛО РАССЫЛКИ: получатели={recipients}, текст_len={len(text) if text else 0}")
|
||||||
|
|
||||||
photo_id = None
|
photo_id = None
|
||||||
|
|
||||||
# Если есть картинка — загружаем
|
# Если есть картинка — загружаем
|
||||||
|
|
@ -650,6 +664,9 @@ async def api_send_broadcast(
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Ошибка логирования рассылки: {e}")
|
logger.error(f"Ошибка логирования рассылки: {e}")
|
||||||
|
|
||||||
|
# Логируем результат
|
||||||
|
logger.info(f"✅ РАССЫЛКА ЗАВЕРШЕНА: успешно={success_count}, ошибок={error_count}, получатели={recipients}")
|
||||||
|
|
||||||
return JSONResponse({
|
return JSONResponse({
|
||||||
"success": True,
|
"success": True,
|
||||||
"message": f"Отправлено: {success_count} (в чат: {'✅' if chat_sent else '❌'})",
|
"message": f"Отправлено: {success_count} (в чат: {'✅' if chat_sent else '❌'})",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue