We make a Telegram bot with the Admin panel and many other goodies. Part 2

The last article was a failure, which is why I want to improve the situation by writing a sequel. Well, I’ll be distracted by the simplest things, let’s get started!

Well, for starters, if you’re from the last article, install PyCharm. I think there will be no difficulties with the installation, at least I hope so.

Open up PyCharm, create a main.py file and start writing.

First preparations
  1. We import the required libraries:

    from aiogram import Bot, Dispatcher, executor, types
    from aiogram.contrib.fsm_storage.memory import MemoryStorage
    from aiogram.dispatcher import FSMContext
    from aiogram.dispatcher.filters.state import State, StatesGroup
    from aiogram.types import Message
    import logging
    import sqlite3
  2. Declaring variables

    API_TOKEN = 'ТОКЕН'
    ADMIN = ваш user-id. Узнать можно тут @getmyid_bot
    
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
    kb.add(types.InlineKeyboardButton(text="Рассылка"))
    kb.add(types.InlineKeyboardButton(text="Добавить в ЧС"))
    kb.add(types.InlineKeyboardButton(text="Убрать из ЧС"))
    kb.add(types.InlineKeyboardButton(text="Статистика"))
  3. Initializing the project

    logging.basicConfig(level=logging.INFO)
    storage = MemoryStorage()
    bot = Bot(token=API_TOKEN)
    dp = Dispatcher(bot, storage=storage)
  4. Create a Database

    conn = sqlite3.connect('db.db')
    cur = conn.cursor()
    cur.execute("""CREATE TABLE IF NOT EXISTS users(user_id INTEGER, block INTEGER);""")
    conn.commit()
  5. Declaring States

    class dialog(StatesGroup):
    	spam = State()
      blacklist = State()
      whitelist = State()

These are the first preparations, now we are ready to start writing the basic logic.

Processing the “/ start” command
@dp.message_handler(commands=['start'])
async def start(message: Message):
  cur = conn.cursor()
  cur.execute(f"SELECT block FROM users WHERE user_id = {message.chat.id}")
  result = cur.fetchone()
  if message.from_user.id == ADMIN:
    await message.answer('Добро пожаловать в Админ-Панель! Выберите действие на клавиатуре', reply_markup=kb)
  else:
      if result is None:
        cur = conn.cursor()
        cur.execute(f'''SELECT * FROM users WHERE (user_id="{message.from_user.id}")''')
        entry = cur.fetchone()
        if entry is None:
          cur.execute(f'''INSERT INTO users VALUES ('{message.from_user.id}', '0')''')
          conn.commit()
          await message.answer('Привет')
      else:
        await message.answer('Ты был заблокирован!')

Here we add three buttons to the admin panel

Let’s write a function to handle the “Subscribe” button

Mailing function

Now let’s process the “Subscribe” button

@dp.message_handler(content_types=['text'], text="Рассылка")
async def spam(message: Message):
  await dialog.spam.set()
  await message.answer('Напиши текст рассылки')

But here we just ask the admin what kind of mailing text is

Now let’s process this text and send it to users.

@dp.message_handler(state=dialog.spam)
async def start_spam(message: Message, state: FSMContext):
  if message.text == 'Назад':
    await message.answer('Главное меню', reply_markup=kb)
    await state.finish()
  else:
    cur = conn.cursor()
    cur.execute(f'''SELECT user_id FROM users''')
    spam_base = cur.fetchall()
      for z in range(len(spam_base)):
        await bot.send_message(spam_base[z][0], message.text)
        await message.answer('Рассылка завершена', reply_markup=kb)
        await state.finish()

Here we get users from the Base and send each message

Now let’s add users to the emergency

Lock function

Now we will process the button “Add to emergency”

@dp.message_handler(content_types=['text'], text="Добавить в ЧС")
async def hanadler(message: types.Message, state: FSMContext):
  if message.chat.id == ADMIN:
    keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True)
    keyboard.add(types.InlineKeyboardButton(text="Назад"))
    await message.answer('Введите id пользователя, которого нужно заблокировать.nДля отмены нажмите кнопку ниже', reply_markup=keyboard)
    await dialog.blacklist.set()

