I'm trying to make a command that takes the user's display name and adds it to a list, "registering" them for an event, but whenever I call the command, it doesn't send the confirmation message of a successful registration. But, if I've already registered, it sends that message telling me I already registered.
Here is my code:
#client.command()
async def register(ctx, *, message=''):
name = ctx.message.author.display_name
embed = Embed(title='Activity Registration', colour= discord.Colour.blue())
if len(fireteam) == 6:
embed.add_field(name='Fireteam Full', value='There is no space left in the fireteam.', inline=False)
else:
if name in fireteam:
embed.add_field(name='You are already registered', value='You cannot register again.', inline=False)
else:
fireteam.append(name)
embed.add_field(name='Successfully Registered', value = name + ' has successfully registered for: **' + message + '**', inline = False)
embed.add_field(name= 'Current Fireteam:', inline = False)
for person in fireteam:
name = ''.join(person)
embed.add_field(value= name, inline= False)
embed.set_thumbnail(url= ctx.message.author.avatar_url)
await ctx.send(embed=embed)
It seems to only be the embedded messages under the second "else" statements that aren't working as I was able to print the contents of the list (fireteam) that the user's names are stored in to the console on a successful registration and my name was on that list, so it's going meeting the criteria to get to that else statement and run that code. Along with that, if I do "^register" a second time, I get the "you already registered" message to pop up, so it's recording my info, it's just not sending the embedded messages.
for person in fireteam:
name = ''.join(person)
embed.add_field(value= name, inline= False) # this causes error
add_field cant be called without a name param
an alternative way would be
embed.add_field(name = "Current Fireteam", value= "\n".join(fireteam), inline= False)
Related
So im making a discord Bot that will notify me when my favorite food is avalable in the cafiteria at my school. Im trying to make it so multiple people can use the bot so im storing the users favorite food in a dictionary with their user id as the key. I've never used slash commands in discord before, normally I just use a command.prefix but decided to try it this way instead.
So far this is what I have:
client = aclient()
tree = app_commands.CommandTree(client)
#tree.command(guild = discord.Object(id=guild_id), name = 'favorite_add', description='Add a food item to your favorite food list') #guild specific slash command
async def addFavorite(interaction: discord.Interaction, content : str = ""):
await interaction.response.send_message(f"{content} has been added to your favorite food list", ephemeral = True)
userFavorites[content.author.id] += [content]
The problem im having is that the str: content doesnt have the author.id attrubite. Is there any way to aquire the id of who posted the command so I can add the content to their favorite food list or potentially add a new key to my dictionary
async def addFavorite(interaction: discord.Interaction, content : str = ""):
^^^^^^^
That's because the content argument is a string since you're telling the library that you wanted it to be. If you want to get the ID of the user who triggered the command, you have to get the user from interaction.user then get the ID.
userFavorites[interaction.user.id] += [content]
discord.py isn't beginner-friendly; you should know the basics before trying it. You can look at some examples here.
Let's say I have this command handler:
#bot.message_handler(commands=['setalarm'])
def setalarmcmd(message):
alarmMessage = "Let's start with setting up alarm.\n\n" \
"First of all, provide the pair you want to observe."
bot.send_message(message.chat.id, alarmMessage)
I want to set some action when user click /setalarm command and replies on this message.
Actually, I know how to do that, but I already have handler on provided text:
#bot.message_handler(content_types=['text'])
def getpairfuncmessage(message):
userMessage = message.text.strip().upper()
pair = getPairApi(userMessage)
if not pair:
return bot.send_message(message.chat.id, "Nah, not that, try something else.")
pairResult = printPairResult(pair)
bot.send_message(message.chat.id, pairResult, parse_mode='html')
And that's the problem. By providing message, user triggers this action, but I want to set another one, after /setalarm command. Is this possible?
Here is how you can do this:
#bot.message_handler(commands=['setalarm'])
def setalarmcmd(message):
alarmMessage = "Let's start with setting up alarm.\n\n" \
"First of all, provide the pair you want to observe."
msg = bot.send_message(message.chat.id, alarmMessage)
bot.register_next_step_handler(msg, setalarmcryptopair)
def setalarmcryptopair(pair):
print(pair.text)
Using send_message and register_next_step_handler to go to next function.
I am wondering how I could store/read out a user chat ID to later send them messages.
Example would be, that the user is adding my telegram bot and sends him a message.
Later on in my program at some point, when a sepcific situation occurs, I want to send a message to the specific user.
For a simple example I have this code:
a=1
b=2
if a > b:
# at this point python should send a message to a user via telegram privat chat
else:
# send a different message
I know how to handle a response to a command sent by the user in the telegram chat, but not how to send a message to a user without receiving a command first. I think there fore I would need to have a way to store the users chat Id first to later refer to that Id when sending the message.
The point is I want to compile my program to .exe later on and send it to some friends and it should work for them as well.
It is very easy, just use a simple database.
MongoDB is the best choose in my opinion.
Create an account on it and follow this tutorial.
First get the user_id
userid1 = str(update.message.chat_id)
Then store it into the database
import pymongo
from pymongo import MongoClient
cluster = MongoClient("mongodb+srv://<user>:<password>#cluster0.uubct.mongodb.net/users?retryWrites=true&w=majority")
db = cluster["users"]
collection = db["users"]
results = collection.find({"_id": int(userid1)})
if results.count() == 0:
print("post")
post = {"_id": int(userid1)}
collection.insert_one(post)
else:
print("User already in the database!")
For getting it you need to use the find() method.
results = collection.find()
for result in results:
var1 = (result["_id"])
print(var1)
context.bot.send_message(chat_id=prova,
text = "Hi")
You can simply add the id in a list WHITOUT ANY THIRD PARTS PAKAGE
import telebot
TOKEN = ""
bot = telebot.TeleBot(TOKEN)
admin = # your chat id
users = []
#bot.message_handler(commands=['start'])
def start_message(msg):
bot.send_message(msg.chat.id, 'Welcome!')
if msg.chat.id not in users: # if the id isn't already in the users list
users.append(msg.chat.id)
#bot.message_handler(commands=['send_at_all']) # A way to use the list
def sendAtAll(msg):
if msg.chat.id == admin: # only if YOU start the command the message will be sent
for id in users: # for every user that has start the bot
bot.send_message(id, "I'm sending this message at all the users")
# If an user wants to stop the notifications...
#bot.message_handler(commands=['unsubscribe'])
def sendAtAll(msg):
del users[msg.chat.id]
bot.send_message(msg.chat.id, "If you want to receive the notification click /start")
# Every time you are going to restart the bot polling the content of the users list will be deleated so...
#bot.message_handler(commands=['save_user_list'])
def sendAtAll(msg):
if msg.chat.id == admin:
bot.send_message(admin, users)
# the list will be sent to your telegram chat, when you activate the bot you can add the list manually
bot.polling()
You can also create a class and save every chat id as an object
import telebot
from random import choice
TOKEN = ''
bot = telebot.TeleBot(TOKEN)
admin = # your chat id
users = []
class Userbot: # The class User is already in the pyTelegramBotAPI
def __init__(self, msg):
self.id = msg.chat.id
self.username = '#' + msg.from_user.username
def contestWinner(self):
text = f'Hi {self.username}, you have win!!!'
bot.send_message(self.id, text)
#bot.message_handler(commands=['start'])
def start(msg):
bot.send_message(msg.chat.id, 'Welcome!')
for el in users:
if msg.chat.id not in el.id:
users.append(Userbot(msg))
# you can't type 'if msg.chat.id not in users.id' because only the object inside the list can use the method id
#bot.message_handler(commands=['extract']) # another way to use the list
def extract(msg):
if msg.chat.id == admin:
winner = choice(users)
winner.contestWinner()
#bot.message_handler(commands=['unsubscribe'])
def sendAtAll(msg):
for el in users:
if msg.chat.id == el.id:
del users[el]
# only if the user inside the object is the same as the user that has sent the message the object will be deleated
bot.send_message(msg.chat.id, "If you want to receive the notification click /start")
#bot.message_handler(commands=['save_user_list'])
def sendAtAll(msg):
if msg.chat.id == admin:
bot.send_message(admin, users)
bot.polling()
Apologise for my terrible english
I'm developing an text message marketing service. In order to subscribe to my service, the user must text the keyword memphis. I've already written the code to add the users number to my subscriber's list, but if someone's number is already on the list, how can I include a process to check the already existing list and reply back with a message informing the user that they are already subscribed?
I have tried using a for loop to iterate over every number in the csv file:
def sms_subscription():
contact_num = request.values.get('From')
response = request.values.get('Body')
resp = MessagingResponse()
#NEW SUBSCRIBERS
if response.lower() == 'memphis':
with open('Subscriber_List.csv', 'r+') as subscriber_list:
subscriber_list_writer = csv.writer(subscriber_list)
for contact in subscriber_list:
if contact == contact_num:
resp.message("Your already subscribed")
return str(resp)
else:
subscriber_list_writer.writerow([contact_num])
resp.message("Thanks for subscribing to our local coupon book. As we get new deals, we'll notify via SMS. To opt-out reply 'STOP'")
return str(resp)
else:
resp.message("Be sure to check spelling and for spaces and try again.")
return str(resp
I've tested this with my personal cell phone. Instead of replying back to me that my number is already subscribed, I continue to get the "Thanks for subscribing to our local coupon book.
As we get new deals, we'll notify the user via SMS. To opt-out, the user would reply 'STOP'.
I think I see the problem.
Your code:
def sms_subscription():
contact_num = request.values.get('From')
response = request.values.get('Body')
resp = MessagingResponse()
#NEW SUBSCRIBERS
if response.lower() == 'memphis':
with open('Subscriber_List.csv', 'r+') as subscriber_list:
subscriber_list_writer = csv.writer(subscriber_list)
for contact in subscriber_list:
if contact == contact_num:
resp.message("Your already subscribed")
return str(resp)
else:
subscriber_list_writer.writerow([contact_num])
resp.message("Thanks for subscribing to our local coupon book. As we get new deals, we'll notify via SMS. To opt-out reply 'STOP'")
return str(resp)
else:
resp.message("Be sure to check spelling and for spaces and try again.")
return str(resp
First off, you should change subscriber_list to subscriber_list.readlines() to get a list in which each line is an element.
In your for loop you check if contact equals contact_num, but contact contains a newline (\n) (in my case when I tested it, but it may contain whitespaces or other chars), and thus is not equal to contact_num. To fix this, you can add these lines (there are one-liners to do this, with regex for example, but I'm using this example for readability and simplicity) above if contact == contact_num:
contact = contact.replace('\n','')
contact = contact.replace(' ','')
What these do is replace newlines and whitespaces with nothing, essentially removing them.
Furthermore, in your for loop, you are checking if contact_num is in the file, but if it is not the first element, then it will run this:
else:
subscriber_list_writer.writerow([contact_num])
resp.message("Thanks for subscribing to our local coupon book. As we get new deals, we'll notify via SMS. To opt-out reply 'STOP'")
return str(resp)
What you need is to check all elements in the file, and then, if the number was not found, write it to the file. When you return a value, it exits the function, so if the first element in your file is not the desired phone number, then it will run your code under else and exit the function.
To fix this, just move
else:
subscriber_list_writer.writerow([contact_num])
resp.message("Thanks for subscribing to our local coupon book. As we get new deals, we'll notify via SMS. To opt-out reply 'STOP'")
return str(resp)
outside of the for loop, and remove the else-- it is not needed. The loop will now check to see if contact_num is in the file, and if it is, it will return
"You're already subscribed",
if not, it will add the num to the file and return
"Thanks for subscribing to our local coupon book. As we get new deals, we'll notify via SMS. To opt-out reply 'STOP'"
I am assuming that MessagingResponse() is a class, like so:
class MessagingResponse:
def __init__(self,message):
self.message = message
If so, resp.message("Your already subscribed") will throw an error; the correct syntax is resp.message = "Your already subscribed".
Final code (with a few modifications):
EDIT:
As #jpmc26 said, using the csv reader/writer is a better option. There were also some bugs in the previous code. Edited code:
def sms_subscription():
contact_num = request.values.get('From')
response = request.values.get('Body')
resp = MessagingResponse("") #you might want to remove the quotes if this throws an error
#NEW SUBSCRIBERS
if response.lower() == 'memphis':
with open('Subscriber_List.csv', 'r+') as subscriber_list:
for contact in csv.reader(subscriber_list):
if contact_num in contact:
resp.message = "You're already subscribed"
return resp
csv.writer(subscriber_list).writerow([contact_num])
resp.message = ("Thanks for subscribing to our local coupon book. As we get new deals, we'll notify via SMS. To opt-out reply 'STOP'")
return resp
else:
resp.message = "Be sure to check spelling and for spaces and try again."
return resp
I am building some telegram bot on python (using this framework pyTelegramBotAPI). And I ran into the problem with user input. I need save user input(it can be any text) after certain bot's message. For example:
Bot: - Please describe your problem.
User: - Our computer doesn't work.
Then I need to save this text "Our computer doesn't work" to some variable and go to the next step.
Here's my code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import telebot
import constants
from telebot import types
bot = telebot.TeleBot(constants.token)
#bot.message_handler(commands=['start'])
def handle_start(message):
keyboard = types.InlineKeyboardMarkup()
callback_button = types.InlineKeyboardButton(text="Help me!", callback_data="start")
keyboard.add(callback_button)
bot.send_message(message.chat.id, "Welcome I am helper bot!", reply_markup=keyboard)
#bot.inline_handler(lambda query: len(query.query) > 0)
def query_text(query):
kb = types.InlineKeyboardMarkup()
kb.add(types.InlineKeyboardButton(text="Help me!", callback_data="start"))
results = []
single_msg = types.InlineQueryResultArticle(
id="1", title="Press me",
input_message_content=types.InputTextMessageContent(message_text="Welcome I am helper bot!"),
reply_markup=kb
)
results.append(single_msg)
bot.answer_inline_query(query.id, results)
#bot.callback_query_handler(func=lambda call: True)
def callback_inline(call):
if call.message:
if call.data == "start":
bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="Please describe your problem.")
#here I need wait for user text response, save it and go to the next step
I have the idea with using message_id in statement, but still can't implement it. How I can solve this? Any ideas? Thank you.
This will help you
https://github.com/eternnoir/pyTelegramBotAPI/blob/master/examples/step_example.py
import telebot
import constants
from telebot import types
bot = telebot.TeleBot(constants.token)
#bot.message_handler(commands=['start'])
def start(message):
sent = bot.send_message(message.chat.id, 'Please describe your problem.')
bot.register_next_step_handler(sent, hello)
def hello(message):
open('problem.txt', 'w').write(message.chat.id + ' | ' + message.text + '||')
bot.send_message(message.chat.id, 'Thank you!')
bot.send_message(ADMIN_ID, message.chat.id + ' | ' + message.text)
bot.polling()
its not a python or even programming related question. its more like designing problem. but anyway.
the solution is keeping session for users. for example user send you:
Our computer doesn't work.
at first you create a session for this user(the identity should be a user id) then send him/her a proper message. when user send the next message at first you look at the user status and see if he/she has a session or not. if he/she has session you continue with second step. i develop a bot like this and used dictionary in order to store users sessions. but it make all thing little complicated.
You can use Forcereply.
Upon receiving a message with this object, Telegram clients will display a reply interface to the user (act as if the user has selected the bot‘s message and tapped ’Reply'). This can be extremely useful if you want to create user-friendly step-by-step interfaces without having to sacrifice privacy mode. https://core.telegram.org/bots/api#forcereply
i know how fix that. It took 3 years for solution.
Just look at my code and make your own. Thx
#bot.callback_query_handler(func=lambda call: True)
def callback_inline(call): #your call
UserID = str(call.message.chat.id)
if call.data == 'PhotoTEXT':
#bot.message_handler(content_types=['text'])
def SetTEXTonPHOTO(message): # THIS FUNCTION
sent = bot.send_message(message.chat.id,'send me text')
bot.register_next_step_handler(sent, TextONphoto)
def TextONphoto(message): #Thsi function add text on photo
im = Image.open('UserData/Files/photos/not_converted/'+UserID+'.jpg')
idraw = ImageDraw.Draw(im)
text = message.text
font = ImageFont.truetype("arial.ttf", size=18)
idraw.text((10, 10), text, font=font)
im.save('UserData/Files/photos/converted/'+UserID+'.jpg')
im.show()
SetTEXTonPHOTO(call.message) #just run your function
with open('UserData/Files/photos/converted/'+UserID+'.jpg', 'rb') as file:
bot.send_document(UserID,file)
I think i helped you friends <3
You should save the data in cache or database.