├── .gitattributes ├── .gitignore ├── README.md ├── bot.py ├── requirements.txt ├── systemd └── tgbot.service └── tgbot ├── config.py ├── filters ├── __init__.py └── admin_filter.py ├── handlers ├── __init__.py ├── admin.py ├── spam_command.py └── user.py ├── middlewares ├── __init__.py └── antiflood_middleware.py ├── models ├── __init__.py └── users_model.py ├── states ├── __init__.py └── register_state.py └── utils ├── __init__.py └── database.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # asynctelebot_template 2 | Template for asynchronous implementation of telebot. 3 | 4 | You are welcome to make pull requests or open issues to improve template. 5 | 6 | Note that this template requires pyTelegramBotAPI version higher or equal to 4.4.0. You can install it from github because it is not released yet. 7 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | # filters 4 | from tgbot.filters.admin_filter import AdminFilter 5 | 6 | # handlers 7 | from tgbot.handlers.admin import admin_user 8 | from tgbot.handlers.spam_command import anti_spam 9 | from tgbot.handlers.user import any_user 10 | 11 | # middlewares 12 | from tgbot.middlewares.antiflood_middleware import AntiFloodMiddleware 13 | 14 | # states 15 | from tgbot.states.register_state import Register 16 | 17 | # utils 18 | from tgbot.utils.database import Database 19 | 20 | # telebot 21 | from telebot.async_telebot import AsyncTeleBot 22 | 23 | # config 24 | from tgbot import config 25 | 26 | db = Database() 27 | 28 | 29 | bot = AsyncTeleBot(config.TOKEN) 30 | 31 | def register_handlers(): 32 | bot.register_message_handler(admin_user, commands=['start'], admin=True, pass_bot=True) 33 | bot.register_message_handler(any_user, commands=['start'], admin=False, pass_bot=True) 34 | bot.register_message_handler(anti_spam, commands=['spam'], pass_bot=True) 35 | 36 | register_handlers() 37 | 38 | # Middlewares 39 | bot.setup_middleware(AntiFloodMiddleware(limit=2, bot=bot)) 40 | 41 | 42 | # custom filters 43 | bot.add_custom_filter(AdminFilter()) 44 | 45 | async def run(): 46 | await bot.polling(non_stop=True) 47 | 48 | 49 | asyncio.run(run()) 50 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp 2 | aioredis 3 | -------------------------------------------------------------------------------- /systemd/tgbot.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | After=network.target 3 | Description=Template Bot 4 | 5 | [Service] 6 | Type=simple 7 | WorkingDirectory=/root/folder/ 8 | ExecStart=/usr/bin/python3 bot.py 9 | Restart=always 10 | 11 | [Install] 12 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /tgbot/config.py: -------------------------------------------------------------------------------- 1 | # any configuration should be stored here 2 | 3 | TOKEN = 'token' # configure env if you need; -------------------------------------------------------------------------------- /tgbot/filters/__init__.py: -------------------------------------------------------------------------------- 1 | # register filters here or in different folders. -------------------------------------------------------------------------------- /tgbot/filters/admin_filter.py: -------------------------------------------------------------------------------- 1 | from telebot.asyncio_filters import SimpleCustomFilter 2 | from tgbot.models.users_model import Admin 3 | 4 | 5 | class AdminFilter(SimpleCustomFilter): 6 | """ 7 | Filter for admin users 8 | """ 9 | 10 | key = 'admin' 11 | async def check(self, message): 12 | 13 | return int(message.chat.id) == int(Admin.ADMIN.value) -------------------------------------------------------------------------------- /tgbot/handlers/__init__.py: -------------------------------------------------------------------------------- 1 | # Create files for handlers in this folder. -------------------------------------------------------------------------------- /tgbot/handlers/admin.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | from telebot.types import Message 3 | 4 | async def admin_user(message: Message, bot: AsyncTeleBot): 5 | """ 6 | You can create a function and use parameter pass_bot. 7 | """ 8 | await bot.send_message(message.chat.id, "Hello, admin!") -------------------------------------------------------------------------------- /tgbot/handlers/spam_command.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | from telebot.types import Message 3 | 4 | 5 | async def anti_spam(message: Message, bot: AsyncTeleBot): 6 | """ 7 | You can create a function and use parameter pass_bot. 8 | """ 9 | 10 | await bot.send_message( 11 | message.chat.id, 12 | """This is demo spam command. 13 | If you send this command more than once within 2 seconds, 14 | bot will warn you. 15 | This is made by using middlewares.""" 16 | ) -------------------------------------------------------------------------------- /tgbot/handlers/user.py: -------------------------------------------------------------------------------- 1 | from telebot.async_telebot import AsyncTeleBot 2 | from telebot.types import Message 3 | 4 | async def any_user(message: Message, bot: AsyncTeleBot): 5 | """ 6 | You can create a function and use parameter pass_bot. 7 | """ 8 | await bot.send_message(message.chat.id, "Hello, user!") -------------------------------------------------------------------------------- /tgbot/middlewares/__init__.py: -------------------------------------------------------------------------------- 1 | # Create files for your middlewares in this folder. -------------------------------------------------------------------------------- /tgbot/middlewares/antiflood_middleware.py: -------------------------------------------------------------------------------- 1 | from telebot.asyncio_handler_backends import BaseMiddleware 2 | from telebot.async_telebot import CancelUpdate 3 | 4 | class AntiFloodMiddleware(BaseMiddleware): 5 | def __init__(self, limit, bot) -> None: 6 | self.last_time = {} 7 | self.limit = limit 8 | self.update_types = ['message'] 9 | self.bot = bot 10 | # Always specify update types, otherwise middlewares won't work 11 | 12 | 13 | async def pre_process(self, message, data): 14 | if message.text != '/spam': return # make it work only for this command 15 | if not message.from_user.id in self.last_time: 16 | # User is not in a dict, so lets add and cancel this function 17 | self.last_time[message.from_user.id] = message.date 18 | return 19 | if message.date - self.last_time[message.from_user.id] < self.limit: 20 | # User is flooding 21 | await self.bot.send_message(message.chat.id, 'You are making request too often') 22 | return CancelUpdate() 23 | # write the time of the last request 24 | self.last_time[message.from_user.id] = message.date 25 | 26 | 27 | async def post_process(self, message, data, exception): 28 | pass -------------------------------------------------------------------------------- /tgbot/models/__init__.py: -------------------------------------------------------------------------------- 1 | # Register models in this folder. -------------------------------------------------------------------------------- /tgbot/models/users_model.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | # Admin role 5 | class Admin(Enum): 6 | ADMIN = 927266710 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tgbot/states/__init__.py: -------------------------------------------------------------------------------- 1 | # register states in this folder. -------------------------------------------------------------------------------- /tgbot/states/register_state.py: -------------------------------------------------------------------------------- 1 | # Create your states in this folder. 2 | 3 | 4 | from telebot.asyncio_handler_backends import State, StatesGroup 5 | 6 | 7 | class Register(StatesGroup): 8 | """ 9 | Group of states for registering 10 | """ 11 | name = State() 12 | surname = State() -------------------------------------------------------------------------------- /tgbot/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # create your functions, database connections, and other things in this folder -------------------------------------------------------------------------------- /tgbot/utils/database.py: -------------------------------------------------------------------------------- 1 | # aioredis 2 | import aioredis 3 | 4 | # Create a connection 5 | class Database: 6 | def __init__(self) -> None: 7 | self.redis = aioredis.from_url("redis://localhost") 8 | # write other methods if needed. 9 | --------------------------------------------------------------------------------