But again, now the bot will not do anything with the received ID. Let’s ban users)

@dp.message_handler(state=dialog.blacklist)
async def proce(message: types.Message, state: FSMContext):
  if message.text == 'Назад':
    await message.answer('Отмена! Возвращаю назад.', reply_markup=kb)
    await state.finish()
  else:
    if message.text.isdigit():
      cur = conn.cursor()
      cur.execute(f"SELECT block FROM users WHERE user_id = {message.text}")
      result = cur.fetchall()
      if len(result) == 0:
        await message.answer('Такой пользователь не найден в базе данных.', reply_markup=kb)
        await state.finish()
      else:
        a = result[0]
        id = a[0]
        if id == 0:
          cur.execute(f"UPDATE users SET block = 1 WHERE user_id = {message.text}")
          conn.commit()
          await message.answer('Пользователь успешно добавлен в ЧС.', reply_markup=kb)
          await state.finish()
          await bot.send_message(message.text, 'Ты был забанен Администрацией')
        else:
          await message.answer('Данный пользователь уже получил бан', reply_markup=kb)
          await state.finish()
    else:
      await message.answer('Ты вводишь буквы...nnВведи ID')

Now, after you send him a user ID, he will check it, and if he found this user in the Base not banned, then he will be banned! Otherwise, it returns to the main menu.

Now let’s remove users from the emergency

Unlock function

To begin with, according to the standard, we will process the button

@dp.message_handler(content_types=['text'], text="Убрать из ЧС")
async def hfandler(message: types.Message, state: FSMContext):
  cur = conn.cursor()
  cur.execute(f"SELECT block FROM users WHERE user_id = {message.chat.id}")
  result = cur.fetchone()
  if result is None:
    if message.chat.id == ADMIN:
      keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True)
      keyboard.add(types.InlineKeyboardButton(text="Назад"))
      await message.answer('Введите id пользователя, которого нужно разблокировать.nДля отмены нажмите кнопку ниже', reply_markup=keyboard)
      await dialog.whitelist.set()

And again the bot does nothing, now let’s fix it!

@dp.message_handler(state=dialog.whitelist)
async def proc(message: types.Message, state: FSMContext):
  if message.text == 'Отмена':
    await message.answer('Отмена! Возвращаю назад.', reply_markup=kb)
    await state.finish()
  else:
    if message.text.isdigit():
      cur = conn.cursor()
      cur.execute(f"SELECT block FROM users WHERE user_id = {message.text}")
      result = cur.fetchall()
      conn.commit()
      if len(result) == 0:
        await message.answer('Такой пользователь не найден в базе данных.', reply_markup=kb)
        await state.finish()
      else:
        a = result[0]
        id = a[0]
        if id == 1:
          cur = conn.cursor()
          cur.execute(f"UPDATE users SET block = 0 WHERE user_id = {message.text}")
          conn.commit()
          await message.answer('Пользователь успешно разбанен.', reply_markup=kb)
          await state.finish()
          await bot.send_message(message.text, 'Вы были разблокированы администрацией.')
        else:
          await message.answer('Данный пользователь не получал бан.', reply_markup=kb)
          await state.finish()
    else:
      await message.answer('Ты вводишь буквы...nnВведи ID')

Now let’s add statistics for our bot

Statistics

Unlike other functions, this one will be the simplest.

Here we will receive the number of users in the bot, not active, nor any others, just those who have entered the bot at least once

@dp.message_handler(content_types=['text'], text="Статистика")
async def hfandler(message: types.Message, state: FSMContext):
	cur = conn.cursor()
	cur.execute('''select * from users''')
  results = cur.fetchall()
  await message.answer(f'Людей которые когда либо заходили в бота: {len(results)}')

Now you also have statistics for the bot.

That’s all!

At the end of the file, we must add two lines

if __name__ == '__main__':
  executor.start_polling(dp, skip_updates=True)

Now, just launch it and go check it out!
I understand the functionality is not great, not what the title says, but I accept suggestions for what else to add! In the future, finally, I will most likely implement proposals, and I will add them to this article, or to a new one!

All code is laid out on GITHUB

As usual, I am available at the TG: @derkown

Thanks for reading!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *