mirror of
https://github.com/civsocit/olgram.git
synced 2023-07-22 01:29:12 +03:00
mailing second iteration
This commit is contained in:
parent
340246b937
commit
696bc5368b
@ -1,10 +1,12 @@
|
|||||||
"""
|
"""
|
||||||
Здесь работа с конкретным ботом
|
Здесь работа с конкретным ботом
|
||||||
"""
|
"""
|
||||||
|
from asyncio import sleep
|
||||||
from aiogram import types
|
from aiogram import types
|
||||||
from aiogram.utils.exceptions import TelegramAPIError, Unauthorized
|
from aiogram.utils.exceptions import TelegramAPIError, Unauthorized, BotKicked, BotBlocked
|
||||||
from aiogram import Bot as AioBot
|
from aiogram import Bot as AioBot
|
||||||
from olgram.models.models import Bot
|
from olgram.models.models import Bot
|
||||||
|
from olgram.utils.mix import send_stored_message
|
||||||
from server.server import unregister_token
|
from server.server import unregister_token
|
||||||
from locales.locale import _
|
from locales.locale import _
|
||||||
|
|
||||||
@ -111,3 +113,22 @@ async def antiflood(bot: Bot, call: types.CallbackQuery):
|
|||||||
async def mailing(bot: Bot, call: types.CallbackQuery):
|
async def mailing(bot: Bot, call: types.CallbackQuery):
|
||||||
bot.enable_mailing = not bot.enable_mailing
|
bot.enable_mailing = not bot.enable_mailing
|
||||||
await bot.save(update_fields=["enable_mailing"])
|
await bot.save(update_fields=["enable_mailing"])
|
||||||
|
|
||||||
|
|
||||||
|
async def go_mailing(bot: Bot, context) -> int:
|
||||||
|
users = await bot.mailing_users
|
||||||
|
a_bot = AioBot(bot.decrypted_token())
|
||||||
|
|
||||||
|
sended = 0
|
||||||
|
|
||||||
|
for user in users:
|
||||||
|
try:
|
||||||
|
await sleep(0.2)
|
||||||
|
await send_stored_message(context, a_bot, user.telegram_id)
|
||||||
|
sended += 1
|
||||||
|
except TelegramAPIError:
|
||||||
|
# TODO:
|
||||||
|
# delete user
|
||||||
|
# check error source, check bot, break if bot deleted
|
||||||
|
continue
|
||||||
|
return sended
|
||||||
|
@ -4,14 +4,14 @@ from aiogram import types, Bot as AioBot
|
|||||||
from olgram.models.models import Bot, User, DefaultAnswer
|
from olgram.models.models import Bot, User, DefaultAnswer
|
||||||
from aiogram.dispatcher import FSMContext
|
from aiogram.dispatcher import FSMContext
|
||||||
from aiogram.utils.callback_data import CallbackData
|
from aiogram.utils.callback_data import CallbackData
|
||||||
|
from datetime import datetime, timedelta
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from olgram.utils.mix import edit_or_create, button_text_limit, wrap
|
from olgram.utils.mix import edit_or_create, button_text_limit, wrap, send_stored_message
|
||||||
from olgram.commands import bot_actions
|
from olgram.commands import bot_actions
|
||||||
from locales.locale import _
|
from locales.locale import _
|
||||||
|
|
||||||
import typing as ty
|
import typing as ty
|
||||||
|
|
||||||
|
|
||||||
menu_callback = CallbackData('menu', 'level', 'bot_id', 'operation', 'chat')
|
menu_callback = CallbackData('menu', 'level', 'bot_id', 'operation', 'chat')
|
||||||
|
|
||||||
empty = "0"
|
empty = "0"
|
||||||
@ -127,6 +127,12 @@ async def send_bot_menu(bot: Bot, call: types.CallbackQuery):
|
|||||||
callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="settings",
|
callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="settings",
|
||||||
chat=empty))
|
chat=empty))
|
||||||
)
|
)
|
||||||
|
if bot.enable_mailing:
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("Рассылка"),
|
||||||
|
callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="go_mailing",
|
||||||
|
chat=empty))
|
||||||
|
)
|
||||||
|
|
||||||
await edit_or_create(call, dedent(_("""
|
await edit_or_create(call, dedent(_("""
|
||||||
Управление ботом @{0}.
|
Управление ботом @{0}.
|
||||||
@ -245,6 +251,30 @@ async def send_bot_text_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] =
|
|||||||
await AioBot.get_current().send_message(chat_id, text, reply_markup=keyboard, parse_mode="HTML")
|
await AioBot.get_current().send_message(chat_id, text, reply_markup=keyboard, parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
|
async def send_bot_mailing_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = None,
|
||||||
|
chat_id: ty.Optional[int] = None):
|
||||||
|
if call:
|
||||||
|
await call.answer()
|
||||||
|
keyboard = types.InlineKeyboardMarkup(row_width=1)
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("<< Отменить рассылку"),
|
||||||
|
callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty))
|
||||||
|
)
|
||||||
|
|
||||||
|
text = dedent(_("""
|
||||||
|
Напишите сообщение, которое нужно разослать всем подписчикам вашего бота @{0}.
|
||||||
|
У сообщения будет до {1} получателей.
|
||||||
|
Учтите, что
|
||||||
|
1. Рассылается только одно сообщение за раз (в т.ч. только одна картинка)
|
||||||
|
2. Когда рассылка запущена, её нельзя отменить
|
||||||
|
"""))
|
||||||
|
text = text.format(bot.name, len(await bot.mailing_users))
|
||||||
|
if call:
|
||||||
|
await edit_or_create(call, text, keyboard, parse_mode="HTML")
|
||||||
|
else:
|
||||||
|
await AioBot.get_current().send_message(chat_id, text, reply_markup=keyboard, parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
async def send_bot_statistic_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = None,
|
async def send_bot_statistic_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = None,
|
||||||
chat_id: ty.Optional[int] = None):
|
chat_id: ty.Optional[int] = None):
|
||||||
if call:
|
if call:
|
||||||
@ -359,6 +389,54 @@ async def start_text_received(message: types.Message, state: FSMContext):
|
|||||||
await send_bot_text_menu(bot, chat_id=message.chat.id)
|
await send_bot_text_menu(bot, chat_id=message.chat.id)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_handler(state="wait_mailing_text",
|
||||||
|
content_types=[types.ContentType.TEXT,
|
||||||
|
types.ContentType.LOCATION,
|
||||||
|
types.ContentType.DOCUMENT,
|
||||||
|
types.ContentType.PHOTO,
|
||||||
|
types.ContentType.AUDIO,
|
||||||
|
types.ContentType.VIDEO]) # TODO: not command
|
||||||
|
async def mailing_text_received(message: types.Message, state: FSMContext):
|
||||||
|
async with state.proxy() as proxy:
|
||||||
|
bot_id = proxy["bot_id"]
|
||||||
|
proxy["mailing_content_type"] = message.content_type
|
||||||
|
|
||||||
|
if message.content_type == types.ContentType.TEXT:
|
||||||
|
proxy["mailing_text"] = message.html_text
|
||||||
|
elif message.content_type == types.ContentType.LOCATION:
|
||||||
|
proxy["mailing_location"] = message.location
|
||||||
|
elif message.content_type == types.ContentType.PHOTO:
|
||||||
|
proxy["mailing_photo"] = message.photo[0].file_id
|
||||||
|
proxy["mailing_caption"] = message.caption
|
||||||
|
elif message.content_type == types.ContentType.DOCUMENT:
|
||||||
|
proxy["mailing_document"] = message.document.file_id
|
||||||
|
proxy["mailing_caption"] = message.caption
|
||||||
|
elif message.content_type == types.ContentType.AUDIO:
|
||||||
|
proxy["mailing_audio"] = message.audio.file_id
|
||||||
|
proxy["mailing_caption"] = message.caption
|
||||||
|
elif message.content_type == types.ContentType.VIDEO:
|
||||||
|
proxy["mailing_video"] = message.video.file_id
|
||||||
|
proxy["mailing_video"] = message.caption
|
||||||
|
|
||||||
|
_message_id = await send_stored_message(proxy, AioBot.get_current(), message.chat.id)
|
||||||
|
|
||||||
|
keyboard = types.InlineKeyboardMarkup(row_width=2)
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("<< Нет, отменить"), # TODO: don't move menu back
|
||||||
|
callback_data=menu_callback.new(level=1, bot_id=bot_id, operation=empty,
|
||||||
|
chat=empty))
|
||||||
|
)
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("Да, начать рассылку"),
|
||||||
|
callback_data=menu_callback.new(level=2, bot_id=bot_id, operation="go_go_mailing",
|
||||||
|
chat=empty))
|
||||||
|
)
|
||||||
|
|
||||||
|
await AioBot.get_current().send_message(message.chat.id, reply_to_message_id=_message_id.message_id,
|
||||||
|
text="Вы уверены, что хотите разослать это сообщение всем пользователям?",
|
||||||
|
reply_markup=keyboard)
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(state="wait_second_text", content_types="text", regexp="^[^/].+") # Not command
|
@dp.message_handler(state="wait_second_text", content_types="text", regexp="^[^/].+") # Not command
|
||||||
async def second_text_received(message: types.Message, state: FSMContext):
|
async def second_text_received(message: types.Message, state: FSMContext):
|
||||||
async with state.proxy() as proxy:
|
async with state.proxy() as proxy:
|
||||||
@ -430,6 +508,20 @@ async def callback(call: types.CallbackQuery, callback_data: dict, state: FSMCon
|
|||||||
return await send_bot_statistic_menu(bot, call)
|
return await send_bot_statistic_menu(bot, call)
|
||||||
if operation == "settings":
|
if operation == "settings":
|
||||||
return await send_bot_settings_menu(bot, call)
|
return await send_bot_settings_menu(bot, call)
|
||||||
|
if operation in ("go_mailing", "go_go_mailing"):
|
||||||
|
if bot.last_mailing_at and bot.last_mailing_at >= datetime.now() - timedelta(minutes=5):
|
||||||
|
return await call.answer(_("Рассылка была совсем недавно, подождите немного"), show_alert=True)
|
||||||
|
if operation == "go_mailing":
|
||||||
|
await state.set_state("wait_mailing_text")
|
||||||
|
async with state.proxy() as proxy:
|
||||||
|
proxy["bot_id"] = bot.id
|
||||||
|
return await send_bot_mailing_menu(bot, call)
|
||||||
|
if operation == "go_go_mailing":
|
||||||
|
async with state.proxy() as proxy:
|
||||||
|
mailing_data = dict(proxy)
|
||||||
|
await state.reset_state() # TODO: double-click protection
|
||||||
|
await call.answer(_("Рассылка запущена"))
|
||||||
|
await bot_actions.go_mailing(bot, mailing_data)
|
||||||
if operation == "text":
|
if operation == "text":
|
||||||
await state.set_state("wait_start_text")
|
await state.set_state("wait_start_text")
|
||||||
async with state.proxy() as proxy:
|
async with state.proxy() as proxy:
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup
|
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup
|
||||||
|
from aiogram import types, Bot as AioBot
|
||||||
from aiogram.utils.exceptions import TelegramAPIError
|
from aiogram.utils.exceptions import TelegramAPIError
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@ -30,3 +31,23 @@ def wrap(data: str, max_len: int) -> str:
|
|||||||
|
|
||||||
def button_text_limit(data: str) -> str:
|
def button_text_limit(data: str) -> str:
|
||||||
return wrap(data, 30)
|
return wrap(data, 30)
|
||||||
|
|
||||||
|
|
||||||
|
async def send_stored_message(storage: dict, bot: AioBot, chat_id: int):
|
||||||
|
content_type = storage["mailing_content_type"]
|
||||||
|
if content_type == types.ContentType.TEXT:
|
||||||
|
return await bot.send_message(chat_id, storage["mailing_text"], parse_mode="HTML")
|
||||||
|
if content_type == types.ContentType.LOCATION:
|
||||||
|
return await bot.send_location(chat_id, storage["mailing_location"][0], storage["mailing_location"][1])
|
||||||
|
if content_type == types.ContentType.AUDIO:
|
||||||
|
return await bot.send_audio(chat_id, audio=storage["mailing_audio"], caption=storage.get("mailing_caption"))
|
||||||
|
if content_type == types.ContentType.DOCUMENT:
|
||||||
|
return await bot.send_document(chat_id, document=storage["mailing_document"],
|
||||||
|
caption=storage.get("mailing_caption"))
|
||||||
|
if content_type == types.ContentType.PHOTO:
|
||||||
|
return await bot.send_photo(chat_id, photo=storage["mailing_photo"],
|
||||||
|
caption=storage.get("mailing_caption"))
|
||||||
|
if content_type == types.ContentType.VIDEO:
|
||||||
|
return await bot.send_video(chat_id, video=storage["mailing_video"],
|
||||||
|
caption=storage.get("mailing_caption"))
|
||||||
|
raise NotImplementedError("Mailing, unknown content type")
|
Loading…
Reference in New Issue
Block a user