I write telegram bot with aiogram
There's the function:
async def create_bill(message:types.Message, state: FSMContext):
if message.text.isdigit():
amount = int(message.text)
await message.answer('Создаю счет для оплаты...')
logging.logger_info.info('Создается счет')
bill = p2p.bill(bill_id=message.from_user.id+1, amount=amount, lifetime=5)
payment_url = p2p.check(bill_id=message.from_user.id+1).pay_url
pkb_btn_1 = InlineKeyboardButton('Оплатить', url=payment_url)
pkb_btn_2 = (InlineKeyboardButton(text="Зачислить на счет", callback_data='update_balance'))
pkb_mark_1 = InlineKeyboardMarkup.add(pkb_btn_1)
pkb_full = InlineKeyboardMarkup(row_width=2).add(pkb_btn_1)
pkb_full.add(pkb_btn_2)
logging.logger_info.info(f'Создан счет #{bill.bill_id} на сумму {amount} для пользователя {message.from_user.id}')
await message.answer('Счет создан!\nНажмите на кнопку, чтобы оплатить', reply_markup=pkb_full)
await UserStates.next()
else:
await message.answer('Пожалуйста, введите число!')
logging.logger_info.info(f'Пользователь {message.from_user.id} ввел некорректные данные')
It works and awaiting the inline keyboard with 2 buttons. First button is just a link (it works), second button should to call this handler:
#dp.callback_query_handler(lambda c: c.data == 'update_balance')
async def process_callback_balance_update(callback_query: types.CallbackQuery, state='*'):
if user.get_user_block_status(callback_query.from_user.id):
await callback_query.message.answer('Вы были заблокированы')
logging.logger_warn.warning(f'Заблокированный пользователь {callback_query.from_user.id} пытался подключиться к боту!')
else:
if p2p.check(bill_id=callback_query.from_user.id+1).status != 'PAID':
await callback_query.message.answer('Оплата не прошла!')
logging.logger_warn.warning(f'Пользователь {callback_query.from_user.id} пытался пополнить баланс с неоплаченным счетом!')
else:
current_balance = user.get_user_balance(callback_query.from_user.id)
new_balance = current_balance + p2p.check(bill_id=callback_query.from_user.id+1).amount
logging.logger_info.info(f'Производится зачисление средств на баланс пользователя {callback_query.from_user.id}')
await user.change_user_balance(callback_query.from_user.id, new_balance)
await callback_query.message.answer('Деньги зачислены')
await state.finish()
logging.logger_info.info(f'Деньги зачислены. Баланс пользователя {new_balance}')
await callback_query.answer()
But it's doesn't call handler!
I tried to add/remove state, replace this handler in another place in code, but nothing!
In logs I see this:
aiogram.contrib.middlewares.logging - INFO - Unhandled callback query [ID:1342058245786784398] from user [ID:312472285] for message [ID:621] in chat [private:312472285] with data: users originally posted by user [ID:5621517130]
I read almost all in google, read the docs and examples, tried different ways, but is still doesn't work
Also I have another handler wrote definitely same way and in works correctly
Related
I would appreciate if anyone out there could help me.
I wanted to code a bot for a esports team, which does have a ticket included, on pycharm on my computer actually everything works fine, but when i then want to host it on replit it doesnt work. I have made the ticket with discord-components and as the button is clicked, the bot thinks, but does never send the messege and goes on with the code. But on my other replit file I have another ticket, but that does work just fine.
Does someone have an idea what could have gone wrong?
#client.command()
async def tryout(ctx):
server = client.get_guild(879321194506121247)
tryouter = get(server.roles, name="Tryouter")
embed_tryout = discord.Embed(title="Tryout",
description="*Start your tryout right now, to join HOC-Esports and start your clash royale esports journey*",
color=discord.Color.from_rgb(244, 246, 246))
embed_tryout.add_field(name="What we offer:",
value="• 4-5 scrims per week\n• A good organised team with engaged managers\n• Custom HOC logo + banner",
inline=False)
embed_tryout.add_field(name="What we demand from you:",
value="• You are engaged to improve yourself\n• You aren't toxic",
inline=False)
embed_tryout.add_field(name="Informations to the tryout""Infos zum Tryout",
value=f"You will make a bo5 against a {tryouter.mention}, who will rate your skill decide if you fit in our team or not",
inline=False)
await ctx.send(embed=embed_tryout, components=[
[Button(label="🎫 start tryout", style=1, custom_id="button1")]
])
#client.event
async def on_button_click(interaction):
if interaction.custom_id == "button1":
pass
else:
return
guild = interaction.guild
tryouter = get(guild.roles, name="Tryouter")
category = client.get_channel(997078909071929434)
await interaction.send(content="You just started a tryout", ephemeral=True)
benutzer = str(interaction.user)
user_letters = len(benutzer)
username = benutzer[:user_letters - 4]
ticket_channel = await guild.create_text_channel(name=f"Tryout of {username}", category=category)
user = interaction.author
tryoutrole = get(guild.roles, name= "Tryout")
visitorrole = get(guild.roles, name="Besucher")
esports_role = get(guild.roles, id=917100410400014426)
await user.add_roles(tryoutrole)
await user.remove_roles(besucherrolle)
await ticket_channel.set_permissions(user, view_channel=True, read_message_history=True, read_messages=True,
add_reactions=True, embed_links=True, attach_files=True,
use_external_emojis=True)
await ticket_channel.send(
f"Welcome {interaction.user.mention}. You just started a tryout.\nA {tryouter.mention} will take care of you.\nPlease send meanwhile your friendlink and your profile right here\nIf you don't want to make the tryout anymore, just close the ticket.",
components=[
Button(label="🔒 close ticket", style=2, custom_id="button2")
])
interaction2 = await client.wait_for("button_click", check=lambda i: i.custom_id == "button2")
await interaction2.send(content="You just closed the ticket", ephemeral=True)
time.sleep(5)
await ticket_channel.delete()
await user.remove_roles(tryoutrole)
if esports_role in user.roles:
return
await user.add_roles(visiterrole)
I want that when a user writes a command, the bot deletes certain channels with certain names, but I can't succeed.
Error:
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'Guild' object has no attribute 'get_category'
Code:
#client.command()
async def verification_channels_delete(ctx):
await ctx.send('Удаляю категории и каналы для верефикации...')
category1 = await ctx.message.guild.get_category('Verification')
category2 = await ctx.message.guild.get_category("Chat")
await category1.delete()
await category2.delete()
channel1 = await ctx.message.guild.get_text_channel("Verification")
channel2 = await ctx.message.guild.get_text_channel("Chat")
await channel1.delete()
await channel2.delete()
await ctx.send('Я удалил все каналы для верефикации!')
If you want to get channel, category, or anything else by name you should use discord_utils for it:
from discord.utils import get
#client.command()
async def verification_channels_delete(ctx):
category1 = get(ctx.guild.categories, name = "Verification")
category2 = get(ctx.guild.categories, name = "Chat")
await category1.delete()
await category2.delete()
channel1 = get(ctx.guild.text_channels, name = "verification")
channel2 = get(ctx.guild.text_channels, name = "chat")
await channel1.delete()
await channel2.delete()
Im trying to make a public bot, and i would want this ticket system witha logging channel it already has a logging channel but how can i modify this to make a command that sets the logging channel?
# --- Ticket Open ---
#client.command()
#commands.guild_only()
async def ticket(ctx):
if ctx.channel.type != discord.ChannelType.private:
channels = [str(channel) for channel in client.get_all_channels()]
if f'ticket-{ctx.author.id}' in channels:
await ctx.message.delete()
else:
ticket_channel = await ctx.guild.create_text_channel(f'ticket-{ctx.author.id}')
await ticket_channel.set_permissions(ctx.guild.default_role, send_messages=False, read_messages=False)
await ticket_channel.set_permissions(ctx.author, send_messages=True, read_messages=True, add_reactions=True, embed_links=True, attach_files=True, read_message_history=True, external_emojis=True)
embed = discord.Embed(color=10181046, description=f'Please enter the reason for this ticket, type `-close` if you want to close this ticket.')
embed.set_thumbnail(url='')
await ticket_channel.send(f'{ctx.author.mention}', embed=embed)
await ctx.message.delete()
logchannel = await client.fetch_channel('850364625479532545')
embed = discord.Embed(title="Ticket Created",
description="",
color=discord.Colour.green())
embed.add_field(name=f'**By:** {ctx.author}',value= f'**ID:** {ctx.author.id}')
await logchannel.send(embed=embed)
#--- Ticket Close ---
#client.command()
#commands.guild_only()
async def close(ctx):
print(f'{ctx.author} | {ctx.author.id} -> {client.command_prefix}close')
if ctx.channel.type != discord.ChannelType.private:
admin_roles = [834126146215477348,835608325273157733,838859643224326144,835582821221138472,835914273402126376]
if ctx.channel.name == f'ticket-{ctx.author.id}':
await ctx.channel.delete()
elif admin_roles and 'ticket' in ctx.channel.name or ctx.author.id in administrator_ids and 'ticket' in ctx.channel.name:
await ctx.channel.delete()
else:
await ctx.message.delete()
logchannel = await client.fetch_channel('850364625479532545')
embed = discord.Embed(title="Ticket Closed",
description="",
color=discord.Colour.red())
embed.add_field(name=f'**By:** {ctx.author}',value= f'**ID:** {ctx.author.id}')
await logchannel.send(embed=embed)
Tip: if you want to create a public bot don't use handwritten channel id, you'd better save to file for all servers in json file and set it with command.
For example this:
{
"server identifier": "system channel identifier",
...
}
I don't know what's wrong with the code.
I have a script, it has inline buttons that, when clicked in a group chat, send a message to private messages.
I would like to try so that they send in response to pressing the inline button by chat id
If possible, write me where and how to add sending a message via chat id
For these messages, I need to change the sending to the chat id: https://imgur.com/a/RdXSb7E
PS: here is the chat id (-1001479485376)
import logging
import asyncio
from aiogram import Bot, Dispatcher, executor, types
from aiogram.utils.markdown import hbold, hunderline, hcode, hlink
API_TOKEN = 'token'
# Configure logging
logging.basicConfig(level=logging.INFO)
# Initialize bot and dispatcher
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot)
#dp.message_handler(commands='cat')
async def send_welcome(message: types.Message):
# So... At first I want to send something like this:
await message.reply("Вы хотите видеть много кисок? Вы готовы? 😏")
# Wait a little...
await asyncio.sleep(1)
# Good bots should send chat actions...
await types.ChatActions.upload_photo()
# Create media group
media = types.MediaGroup()
# Attach local file
media.attach_photo(types.InputFile('data/cat.jpg'), 'Cat!')
# More local files and more cats!
media.attach_photo(types.InputFile('data/cats.jpg'), 'More cats!')
# You can also use URL's
# For example: get random puss:
media.attach_photo('http://lorempixel.com/400/200/cats/', 'Random cat.')
# And you can also use file ID:
# media.attach_photo('<file_id>', 'cat-cat-cat.')
# Done! Send media group
await message.reply_media_group(media=media)
#dp.message_handler(commands='dog')
async def send_welcome(message: types.Message):
# So... At first I want to send something like this:
await message.reply("Вы хотите видеть много собачек? Вы готовы? 😏")
# Wait a little...
await asyncio.sleep(1)
# Good bots should send chat actions...
await types.ChatActions.upload_photo()
# Create media group
media = types.MediaGroup()
# Attach local file
media.attach_photo(types.InputFile('data/c2b.jpg'), 'Dog!')
# More local files and more cats!
media.attach_photo(types.InputFile('data/c2a.jpg'), 'More dog!')
media.attach_photo(types.InputFile('data/c2w.gif'), 'More dogs!')
# Done! Send media group
await message.reply_media_group(media=media)
#dp.message_handler(commands='music')
async def send_welcome(message: types.Message):
# So... At first I want to send something like this:
await message.reply("Вот и музычка подъехала! Вы готовы? 😏")
# Wait a little...
await asyncio.sleep(1)
await types.ChatActions.upload_photo()
# Create media group
media = types.MediaGroup()
media.attach_audio(types.InputFile('data/ChillOut.mp3'), 'Music!')
media.attach_audio(types.InputFile('data/REIMANN TEAM.mp3'), 'Music2!')
media.attach_audio(types.InputFile('data/Mister Robot Поёт.mp3'), 'Music3!')
# Done! Send media group
await message.reply_media_group(media=media)
#dp.message_handler(commands='bot')
async def start_cmd_handler(message: types.Message):
keyboard_markup = types.InlineKeyboardMarkup(row_width=3)
# default row_width is 3, so here we can omit it actually
# kept for clearness
text_and_data = (
('Помощь 🧞', 'Помощь 🧞'),
('Правила ⚔️', 'Правила ⚔️'),
('Мануалы 🧸', 'Мануалы 🧸'),
)
# in real life for the callback_data the callback data factory should be used
# here the raw string is used for the simplicity
row_btns = (types.InlineKeyboardButton(text, callback_data=data) for text, data in text_and_data)
keyboard_markup.row(*row_btns)
keyboard_markup.add(
# url buttons have no callback data
types.InlineKeyboardButton('ReimannLogs 🔱', url='https://t.me/reimannlogs_bot'),
)
await message.reply("Здравствуй, сударь! 👋🏻\nС чем тебе нужна помощь?", reply_markup=keyboard_markup)
# Use multiple registrators. Handler will execute when one of the filters is OK
#dp.callback_query_handler(text='Правила ⚔️') # if cb.data == 'no'
#dp.callback_query_handler(text='Помощь 🧞') # if cb.data == 'yes'
#dp.callback_query_handler(text='Мануалы 🧸')
async def inline_kb_answer_callback_handler(query: types.CallbackQuery):
answer_data = query.data
# always answer callback queries, even if you have nothing to say
await query.answer(f'Вы выбрали пункт {answer_data!r}')
if answer_data == 'Помощь 🧞':
text = "Есть какие-то вопросы? 🛎\n \nВот реквезиты:\n \nПо всем вопросам: #FollHash ☯️\nПо всем вопросам, заявкам в тиму: #t3sse ☯️\n \nВот полезные команды, для развлекухи:\n \n/cat - киски 😏\n/dog - собачки 🦮\n/music - музычка 🌆"
elif answer_data == 'Правила ⚔️':
text = """Пᴩᴀʙиᴧᴀ чᴀᴛᴀ 💻
=======================
Зᴀᴨᴩᴇщᴇнᴏ: 🚫
- ᴧюбᴀя ᴋᴏʍʍᴇᴩция ʙ чᴀᴛᴇ (ᴨᴏᴋуᴨᴋᴀ/ᴨᴩᴏдᴀжᴀ)
- уᴋᴀɜыʙᴀᴛь иᴧи ᴨᴏʍᴇчᴀᴛь дᴩуᴦиᴇ ᴋᴀнᴀᴧы иᴧи бᴏᴛы
- ᴩᴇᴋᴧᴀʍᴀ иᴧи уᴨᴏʍинᴀниᴇ ᴨᴏхᴏжих ᴩᴇᴄуᴩᴄᴏʙ/ɯᴏᴨᴏʙ/нᴇйʍᴏʙ ʙ ᴧюбᴏʍ ᴋᴏнᴛᴇᴋᴄᴛᴇ
- ᴨᴏᴨᴩᴏɯᴀйничᴇᴄᴛʙᴏ
- ɜᴧᴏуᴨᴏᴛᴩᴇбᴧᴇниᴇ "CAPS LOCK"
- ʙᴇᴄᴛи ᴄᴇбя нᴇᴀдᴇᴋʙᴀᴛнᴏ ʙ чᴀᴛᴇ и ᴩᴀɜʙᴏдиᴛь "ᴄᴩᴀч"
- ᴏᴄᴋᴏᴩбᴧᴇниᴇ "мᴏдᴇᴩᴀции/ᴨᴩᴏᴇᴋᴛᴀ/ɯᴏᴨᴀ" - бᴀн ❗️
- ᴏᴛᴨᴩᴀʙᴧяᴛь ᴄᴋᴩиʍᴇᴩы, ᴩᴀᴄчᴧᴇнᴇнᴋу, ᴄʙᴀᴄᴛиᴋу, нᴀциɜʍ, ᴋᴏнᴛᴇнᴛ 🔞
- ᴏɸᴏᴩʍᴧяᴛь ᴩᴀɜᴧичныᴇ ᴋᴀᴩᴛы, ᴀбуɜиᴛь ᴩᴇɸᴇᴩᴀᴧьную ᴄиᴄᴛᴇʍу, ᴄᴋᴀʍ и ᴏбʍᴀн ᴨᴏᴧьɜᴏʙᴀᴛᴇᴧᴇй
- ᴨᴩᴏᴨᴀᴦᴀндᴀ ᴨᴏᴧиᴛиᴋи
- ɸᴧуд\ᴄᴨᴀʍ ᴏдинᴀᴋᴏʙыʍи ɜᴀ ᴋᴏнᴛᴇᴋᴄᴛᴏʍ ᴄᴧᴏʙᴀʍи иᴧи ᴨᴩᴇдᴧᴏжᴇнияʍи (1 ᴨᴩᴇдуᴨᴩᴇждᴇниᴇ, ᴨᴏᴄᴧᴇ - ɯᴛᴩᴀɸ) """
elif answer_data == 'Мануалы 🧸':
text = "Краткий мануал о том как обрабатывать логи - https://telegra.ph/Kak-obrabatyvat-logi-05-30\nЗа привлечение новой аудитории, выдаю логи🥳"
else:
text = f'Unexpected callback data {answer_data!r}!'
await bot.send_message(query.from_chat.id, text)
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)
Just change await bot.send_message(query.from_chat.id, text) to await bot.send_message(-1001479485376, text). See the docs here.
I'm trying to make a poll command in Discord.py but want at the end the bot to send a list of users that reacted with 1️⃣ and another list of people that reacted with 2️⃣.
This is my code so far:
async def poll(ctx, q1, q2, time : int):
await ctx.send(f"React with 1 to vote for **{q1}** and with 2 to vote for **{q2}**\n**Poll Lasts for {time} seconds**")
poll = discord.Embed(title = "Poll", color = discord.Color.blue())
poll.add_field(name = f"{q1} 1️⃣", value = "")
poll.add_field(name = f"{q2} 2️⃣", value = "")
msg = await ctx.send(embed = poll)
r1 = await msg.add_reaction("1️⃣")
r2 = await msg.add_reaction("2️⃣")
await asyncio.sleep(time)
await ctx.send("Times up! **Poll Closed**")
new_msg = discord.utils.get(client.cached_messages,id = msg.id)
users1 = await r1.reactions[0].users().flatten()
users1.pop(users1.index(client.user))
users2 = await r2.reactions[0].users().flatten()
users2.pop(users2.index(client.user))
em=discord.Embed(title=f'Votes for {q1}', description=" , ".join(user.name for user in users1),color = discord.Colour.blue())
await ctx.send(embed = em)
em=discord.Embed(title=f'Votes for {q2}', description=" , ".join(user.name for user in users2),color = discord.Colour.blue())
await ctx.send(embed = em)
And this is the error I am getting:
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'NoneType' object has no attribute 'reactions'
Message.add_reaction returns None, you can't use these two lines
r1 = await msg.add_reaction("1️⃣")
r2 = await msg.add_reaction("2️⃣")
Easiest approach would be to fetch the message again with the updated reactions
message = await ctx.send("Whatever")
await message.add_reaction("1️⃣")
await message.add_reaction("2️⃣")
await asyncio.sleep(10)
updated_message = await ctx.channel.fetch_message(message.id)
users1, users2 = [], []
for r in updated_message.reactions:
print(f"{str(r)} was added {r.count} times")
if str(r) == "1️⃣":
users = await r.users().flatten()
users1.extend(users)
elif str(r) == "2️⃣":
users = await r.users().flatten()
users2.extend(users)
# `users1` and `users2` are lists of users that reacted with `1️⃣` and `2️⃣` accordingly
Reference:
Messageable.fetch_message
Message.reactions
Reaction.count
Reaction.users