How to handle several user requests in pytelegrambotapi[Telegram] - bots

I am new to telegram bot development. I use python 3.9
My bot works fine when 1 person uses but 2 or more it gives me Error code: 400. Description: Bad Request: message to edit not found
I use pytelegrambotapi and imported telebot
Here is my code:
import telebot
#bot.message_handler(commands = ["start"])
def start_bot(message):
global user
#--------creating new user or load old user data--------
user = USER(message.chat.id)
#-----------asking-----------
if user.isFull():
user.last_message = bot.send_message(message.chat.id,
f"Hello {user.fish}",
reply_markup=MAIN_MENU)
else:
bot.delete_message(message.chat.id, message.message_id)
bot.send_message(message.chat.id, "*Some post", reply_markup=None)
user.info_post_id = bot.send_message(message.chat.id, user.user_info_checking()).message_id
user.last_message = bot.send_message(message.chat.id, 'Name:')
#bot.message_handler(content_types=['text'])
def get_name_and_age(message):
global user
chat_id = message.chat.id
if user.last_message.text=='Name:':
user.fish = message.text
bot.delete_message(chat_id, message.message_id)
bot.edit_message_text(chat_id=chat_id,
message_id=user.info_post_id,
text=user.user_info_checking(),
reply_markup=None)
user.last_message = bot.edit_message_text(chat_id=chat_id,
message_id=user.last_message.message_id,
text="Age:",
reply_markup=None)
got this error
I need to keep my bot chat clean so I need to delete or edit messages but I got the error.
I used user class to save induvidual message and its id to track but still failed:
def __init__(self, id):
self.id = id
self.motion = None
self.info_post_id = None
self.last_message = None
self.last_error = None
self.post_counter = None
self.current_post = None
self.current_post_id = 0
self.current_post_link = None
self.current_catalog = None
self.current_channel_id = None
self.current_category = None
self.current_sub_category = None

The issue is likely the use of your global variable user. When two different users are using your bot at the same time, you write data from both of them into this object. Instead you do something like
user_info = defaultdict(USER)
...
def start_bot(message):
global user_info
#--------creating new user or load old user data--------
user = user_info[message.from_user.id]
...
Note that I used message.from_user.id rather then message.chat.id because for messages net in groups chats, message.chat will be the group chat, while message.from_user will be information about the user who sent the message.
It may be that pyTelegramBotAPI has some built-in mechanism for storing user-related data, but I'm not very familiar with that library …

Related

embed snipe message displays user id instead of the username discord bot python

My discord snipe feature but functions quite well however whenever it sends the embed of the deleted message, it displays the id number of the user who deleted the message instead of showing the actual username
#client.event
async def on_message_delete(message):
global snipe_message_content
global snipe_message_author
global snipe_message_id
snipe_message_content = message.content
snipe_message_author = message.author.id
snipe_message_id = message.id
embed = discord.Embed(description=f"{snipe_message_content}")
embed.set_author(name= f"<#{snipe_message_author}>")
channel = client.get_channel(795726497922809947)
await channel.send(embed=embed)
You assigned the author ID not the author name to snipe_message_author
snipe_message_author = message.author.name
Otherwise you could use str(message.author) which gives you the name#tag.
But I don't recommend that way. I'm using it myself because it is shorter than message.author.name + "#" + message.author.discriminator But yeah.

Discord.py welcome message for multiple servers

I am making a discord bot that I plan on being in multiple servers. Each server will have a different welcome channel name and all that. I made the welcome message and I tried making the bot post the message in a channel called "welcome" which would solve this problem but didn't work. I thought about making a database that saves the channel id that the server owner sends to the bot under the server name/ID. The bot when triggered would match the server ID to one in the database then grab the channel id linked to the server id. But that would be a lot of coding in SQL or PostgreSQL which I would have to learn how to get the bot to save the sever id and channel id to the database, How to get the bot to match the server id's then grab the channel id and posting it the message to the server. There is no documentation on discord py bots and making welcome messages for different servers. I was wondering if there is a better way to do it and how would I do it?
What I have so far in relation to the welcome message.
import discord
import logging
import asyncio
import random
import time
import tweepy, discord
from discord.ext import commands
from discord.ext.commands import bot
#File Imports
from config import *
client = commands.Bot(command_prefix='sec.')
# logger = logging.getLogger('discord')
# logger.setLevel(logging.DEBUG)
# handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w')
# handler.setFormatter(logging.Formatter('%(name)s: %(message)s'))
# logger.addHandler(handler)
#client.event
async def on_ready():
print('Logged in as %s' % client.user.name)
while True:
presence = random.choice(['sec.help', 'Defending Servers'])
activity = discord.Game(name=(presence))
await client.change_presence(status=discord.Status.online, activity=activity)
await asyncio.sleep(7)
client.remove_command('help')
#client.event
async def on_member_join(member):
# Adds role to user
# role = discord.utils.get(member.server.roles, name='Member')
# await client.add_roles(member, role)
# Random embed color
range = [255,0,0]
rand = random.shuffle(range)
# Welcomes User
embed = discord.Embed(title="{}'s info".format(member.name), description="Welcome too {}".format(member.guild.name))
embed.add_field(name="Name", value=member.name, inline=True)
embed.add_field(name="ID", value=member.id, inline=True)
embed.add_field(name="Status", value=member.status, inline=True)
embed.add_field(name="Roles", value=member.top_role)
embed.add_field(name="Joined", value=member.joined_at)
embed.add_field(name="Created", value=member.created_at)
embed.set_thumbnail(url=member.avatar_url)
inlul = client.get_channel(CHANNEL_ID)
await inlul.send(inlul, embed=embed)
If you find any documentation on this I would love to read it. All I could find are for bots that are basic and has you enter a channel id.
If the bot is on a much smaller scale, say just a few servers, then I'd say using a json file to save a dictionary wouldn't be a bad idea.
You can save the Id of the top text channel as a default when the server joins the server and let them change what channel to use with commands, this can be done with the on_guild_join event
import json
#sets value in json to guild id upon the bot joining the guild
#client.event
async def on_guild_join(guild):
#loads json file to dictionary
with open("filename.json", "r") as f:
guildInfo = json.load(f)
guildInfo[guild.id] = guild.text_channels[0] #sets key to guilds id and value to top textchannel
#writes dictionary to json file
with open("filename.json", "w") as f:
json.dump(guildInfo, f)
#allows server members to set channel for welcome messages to send to
#client.command()
async def welcomeMessage(ctx):
with open("filename.json", "r") as f:
guildInfo = json.load(f)
guildInfo[ctx.message.guild.id] = ctx.message.channel.id #sets channel to send message to as the channel the command was sent to
with open("filename.json", "w") as f:
json.dump(guildInfo, f)
then just use
with open("filename.json", "r"):
guildInfo = json.load(f)
channnel = guildInfo[ctx.message.guild.id]
to get the channel to send the message to and
channel.send(embed=embed)
to send the message
before running it ensure to have an empty json file in the same directory and add {} to the file.

Send message to new user only in python-telegram-bot

Currently I'm writing my first Telegram bot.
It should send a message to new users.
Other users should not get spammed by these messages and therefore I want to send it only to the new user.
I already have:
def switch(update, context):
try:
for new_member in update.message.new_chat_members:
callback_id = str(new_member.id)
# This is where I'm stuck
except AttributeError:
pass
def main():
updater = Updater(str(TOKEN), use_context=True)
dp = updater.dispatcher
dp.add_handler(MessageHandler(Filters.chat(int(CHAT_ID)), switch))
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
It runs until the commented line when a new user enters the chat.
Now I'm searching for the method to send a message to the new user only.

Easy integration of chatbot with slack-app

