Telegram bot (using aiogram): User verification - python

I'm making a Telegram bot for work purposes. For confidentiality reasons I need to implement a identification check upon starting the bot.
I'm getting a list of employees IDs who are given access to the bot from a database. It is updated every day.
When a user starts the bot, it asks for the ID. The user is supposed to reply with their ID.
The bot then is supposed to check if this ID is in the list downloaded from the database.
If it is, the bot gives access to the information. If not, it replies with something like "Sorry, you are not a verified user. For getting access, please contact Kate or try again."
Also, it needs to check this information every day - since a list of employees can change every day (for example, in case one of the employees on the list quit their job).
I haven't been able to find suitable solutions on the Internet or come up with one that works for me.
Please help me out with ideas - I'm still new to Python and only just started learning about aiogram.
Things I have tried:
I managed to make the bot respond to 'XXXXXXX' with "verification succeeded" lol:
dp.register_message_handler(handlers.start, commands=["start"])
dp.register_message_handler(handlers.verify_user, text=["XXXXXXX"])
user_id_list = ['YYYYYYY', 'XXXXXXX', 'ZZZZZZ']
# start
async def start(message: types.Message):
await message.answer("Hi there! For verification please write your ID in this format: XXXXXXX.")
# verification
async def verify_user(message: types.Message):
if message.text in user_id_list:
keyboard = types.InlineKeyboardMarkup()
keyboard.add(types.InlineKeyboardButton(text="get report", callback_data="get_report"))
await message.answer("You have been identified!", reply_markup=keyboard)
else:
keyboard = types.InlineKeyboardMarkup()
keyboard.add(types.InlineKeyboardButton(text="try again", callback_data="/start"))
await message.answer("Sorry, you are not a verified user. For getting access, please contact Kate or try again.", reply_markup=keyboard)
I also tried using Text filter like this:
id_list = ['XXXXX', 'YYYYY']
dp.register_message_handler(handlers.verification, filters.Text(contains=id_list, ignore_case=True))
async def verification(message: types.Message):
keyboard = types.InlineKeyboardMarkup()
keyboard.add(types.InlineKeyboardButton(text="get report", callback_data="get_report"))
await message.answer("You have been identified!", reply_markup=keyboard)
but this only works if you include the whole id_list in your message (i.e. XXXXX YYYYY).
Another thing I tried is IDFilter but seems like it only works with numbers - and our IDs are str.
Finally, I tried creating a State and using FSM but I can't quite understand what this is doing: it checks my ID fine, but after that the bot does nothing. Moreover, if I restart the bot, it doesn't ask me for my ID, it tells me straight away that my ID is wrong (it sees '/start' as an ID input, I guess). The code is below:
id_list = ['XXXXX', 'YYYYY']
class Form(StatesGroup):
work_id = State()
dp.register_message_handler(handlers.set_work_id, state=Form.work_id)
async def start(message: types.Message):
await bot.send_message(message.chat.id, 'Hi there! What is your ID?')
await Form.work_id.set()
async def set_work_id(message: types.Message, state: FSMContext):
if message.text in id_list:
keyboard = types.InlineKeyboardMarkup()
keyboard.add(types.InlineKeyboardButton(text="get report", callback_data="get_report"))
await message.answer("You have been verified!", reply_markup=keyboard)
else:
keyboard = types.InlineKeyboardMarkup()
keyboard.add(types.InlineKeyboardButton(text="Try again", callback_data="/start"))
await message.answer("Sorry, you are not a verified user. For getting access, please contact Kate or try again.", reply_markup=keyboard)

Related

Print channel id/name into console with discord py

So I need my bot to print in which channel it sents a message. This is my code:
#client.command()
async def test(ctx):
await ctx.reply('hello', mention_author=True)
channel = #what goes here????
print('i said hello in', (channel))
I've tried all of these:
user = bot.get_user(user_id)
message.author.username
username = client.get_user(user_id)
The things you tried are referencing user id. I have not used discord.py in a while, but you will have to reference the channel id and not the user id. Maybe try:
ctx.message.channel.id
I can't remember if this returns an object or a string so you may have to format further to get the string.

