Feat: added notifier
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
2
main.py
2
main.py
@@ -25,5 +25,5 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
# Start bot
|
# Start bot
|
||||||
bot = NwXrayBot(config.bot_token.get_secret_value())
|
bot = NwXrayBot(config.bot_token.get_secret_value())
|
||||||
bot.include_routers(HelloHandler(), MenuHandler(), AdminHandler())
|
bot.include_routers(HelloHandler(), MenuHandler(), AdminHandler(bot.bot))
|
||||||
loop.run_until_complete(bot.start(skip_updates=True))
|
loop.run_until_complete(bot.start(skip_updates=True))
|
||||||
|
|||||||
1
nwxraybot/fsm/__init__.py
Normal file
1
nwxraybot/fsm/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from nwxraybot.fsm.broadcast import BroadcastStates
|
||||||
6
nwxraybot/fsm/broadcast.py
Normal file
6
nwxraybot/fsm/broadcast.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from aiogram.fsm.state import State, StatesGroup
|
||||||
|
|
||||||
|
|
||||||
|
class BroadcastStates(StatesGroup):
|
||||||
|
waiting_for_message = State()
|
||||||
|
confirming_message = State()
|
||||||
@@ -1,19 +1,26 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from aiogram import Bot, F
|
||||||
from aiogram.enums import ParseMode
|
from aiogram.enums import ParseMode
|
||||||
from aiogram.filters import Command
|
from aiogram.filters import Command
|
||||||
from aiogram.types import Message
|
from aiogram.fsm.context import FSMContext
|
||||||
|
from aiogram.types import (CallbackQuery, InlineKeyboardButton,
|
||||||
|
InlineKeyboardMarkup, Message)
|
||||||
|
|
||||||
from nwxraybot import get_code
|
from nwxraybot import get_code
|
||||||
|
from nwxraybot.fsm import BroadcastStates
|
||||||
from nwxraybot.meta import Handler
|
from nwxraybot.meta import Handler
|
||||||
from nwxraybot.middlewares import AdminMiddleware
|
from nwxraybot.middlewares import AdminMiddleware
|
||||||
from nwxraybot.models import User
|
from nwxraybot.models import User
|
||||||
|
|
||||||
|
|
||||||
class AdminHandler(Handler):
|
class AdminHandler(Handler):
|
||||||
def __init__(self) -> None:
|
def __init__(self, bot: Optional[Bot] = None) -> None:
|
||||||
super().__init__()
|
super().__init__(bot)
|
||||||
|
|
||||||
self.router.message.middleware(AdminMiddleware())
|
self.router.message.middleware(AdminMiddleware())
|
||||||
|
|
||||||
@@ -51,3 +58,46 @@ class AdminHandler(Handler):
|
|||||||
User.name == user_dict['name'])
|
User.name == user_dict['name'])
|
||||||
query.execute()
|
query.execute()
|
||||||
await message.answer('Информация о пользователе обновлена.')
|
await message.answer('Информация о пользователе обновлена.')
|
||||||
|
|
||||||
|
@self.router.message(Command('broadcast'))
|
||||||
|
async def start_broadcast(message: Message, state: FSMContext):
|
||||||
|
await message.answer('Отправьте для рассылки')
|
||||||
|
await state.set_state(BroadcastStates.waiting_for_message)
|
||||||
|
|
||||||
|
@self.router.message(BroadcastStates.waiting_for_message)
|
||||||
|
async def broadcast_message(message: Message, state: FSMContext):
|
||||||
|
if message.media_group_id is not None:
|
||||||
|
await state.clear()
|
||||||
|
await message.answer('Пожалуйста, не отправляйте сообщение с несколькими изображениями.')
|
||||||
|
return
|
||||||
|
await state.set_state(BroadcastStates.confirming_message)
|
||||||
|
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||||
|
[InlineKeyboardButton(
|
||||||
|
text="Подтвердить", callback_data='confirm_broadcast')],
|
||||||
|
[InlineKeyboardButton(
|
||||||
|
text="Отменить", callback_data='cancel_broadcast')]
|
||||||
|
])
|
||||||
|
await state.update_data(message_id=message.message_id)
|
||||||
|
await message.answer("Подтвердите отправку сообщения", reply_markup=keyboard)
|
||||||
|
|
||||||
|
@self.router.callback_query(F.data == 'confirm_broadcast', BroadcastStates.confirming_message)
|
||||||
|
async def confirm_broadcast(callback: CallbackQuery, state: FSMContext):
|
||||||
|
await callback.answer()
|
||||||
|
data = await state.get_data()
|
||||||
|
message_id = data.get('message_id')
|
||||||
|
users = User.select().where((User.telegram_id != None))
|
||||||
|
semaphore = asyncio.Semaphore(10)
|
||||||
|
for user in users:
|
||||||
|
async with semaphore:
|
||||||
|
try:
|
||||||
|
await self.bot.copy_message(user.telegram_id, callback.from_user.id, message_id)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error while broadcasting message to user {
|
||||||
|
user.telegram_id}: {e}")
|
||||||
|
await state.clear()
|
||||||
|
|
||||||
|
@self.router.callback_query(F.data == 'cancel_broadcast', BroadcastStates.confirming_message)
|
||||||
|
async def cancel_broadcast(callback: CallbackQuery, state: FSMContext):
|
||||||
|
await callback.answer()
|
||||||
|
await state.clear()
|
||||||
|
await callback.message.answer('Рассылка отменена.')
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ class Handler:
|
|||||||
|
|
||||||
def __init__(self, bot: Optional[Bot] = None) -> None:
|
def __init__(self, bot: Optional[Bot] = None) -> None:
|
||||||
if bot:
|
if bot:
|
||||||
assert isinstance(bot.bot, Optional[Bot])
|
assert isinstance(bot, Bot)
|
||||||
self.bot = bot.bot
|
self.bot = bot
|
||||||
self.router = Router()
|
self.router = Router()
|
||||||
|
|
||||||
def __call__(self) -> Router:
|
def __call__(self) -> Router:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class UserMiddleware(BaseMiddleware):
|
|||||||
async def __call__(self, handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]], event: Message, data: Dict[str, Any]) -> Any:
|
async def __call__(self, handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]], event: Message, data: Dict[str, Any]) -> Any:
|
||||||
if event.chat.type != ChatType.PRIVATE:
|
if event.chat.type != ChatType.PRIVATE:
|
||||||
return None
|
return None
|
||||||
if event.text.startswith('/start'):
|
if event.text and event.text.startswith('/start'):
|
||||||
return await handler(event, data)
|
return await handler(event, data)
|
||||||
user: Optional[User] = User.select().where(
|
user: Optional[User] = User.select().where(
|
||||||
User.telegram_id == event.from_user.id).first()
|
User.telegram_id == event.from_user.id).first()
|
||||||
|
|||||||
Reference in New Issue
Block a user