I have a ChatBot application running, just want to hook this application with Slack-api as it's interface.
I used Slack RTM and maintained user-session with its slack user-id.
finally solved and written a client(API) which can easily connect to any conversation engine.
Github repo link-
https://github.com/csemanmohan/Slack_api_client
import time
import re
from slackclient import SlackClient
import requests
# 'url', chatbot endpoint and 'slack_token' is slack application user-access-token
url = "http://127.0.0.1:****/*******/v2/api"
slack_token = "xoxb-**********-***********-*************lipO8hoI"
# instantiate Slack client
slack_client = SlackClient(slack_token)
# starterbot's user ID in Slack: value is assigned after the bot starts up
starterbot_id = None
# constants
RTM_READ_DELAY = 1 # 1 second delay between reading from RTM
EXAMPLE_COMMAND = "do"
MENTION_REGEX = "^<#(|[WU].+?)>(.*)"
def parse_bot_commands(slack_events):
"""
Parses a list of events coming from the Slack RTM API to find bot commands.
If a bot command is found, this function returns a tuple of command and channel.
If its not found, then this function returns None, None.
"""
# below var msg and channel_var will be used/
# when no trigger(#app-name) passed from application
msg = ""
channel_def = ""
for event in slack_events:
if event["type"] == "message" and not "subtype" in event:
msg = event["text"]
channel_def = event["channel"]
user_id, message = parse_direct_mention(event["text"])
print("there is an event here...", user_id, message)
if user_id == starterbot_id:
return message, event["channel"]
channel_def = channel_def
return msg, channel_def
def parse_direct_mention(message_text):
"""
Finds a direct mention (a mention that is at the beginning) in message text
and returns the user ID which was mentioned. If there is no direct mention, returns None
"""
matches = re.search(MENTION_REGEX, message_text)
# the first group contains the username, the second group contains the remaining message
return (matches.group(1), matches.group(2).strip()) if matches else (None, None)
def handle_command(command, channel):
"""
Executes bot command if the command is known
"""
# Default response is help text for the user
default_response = "Not sure what you mean. Try *{}*.".format(EXAMPLE_COMMAND)
# Implemented below code-snippet for making API call to ChatBot
input_text = command
payload = {"text": input_text, "email": "manmohan#m******.com"}
headers = {'content-type': "application/json"}
resp = requests.request("POST", url, json=payload, headers=headers)
result = eval(resp.json())
print("result is: ", result)
response = result['text']
# Sends the response back to the channel
slack_client.api_call(
"chat.postMessage",
channel=channel,
text=response or default_response
)
if __name__ == "__main__":
if slack_client.rtm_connect(with_team_state=False):
print("Starter Bot connected and running!")
# Read bot's user ID by calling Web API method `auth.test`
starterbot_id = slack_client.api_call("auth.test")["user_id"]
while True:
command, channel = parse_bot_commands(slack_client.rtm_read())
if command:
handle_command(command, channel)
time.sleep(RTM_READ_DELAY)
else:
print("Connection failed. Exception traceback printed above.")

Send messages to telegram group without user input

I'm trying to build a bot which automatically sends a message whenever there is an update in the latest news using python. Following is what I did.
companies = {
"name_1": {
"rss": "name_1 rss link",
"link": "name_1 link"
}
}
import feedparser as fp
import time, telebot
token = <TOKEN>
bot = telebot.TeleBot(token)
LIMIT = 1
while True:
def get_news():
count = 1
news = []
for company, value in companies.items():
count = 1
if 'rss' in value:
d = fp.parse(value['rss'])
for entry in d.entries:
if hasattr(entry, 'published'):
if count > LIMIT:
break
news.append(entry.link)
count = count + 1
return (news)
val = get_news()
time.sleep(10)
val2 = get_news()
try:
if val[0]!=val2[0]:
bot.send_message(chat_id= "Hardcoded chat_id", text=val2[0])
except Exception:
pass
How can I update my code so that the bot publishes the latest news to all the groups to which it is added?
I got the chat_id using:
bot.get_updates()[-1].message.chat.id
Any suggestions on how to automate this?
Using the python-telegram-bot api, you can send a message like this
bot.send_message(id, text='Message')
you need the "bot" and "id"
I keep these in a dictionary called "mybots" which I fill/update when people interact with the bot for the first time / or on later communication with the bot. It's possible to pickle this dictionary to keep it persistant.
mybots = {}
def start(bot, update):
"""Send a message when the command /start is issued."""
mybots[update.message.chat_id] = bot
update.message.reply_text('Hello{}!'.format(
update.effective_chat.first_name))
def send_later():
for id, bot in mybots.items():
bot.send_message(id, text='Beep!')
In short, you can use sendMessage() to send message to a specific group or user.
bot.sendMessage(chat_id=chat_id, text=msg)
the complete code,
import telegram
#token that can be generated talking with #BotFather on telegram
my_token = ''
def send(msg, chat_id, token=my_token):
"""
Send a message to a telegram user or group specified on chatId
chat_id must be a number!
"""
bot = telegram.Bot(token=token)
bot.sendMessage(chat_id=chat_id, text=msg)

Resources