From 5d6310e5a472decaf3b491bb990b9bd880db3866 Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Sat, 28 Dec 2024 11:50:40 +0300 Subject: [PATCH 01/12] Feat: started menu command and admin field --- .dockerignore | 1 + main.py | 4 ++-- nwxraybot/bot.py | 6 ++++-- nwxraybot/handlers/__init__.py | 1 + nwxraybot/handlers/menu.py | 18 ++++++++++++++++++ nwxraybot/meta/router.py | 12 +++++------- nwxraybot/models/user.py | 4 +--- run.sh | 7 ------- 8 files changed, 32 insertions(+), 21 deletions(-) create mode 100644 .dockerignore create mode 100644 nwxraybot/handlers/menu.py delete mode 100644 run.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +__pycache__ diff --git a/main.py b/main.py index 8c2a805..0178396 100644 --- a/main.py +++ b/main.py @@ -5,7 +5,7 @@ from sys import exit import uvloop from nwxraybot import NwXrayBot, Settings -from nwxraybot.handlers import HelloHandler +from nwxraybot.handlers import * from nwxraybot.models import User if __name__ == "__main__": @@ -21,5 +21,5 @@ if __name__ == "__main__": # Start bot bot = NwXrayBot(config.bot_token.get_secret_value()) - bot.include_routers(HelloHandler(bot)()) + bot.include_routers(HelloHandler(bot), MenuHandler(bot)) uvloop.run(bot.start(skip_updates=True)) diff --git a/nwxraybot/bot.py b/nwxraybot/bot.py index 6d558fa..173b319 100644 --- a/nwxraybot/bot.py +++ b/nwxraybot/bot.py @@ -1,14 +1,16 @@ from aiogram import Bot, Dispatcher, Router +from .meta import Handler + class NwXrayBot: def __init__(self, token: str) -> None: self.bot = Bot(token=token) self.dp = Dispatcher() - def include_routers(self, *routers: Router): + def include_routers(self, *routers: Handler): for router in routers: - self.dp.include_router(router) + self.dp.include_router(router()) async def start(self, skip_updates: bool = False) -> None: await self.dp.start_polling(self.bot, skip_updates=skip_updates) diff --git a/nwxraybot/handlers/__init__.py b/nwxraybot/handlers/__init__.py index a03cc0c..9a127c1 100644 --- a/nwxraybot/handlers/__init__.py +++ b/nwxraybot/handlers/__init__.py @@ -1 +1,2 @@ from nwxraybot.handlers.hello import HelloHandler +from nwxraybot.handlers.menu import MenuHandler diff --git a/nwxraybot/handlers/menu.py b/nwxraybot/handlers/menu.py new file mode 100644 index 0000000..660881c --- /dev/null +++ b/nwxraybot/handlers/menu.py @@ -0,0 +1,18 @@ +from aiogram import types +from aiogram.enums import ParseMode + +from nwxraybot.meta import Handler +from nwxraybot.models import User + + +class MenuHandler(Handler): + def __init__(self, bot) -> None: + super().__init__(bot) + + @self.router.message() + async def menu(message: types.Message) -> None: + user: User = User.select().where(User.id == message.from_user.id).first() + if user: + await message.reply(f"Ваша ссылка:\n```{user.url}```", parse_mode=ParseMode.MARKDOWN_V2) + else: + await message.reply("Пользователь не найден, обратитесь к админу!") diff --git a/nwxraybot/meta/router.py b/nwxraybot/meta/router.py index 9220bcd..c66f282 100644 --- a/nwxraybot/meta/router.py +++ b/nwxraybot/meta/router.py @@ -1,15 +1,13 @@ -from aiogram import Router - -from nwxraybot import NwXrayBot +from aiogram import Bot, Router class Handler: - bot: NwXrayBot + bot: Bot router: Router - def __init__(self, bot: NwXrayBot) -> None: - assert isinstance(bot, NwXrayBot) - self.bot = bot + def __init__(self, bot) -> None: + assert isinstance(bot.bot, Bot) + self.bot = bot.bot self.router = Router() def __call__(self) -> Router: diff --git a/nwxraybot/models/user.py b/nwxraybot/models/user.py index 67c1f5e..70d2eb1 100644 --- a/nwxraybot/models/user.py +++ b/nwxraybot/models/user.py @@ -12,9 +12,7 @@ class User(Model): name = CharField() url = CharField() time = DateTimeField(null=True) + admin = BooleanField(default=False) class Meta: database = db - - -User.create_table() diff --git a/run.sh b/run.sh deleted file mode 100644 index 75bd83f..0000000 --- a/run.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e - -export $(grep -E -v '^#' .env | xargs) - -docker stack deploy -c docker-compose.yml nwxraybot \ No newline at end of file From e73bc6569b9947c3147a910a7fc59a69e44204e0 Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Thu, 2 Jan 2025 22:00:44 +0300 Subject: [PATCH 02/12] Feat: removed unnecessary bot --- main.py | 3 +-- nwxraybot/handlers/menu.py | 4 ++-- nwxraybot/meta/router.py | 11 +++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/main.py b/main.py index 0178396..3f0bca9 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,3 @@ -import asyncio import logging from sys import exit @@ -21,5 +20,5 @@ if __name__ == "__main__": # Start bot bot = NwXrayBot(config.bot_token.get_secret_value()) - bot.include_routers(HelloHandler(bot), MenuHandler(bot)) + bot.include_routers(HelloHandler(), MenuHandler()) uvloop.run(bot.start(skip_updates=True)) diff --git a/nwxraybot/handlers/menu.py b/nwxraybot/handlers/menu.py index 660881c..a261978 100644 --- a/nwxraybot/handlers/menu.py +++ b/nwxraybot/handlers/menu.py @@ -6,8 +6,8 @@ from nwxraybot.models import User class MenuHandler(Handler): - def __init__(self, bot) -> None: - super().__init__(bot) + def __init__(self) -> None: + super().__init__() @self.router.message() async def menu(message: types.Message) -> None: diff --git a/nwxraybot/meta/router.py b/nwxraybot/meta/router.py index c66f282..9646d7a 100644 --- a/nwxraybot/meta/router.py +++ b/nwxraybot/meta/router.py @@ -1,13 +1,16 @@ +from typing import Optional + from aiogram import Bot, Router class Handler: - bot: Bot + bot: Optional[Bot] router: Router - def __init__(self, bot) -> None: - assert isinstance(bot.bot, Bot) - self.bot = bot.bot + def __init__(self, bot: Optional[Bot] = None) -> None: + if bot: + assert isinstance(bot.bot, Optional[Bot]) + self.bot = bot.bot self.router = Router() def __call__(self) -> Router: From 7093f7452d2c5104eef789c96d44fc188817d256 Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Thu, 2 Jan 2025 22:01:05 +0300 Subject: [PATCH 03/12] Feat: added user middleware --- nwxraybot/bot.py | 3 +++ nwxraybot/middlewares/__init__.py | 1 + nwxraybot/middlewares/user.py | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 nwxraybot/middlewares/__init__.py create mode 100644 nwxraybot/middlewares/user.py diff --git a/nwxraybot/bot.py b/nwxraybot/bot.py index 173b319..8fcc426 100644 --- a/nwxraybot/bot.py +++ b/nwxraybot/bot.py @@ -1,5 +1,7 @@ from aiogram import Bot, Dispatcher, Router +from nwxraybot.middlewares import UserMiddleware + from .meta import Handler @@ -7,6 +9,7 @@ class NwXrayBot: def __init__(self, token: str) -> None: self.bot = Bot(token=token) self.dp = Dispatcher() + self.dp.message.middleware(UserMiddleware()) def include_routers(self, *routers: Handler): for router in routers: diff --git a/nwxraybot/middlewares/__init__.py b/nwxraybot/middlewares/__init__.py new file mode 100644 index 0000000..beb9792 --- /dev/null +++ b/nwxraybot/middlewares/__init__.py @@ -0,0 +1 @@ +from nwxraybot.middlewares.user import UserMiddleware diff --git a/nwxraybot/middlewares/user.py b/nwxraybot/middlewares/user.py new file mode 100644 index 0000000..f6e39e7 --- /dev/null +++ b/nwxraybot/middlewares/user.py @@ -0,0 +1,22 @@ +from typing import Any, Awaitable, Callable, Dict, Optional + +from aiogram import BaseMiddleware +from aiogram.enums import ChatType +from aiogram.types import Message + +from nwxraybot.models import User + + +class UserMiddleware(BaseMiddleware): + def __init__(self) -> None: + pass + + 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: + return None + user: Optional[User] = User.select().where( + User.id == event.from_user.id).first() + if user is None: + await event.answer("Вы не зарегистрированы в системе, обратитесь к админам за доступом!") + return None + return await handler(event, data) From 34308f2cace1743937e284a1934a6d756b3b47f1 Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Thu, 2 Jan 2025 22:01:29 +0300 Subject: [PATCH 04/12] Feat: started main user interface --- nwxraybot/handlers/hello.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/nwxraybot/handlers/hello.py b/nwxraybot/handlers/hello.py index fcf9a4f..05c29bc 100644 --- a/nwxraybot/handlers/hello.py +++ b/nwxraybot/handlers/hello.py @@ -1,13 +1,33 @@ -from aiogram import types +import json +from datetime import datetime + +from aiogram import F, types +from aiogram.enums import ParseMode from aiogram.filters import Command +from aiogram.types import (CallbackQuery, InlineKeyboardButton, + InlineKeyboardMarkup) from nwxraybot.meta import Handler +from nwxraybot.models import User class HelloHandler(Handler): - def __init__(self, bot) -> None: - super().__init__(bot) + def __non_admin_main_menu(self): + markup = [[ + InlineKeyboardButton(text="Обновить данные", + callback_data='update') + ]] + return InlineKeyboardMarkup( + inline_keyboard=markup + ) + + def __init__(self) -> None: + super().__init__() @self.router.message(Command("start")) async def hello(message: types.Message): - await message.reply("Приветствуем в боте NwXray! Здесь вы сможете получить информацию о своем подключении к NwXray") + await message.reply("Приветствуем в боте NwXray! Здесь вы сможете получить информацию о своем подключении к NwXray", reply_markup=self.__non_admin_main_menu()) + + @self.router.callback_query(F.data == 'update') + async def update_data(callback: CallbackQuery): + await callback.message.delete() From 3962c57dde4cda75e036c84a6efa021bcd229208 Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Sun, 5 Jan 2025 20:44:51 +0300 Subject: [PATCH 05/12] Feat: add user command --- main.py | 2 +- nwxraybot/__init__.py | 1 + nwxraybot/bot.py | 2 ++ nwxraybot/handlers/__init__.py | 1 + nwxraybot/handlers/admin.py | 37 +++++++++++++++++++++++++++++++ nwxraybot/handlers/hello.py | 25 ++++++++++++++++----- nwxraybot/handlers/menu.py | 3 ++- nwxraybot/middlewares/__init__.py | 1 + nwxraybot/middlewares/admin.py | 19 ++++++++++++++++ nwxraybot/middlewares/user.py | 4 +++- nwxraybot/models/user.py | 2 ++ nwxraybot/utils.py | 22 ++++++++++++++++++ 12 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 nwxraybot/handlers/admin.py create mode 100644 nwxraybot/middlewares/admin.py create mode 100644 nwxraybot/utils.py diff --git a/main.py b/main.py index 3f0bca9..41445a5 100644 --- a/main.py +++ b/main.py @@ -20,5 +20,5 @@ if __name__ == "__main__": # Start bot bot = NwXrayBot(config.bot_token.get_secret_value()) - bot.include_routers(HelloHandler(), MenuHandler()) + bot.include_routers(HelloHandler(), MenuHandler(), AdminHandler()) uvloop.run(bot.start(skip_updates=True)) diff --git a/nwxraybot/__init__.py b/nwxraybot/__init__.py index 667fdf5..4621279 100644 --- a/nwxraybot/__init__.py +++ b/nwxraybot/__init__.py @@ -1,2 +1,3 @@ from nwxraybot.bot import NwXrayBot from nwxraybot.config import Settings +from nwxraybot.utils import get_code, get_subscription_info diff --git a/nwxraybot/bot.py b/nwxraybot/bot.py index 8fcc426..b24ae5d 100644 --- a/nwxraybot/bot.py +++ b/nwxraybot/bot.py @@ -1,4 +1,5 @@ from aiogram import Bot, Dispatcher, Router +from aiogram.utils.callback_answer import CallbackAnswerMiddleware from nwxraybot.middlewares import UserMiddleware @@ -10,6 +11,7 @@ class NwXrayBot: self.bot = Bot(token=token) self.dp = Dispatcher() self.dp.message.middleware(UserMiddleware()) + self.dp.message.middleware(CallbackAnswerMiddleware()) def include_routers(self, *routers: Handler): for router in routers: diff --git a/nwxraybot/handlers/__init__.py b/nwxraybot/handlers/__init__.py index 9a127c1..0dde1e6 100644 --- a/nwxraybot/handlers/__init__.py +++ b/nwxraybot/handlers/__init__.py @@ -1,2 +1,3 @@ +from nwxraybot.handlers.admin import AdminHandler from nwxraybot.handlers.hello import HelloHandler from nwxraybot.handlers.menu import MenuHandler diff --git a/nwxraybot/handlers/admin.py b/nwxraybot/handlers/admin.py new file mode 100644 index 0000000..70ab2a7 --- /dev/null +++ b/nwxraybot/handlers/admin.py @@ -0,0 +1,37 @@ +import re +from datetime import datetime + +from aiogram.enums import ParseMode +from aiogram.filters import Command +from aiogram.types import Message + +from nwxraybot import get_code +from nwxraybot.meta import Handler +from nwxraybot.middlewares import AdminMiddleware +from nwxraybot.models import User + + +class AdminHandler(Handler): + def __init__(self) -> None: + super().__init__() + + self.router.message.middleware(AdminMiddleware()) + + @self.router.message(Command('adduser')) + async def add_user(message: Message): + mask = r"^(?P[a-zA-Z0-9]+)\s(?P[^\s]+)($|\s(?P[0-9]{2}\.[0-9]{2}\.[0-9]{4})\s(?P