How should I store this and how do I do it? discord.py

I am struggling on something I am working on with my custom discord bot for someone. I have made a series of events that go like the picture here:
Link to Example
I want to be able to store this in a JSON file or database without sending it straight away so later I can do things like:
*event list - lists all text events/announcements Like this
;event preview 1 - Example here
With the '1' I want it to link to an event name in the json file so I can do this command so whatever event name is linked to whatever number. this is to see the preview of the announcement you made. it sends a period, edits that period to whatever is the event/announcement selected. this is so that if the announcement has an everyone or here ping, it wont ping when you're previewing the announcement
;event post 1 (or whatever number relates to the right event I want to post) Example here - this command posts that particular event
I can not figure out how to store it in the Json file or database and be able to do those commands above. I have had little help from other devs but I still cant figure it out and need help on how to do it. Below is my code so far if someone can please help me:
#bot.command()
async def event(ctx):
def check(msg):
return msg.channel.id == ctx.channel.id and msg.author.id == ctx.author.id
await ctx.send("Please enter the event name:")
eventname = await bot.wait_for("message", check=check)
await ctx.send("Please send what you want to say in the announcement in a code block:")
codeblock = await bot.wait_for("message", check=check)
await ctx.send("What image should be posted? (Type 'no' for none)")
image = await bot.wait_for("message", check=check)
mainimage = None
if image.content.lower() != "no":
mainimage = image.attachments[0]
await ctx.send('What channel should the announcement be made in? (Please tag the channel)')
eventch = await bot.wait_for("message", check=check)
realchannel = await commands.TextChannelConverter().convert(ctx, eventch.content)
message = codeblock.content.replace("```", "").replace("`", "")
if mainimage:
return await realchannel.send(message, file=await mainimage.to_file())
await realchannel.send(message)
(Sorry if not indented properly, nor sure how to on here)
Help is appreciated.
It kinda take too long to code so Im here to suggest a few steps to make it easy coding!
First You Need A Database to store these kind of values. i recommend MongoDB
Once You Created A Database in MongoDB, You can easily handle data to be stored [tutorial:youtube] or [tutorial:document]
with the help of wait_for function in discord.py and [refer this] you can get the data and store it in dict.
example
'
dict = {}
dict['name'] = ctx.message.content
#same for all
after storing all kind of info in the dict. you can upload the dict to the database
Now the data are stored in Database! if you learned PyMongo you can easily do the rest of your queries!

Check if the message channel is in that category

Can someone help me? I'm trying to make a modmail every thing is working fine, user sends a DM, bot creates a channel under "category" and if someone message inside that "category" it will be delivered to the user via DM. However I get this annoying error every time someone replies inside that "category" or user DMs the bot. I'm trying to make a category check to only do something if it's the mod mail category. Thank you in advance!
Here's my code:
async def on_message(self, message):
if isinstance(message.channel, discord.DMChannel):
# User DM the bot and the bot will make a textchannel under "category" and will send his DMs there. #
if message.channel.category_id == 123456789101112:
if isinstance(message.channel, discord.TextChannel):
# Message the user who DMed the bot using the textchannel under "category", your replies will be sent to the user by the bot via DM. #
Everything is working, but I'm getting this error every time someone replies inside that textchannel "category" or user DMs the bot
Error:
if message.channel.category_id == 123456789101112:
AttributeError: 'DMChannel' object has no attribute 'category_id'
Your if-statement doesn't make much sense, you should first check for the type of the channel and then for it's category and compare it.
async def on_message(message):
# Checking if the channel is a dm or a text one
if isinstance(message.channel, discord.DMChannel):
# do your thing
elif isinstance(message.channel, discord.TextChannel):
if message.channel.category is not None:
if message.channel.category.id == your_id:
# do your thing
You should format your code properly.
Also you can check whether message.author.id is your bots id client.user.id or a user.
Read the documentation for further information.

