Feat: added notifier
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2025-01-17 13:19:13 +03:00
parent 0d1dd4362d
commit 926774424e
6 changed files with 64 additions and 7 deletions

View File

@@ -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))

View File

@@ -0,0 +1 @@
from nwxraybot.fsm.broadcast import BroadcastStates

View File

@@ -0,0 +1,6 @@
from aiogram.fsm.state import State, StatesGroup
class BroadcastStates(StatesGroup):
waiting_for_message = State()
confirming_message = State()

View File

@@ -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('Рассылка отменена.')

View File

@@ -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:

View File

@@ -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()