📸 РАССЫЛКА С КАРТИНКАМИ

 Реализовано:
- Рассылка текста (работает)
- Рассылка картинки с подписью (НОВОЕ!)
- Отправка в общий чат + в личку каждому
- Отчёт админу об успешной рассылке

🎯 Как использовать:
1. /admin → 📤 Рассылка
2. Отправить текст ИЛИ картинку с подписью
3. Бот разошлёт всем верифицированным:
   - В общий чат
   - В личку каждому

📝 Для срочного объявления:
1. Напиши боту в личку
2. /admin
3. 📤 Рассылка
4. Отправь картинку + текст
5. Готово!

💡 Важно:
- Рассылка только верифицированным
- Картинка сжимается Telegram
- Подпись до 1024 символов

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Admin 2026-03-04 18:32:09 +00:00
parent d81ee6d238
commit b4c06d09a3

View file

@ -32,6 +32,7 @@ router = Router()
class BroadcastState(StatesGroup): class BroadcastState(StatesGroup):
waiting_for_message = State() waiting_for_message = State()
waiting_for_photo = State() # Состояние для ожидания картинки
# ============================================================================= # =============================================================================
@ -308,7 +309,8 @@ async def cb_admin_broadcast(callback: CallbackQuery):
await callback.message.answer( await callback.message.answer(
'📤 <b>Рассылка</b>\n\n' '📤 <b>Рассылка</b>\n\n'
'Теперь отправьте сообщение, которое нужно разослать всем жильцам.\n\n' '<b>Вариант 1:</b> Отправьте текст\n'
'<b>Вариант 2:</b> Отправьте картинку с подписью\n\n'
'Или отмените командой /cancel', 'Или отмените командой /cancel',
parse_mode='HTML' parse_mode='HTML'
) )
@ -324,8 +326,28 @@ async def cb_admin_broadcast(callback: CallbackQuery):
@router.message(StateFilter(BroadcastState.waiting_for_message)) @router.message(StateFilter(BroadcastState.waiting_for_message))
@admin_only @admin_only
async def process_broadcast_message(message: Message): async def process_broadcast_message(message: Message):
"""Обработка сообщения для рассылки""" """Обработка сообщения для рассылки (текст или фото)"""
broadcast_text = message.text
# Проверяем что прислал админ
if message.photo:
# Это картинка с подписью
photo_id = message.photo[-1].file_id # Берём наибольшее качество
caption = message.caption or ''
# Отключаем состояние
await message.bot.delete_state(message.from_user.id)
# Подтверждаем
await message.answer(
f'📤 <b>Начинаю рассылку с картинкой...</b>\n\n'
f'Текст: {caption[:100]}...' if caption else 'Без текста'
)
# Рассылаем
await send_broadcast_with_photo(message.bot, photo_id, caption)
else:
# Это текст
broadcast_text = message.text or ''
# Отключаем состояние # Отключаем состояние
await message.bot.delete_state(message.from_user.id) await message.bot.delete_state(message.from_user.id)
@ -336,12 +358,18 @@ async def process_broadcast_message(message: Message):
f'Сообщение: {broadcast_text[:100]}...' f'Сообщение: {broadcast_text[:100]}...'
) )
# Рассылаем текст
await send_broadcast_text(message.bot, broadcast_text)
async def send_broadcast_text(bot, text: str):
"""Рассылка текста"""
# Отправляем в чат дома # Отправляем в чат дома
try: try:
await message.bot.send_message( await bot.send_message(
config.ADMIN_CHAT_ID, config.ADMIN_CHAT_ID,
f'📢 <b>Объявление от администрации</b>\n\n' f'📢 <b>Объявление от администрации</b>\n\n'
f'{broadcast_text}', f'{text}',
parse_mode='HTML' parse_mode='HTML'
) )
logger.info(f'Рассылка отправлена в чат {config.ADMIN_CHAT_ID}') logger.info(f'Рассылка отправлена в чат {config.ADMIN_CHAT_ID}')
@ -359,10 +387,10 @@ async def process_broadcast_message(message: Message):
for user in users: for user in users:
try: try:
await message.bot.send_message( await bot.send_message(
user.user_id, user.user_id,
f'📢 <b>Объявление от администрации</b>\n\n' f'📢 <b>Объявление от администрации</b>\n\n'
f'{broadcast_text}', f'{text}',
parse_mode='HTML' parse_mode='HTML'
) )
success_count += 1 success_count += 1
@ -371,7 +399,8 @@ async def process_broadcast_message(message: Message):
error_count += 1 error_count += 1
# Отчёт админу # Отчёт админу
await message.answer( await bot.send_message(
config.ADMIN_USER_ID,
f'✅ <b>Рассылка завершена!</b>\n\n' f'✅ <b>Рассылка завершена!</b>\n\n'
f'Успешно: {success_count}\n' f'Успешно: {success_count}\n'
f'Ошибок: {error_count}\n' f'Ошибок: {error_count}\n'
@ -380,6 +409,53 @@ async def process_broadcast_message(message: Message):
) )
async def send_broadcast_with_photo(bot, photo_id: str, caption: str):
"""Рассылка картинки с подписью"""
# Отправляем в чат дома
try:
await bot.send_photo(
config.ADMIN_CHAT_ID,
photo_id,
caption=f'📢 <b>Объявление от администрации</b>\n\n{caption}',
parse_mode='HTML'
)
logger.info(f'Рассылка с фото отправлена в чат {config.ADMIN_CHAT_ID}')
except Exception as e:
logger.error(f'Ошибка отправки фото в чат: {e}')
# Рассылаем всем верифицированным в личку
async with AsyncSessionLocal() as session:
stmt = select(User).where(User.verified == True)
result = await session.execute(stmt)
users = list(result.scalars().all())
success_count = 0
error_count = 0
for user in users:
try:
await bot.send_photo(
user.user_id,
photo_id,
caption=f'📢 <b>Объявление от администрации</b>\n\n{caption}',
parse_mode='HTML'
)
success_count += 1
except Exception as e:
logger.error(f'Не удалось отправить фото пользователю {user.user_id}: {e}')
error_count += 1
# Отчёт админу
await bot.send_message(
config.ADMIN_USER_ID,
f'✅ <b>Рассылка с фото завершена!</b>\n\n'
f'Успешно: {success_count}\n'
f'Ошибок: {error_count}\n'
f'В чат: ✅',
parse_mode='HTML'
)
# ============================================================================= # =============================================================================
# СНЯТИЕ ВЕРИФИКАЦИИ (БЫСТРОЕ) # СНЯТИЕ ВЕРИФИКАЦИИ (БЫСТРОЕ)
# ============================================================================= # =============================================================================