Get message content from reply in DM

I started making a little discord bot to give a key to people who request it. However, requirements changed and now I need to get a valid email from people who want one. I'm not sure how to get a reply in a DM.
I saw Discord.py get message from DM
But I don't really have client.get_user_info() or something?
bot = commands.Bot(command_prefix='!')
#bot.command(pass_context =True, no_pm=True, name='key', help="I give you a key. you're welcome", )
async def key_giver(ctx):
commandTime = str(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
##check if you're PMing bot
elif isinstance (ctx.channel, discord.DMChannel):
print(ctx.message)
await ctx.author.send(keyArray[0])
else:
response = "Hello my friend. I give you a key for a game. This is my purpose. Please enter your email!"
##Send key via PM
await ctx.author.send(response)
Printing ctx.message is
<Message id=620538695124254720 channel=<DMChannel id=614377525417738240 recipient=<User id=605223566371192852 name='aon' discriminator='5906' bot=False>> type=<MessageType.default: 0> author=<User id=605223566371192852 name='aon' discriminator='5906' bot=False>>
I'm really not sure. I'm just stupid, please don't yell at me.
You can use Client.wait_for to wait for the message and use its results. You already have the User object (ctx.author), so you can get the channel to listen for from User.dm_channel. I'm re-using the message_check function from this previous answer to generate the check
# Send them a message in a DM
await ctx.author.send("Please give an email address")
# Wait for a response
response = await bot.wait_for('message', check=message_check(channel=ctx.author.dm_channel))

DM commands to discord bot

I recently had the idea of DMing my bot commands. For example, a command which would unban me from every server that the bot is on.
Unfortunately I don't have any starting point for the command because I'm not even sure DMing commands is possible.
Keywords like discord.py, command or DM are so common in google that finding any good info on the topic is very hard.
I'm looking for a way for the bot to receive DMs as commands and only accept them from me (my ID is stored in the variable ownerID if anyone wants to share any code).
While I'm mostly looking for the above, some code for the DM unban command would also be very helpful.
EDIT: I was asked to show some example code from my bot. Here is the code for the command number which generates a random number and sends it in a message. I hope this gives you an idea of how my bot is made:
#BSL.command(pass_context = True)
async def number(ctx, minInt, maxInt):
if ctx.message.author.server_permissions.send_messages or ctx.message.author.id == ownerID:
maxInt = int(maxInt)
minInt = int(minInt)
randomInt = random.randint(minInt, maxInt)
randomInt = str(randomInt)
await BSL.send_message(ctx.message.channel, 'Your random number is: ' + randomInt)
else:
await BSL.send_message(ctx.message.channel, 'Sorry, you do not have the permissions to do that #{}!'.format(ctx.message.author))
You can send commands in private messages. Something like
#BSL.command(pass_context=True)
async def unban(ctx):
if ctx.message.channel.is_private and ctx.message.author.id == ownerID:
owner = await BSL.get_user_info(ownerID)
await BSL.say('Ok {}, unbanning you.'.format(owner.name))
for server in BSL.servers:
try:
await BSL.unban(server, owner) # I think having the same name should be fine. If you see weird errors this may be why.
await BSL.say('Unbanned from {}'.format(server.name))
except discord.HTTPException as e:
await BSL.say('Unbanning failed in {} because\n{}'.format(server.name, e.text))
except discord.Forbidden:
await BSL.say('Forbidden to unban in {}'.format(server.name))
else:
if ctx.message.author.id != ownerID:
await BSL.say('You are not my owner')
if not ctx.message.channel.is_private:
await BSL.say('This is a public channel')
should work. I'm not sure what happens if you try to unban a user who is not banned, that may be what raises HTTPException

Categories