How to restrict the acess to a few users in pyTelegramBotAPI? - python

I'm using telebot (https://github.com/eternnoir/pyTelegramBotAPI) to create a bot to send photos to its users. The point is I didn't see a way to restrict the access to this bot as I intend to share private images through this bot.
I read in this forum that through python-telegram-bot there is a way to limit the access from the sender's message (How To Limit Access To A Telegram Bot), but I didn't know if via pyTelegramBotAPI it is possible.
Do you know how can I solve it?

A bit late tot the party - perhaps for future post readers. You can wrap the function to disallow access.
An example below:
from functools import wraps
def is_known_username(username):
'''
Returns a boolean if the username is known in the user-list.
'''
known_usernames = ['username1', 'username2']
return username in known_usernames
def private_access():
"""
Restrict access to the command to users allowed by the is_known_username function.
"""
def deco_restrict(f):
#wraps(f)
def f_restrict(message, *args, **kwargs):
username = message.from_user.username
if is_known_username(username):
return f(message, *args, **kwargs)
else:
bot.reply_to(message, text='Who are you? Keep on walking...')
return f_restrict # true decorator
return deco_restrict
Then where you are handling commands you can restrict access to the command like this:
#bot.message_handler(commands=['start'])
#private_access()
def send_welcome(message):
bot.reply_to(message, "Hi and welcome")
Keep in mind, order matters. First the message-handler and then your custom decorator - or it will not work.

The easiest way is probably a hard coded check on the user id.
# The allowed user id
my_user_id = '12345678'
# Handle command
#bot.message_handler(commands=['picture'])
def send_picture(message):
# Get user id from message
to_check_id = message.message_id
if my_user_id = to_check_id:
response_message = 'Pretty picture'
else:
response_message = 'Sorry, this is a private bot!'
# Send response message
bot.reply_to(message, response_message)

Related

How to send/receive message from facebook messenger in python

I want to make a "Auto-Reply" on Facebook Messenger using python but I don't know how to do it
If it's possible, can you share the code?
If you use the fbchat library, you can do something like below (the example is from the docs, and just replies back with the same message)
from fbchat import log, Client
# Subclass fbchat.Client and override required methods
class EchoBot(Client):
def onMessage(self, author_id, message_object, thread_id, thread_type, **kwargs):
self.markAsDelivered(thread_id, message_object.uid)
self.markAsRead(thread_id)
log.info("{} from {} in {}".format(message_object, thread_id, thread_type.name))
# If you're not the author, echo
if author_id != self.uid:
self.send(message_object, thread_id=thread_id, thread_type=thread_type)
client = EchoBot("<email>", "<password>")
client.listen()

How to send a random string via Inline Telegram commands?

I have created a bot (using python-telegram-bot) that upon choosing a type of query, the bot should randomly choose one of the available strings as the reply.
My function to create replies is as follows:
def generate_reply():
replies = """
Hello
Goodbye
Thanks!
Your welcome!
See you around!""".splitlines()
r = random.choice(replies).strip()
return r
And the functions to reply to the users are as follows:
#Inline Reply
def inlinequery(update, context):
query = update.inline_query.query
results = [InlineQueryResultArticle(id=uuid4(), title="Interact",
input_message_content=InputTextMessageContent(
generate_reply()))]
update.inline_query.answer(results)
#Normal reply
def reply(update, context):
update.message.reply_text(generate_reply())
And after creating the bot I add it to the bot using:
dp.add_handler(CommandHandler("reply", reply))
dp.add_handler(InlineQueryHandler(inlinequery))
when I use /reply in chat it works as intended, but wherever I use an inline command in a chat with another user or a group, the random choice apparently stops working.How can I get around this problem?
I found out the answer to my question. Apparently Telegram caches the answers to similar inline queries for some time. For this to work correctly you should set cache_time to something you'd like, in my case 0.
#Inline Reply
def inlinequery(update, context):
query = update.inline_query.query
results = [InlineQueryResultArticle(id=uuid4(), title="Interact",
input_message_content=InputTextMessageContent(
generate_reply()))]
update.inline_query.answer(results, cache_time=0)

How to do a "typing_on" post with pymessenger to FB messenger?

I'm trying to set my chatbot to display a typing bubble before sending the user the response so that it's more human like. I followed the documentation but am still getting instant responses from the bot with no typing bubble. As per the documentation I am using this sender action:
{"recipient":{"id":recipient_id}, "sender_action":"typing_on"}
And to put it in context, here is how I'm using it in the flask app:
#app.route('/', methods=['GET', 'POST'])
def receive_message():
global tag, latest_message
if request.method == 'GET':
# Before allowing people to message your bot Facebook has implemented a verify token
# that confirms all requests that your bot receives came from Facebook.
token_sent = request.args.get("hub.verify_token")
return verify_fb_token(token_sent)
# If the request was not GET, it must be POSTand we can just proceed with sending a message
# back to user
else:
# get whatever message a user sent the bot
output = request.get_json()
for event in output['entry']:
messaging = event['messaging']
for message in messaging:
if message.get('message'):
# Facebook Messenger ID for user so we know where to send response back to
recipient_id = message['sender']['id']
if message['message'].get('text'):
response_sent_text = send(message['message'].get('text'))
send_message(recipient_id, response_sent_text)
latest_message = response_sent_text
return "Message Processed"
def send_message(recipient_id, response):
# sends user the text message provided via input response parameter
typing_payload = {"recipient":{"id":recipient_id}, "sender_action":"typing_on"}
bot.send_raw(typing_payload)
print(bot.send_raw(typing_payload))
bot.send_text_message(recipient_id, response)
return "success"
Any ideas would be much appreciated!
You should pass a string representation of the payload (not a dictionary).
try doing something like this:
import json
...
def send_message(recipient_id, response):
# sends user the text message provided via input response parameter
typing_payload = json.dumps({"recipient":{"id":recipient_id}, "sender_action":"typing_on"})
bot.send_raw(typing_payload)
print(bot.send_raw(typing_payload))
bot.send_text_message(recipient_id, response)
return "success"
Also it's best practice to send these indicators upon receiving message (to show the typing indicator while processing), as opposed to directly before sending message.

Can subclasses (not using inheritance) have it's creator reference?

I don't know how to exactly write a title for this, so let me explain my problem. I'm using Python 3 to implement a bot on Slack, but my doubt is about how classes can be used to solve it.
I'm using Slack's API to create a bot to send messages. When you use the API to send a message, it returns some parameters that indentifies this message (like an id). With this "id" I can change the message's text or delete it, for example.
I created a main class that will be used to handle the API requests and therefore, send messages. I also have another class called SlackMessage that keeps the message's "id" and will have some methods, like change it's text or delete itself, for example. So, when I send a message through the main class, an instance of SlackMessage class will be returned.
As the first class is handling the requests to the API, the SlackMessage class should use it when changing it's text. Would be right the SlackMessage class have the main class as reference when it's being created and use it to update itself?
Here's some code to explain what I mean:
class Slack:
def __init__(self, token):
self._token = token
def send_message(self, message):
result = requests.post(...)
#Get message's reference
ts = result["ts"]
channel = result["channel"]
text = result["text"]
reference = {"ts": ts, "channel": channel, "text": text}
return SlackMessage(self, reference)
def update_message(self, message_reference):
result = requests.post(...)
class SlackMessage:
def __init__(self, slack_client, reference):
self._slack_client = slack_client
self._reference = reference
def change_text(self, text):
self._reference["text"] = text
self._slack_client.update_message(self._reference)
And how would be the best method to create a way to delete the message? Should I do it the same way?
Sorry if this question is a duplicate, I searched for an answer but didn't know how to explain the problem with a few words.

Python twisted irc: Wait for a whois reply inside privmsg method

I'm trying to make an IRC bot using the twisted.words.protocols.irc module.
The bot will parse messages from a channel and parse them for command strings.
Everything works fine except when I need the bot to identify a nick by sending a whois command. The whois reply will not be handled until the privmsg method (the method from which I'm doing the parsing) returns.
example:
from twisted.words.protocols import irc
class MyBot(irc.IRClient):
..........
def privmsg(self, user, channel, msg):
"""This method is called when the client recieves a message"""
if msg.startswith(':whois '):
nick = msg.split()[1]
self.whois(nick)
print(self.whoislist)
def irc_RPL_WHOISCHANNELS(self, prefix, params):
"""This method is called when the client recieves a reply for whois"""
self.whoislist[prefix] = params
Is there a way to somehow make the bot wait for a reply after self.whois(nick)?
Perhaps use a thread (I don't have any experience with those).
Deferred is a core concept in Twisted, you must be familiar with it to use Twisted.
Basically, your whois checking function should return a Deferred that will be fired when you receive whois-reply.
I managed to fix this by running all handler methods as threads, and then setting a field, following
kirelagin's suggestion, before running a whois query, and modifying the method that recieves the data
to change the field when it recieves a reply. Its not the most elegant solution but it works.
Modified code:
class MyBot(irc.IRClient):
..........
def privmsg(self, user, channel, msg):
"""This method is called when the client recieves a message"""
if msg.startswith(':whois '):
nick = msg.split()[1]
self.whois_status = 'REQUEST'
self.whois(nick)
while not self.whois_status == 'ACK':
sleep(1)
print(self.whoislist)
def irc_RPL_WHOISCHANNELS(self, prefix, params):
"""This method is called when the client recieves a reply for whois"""
self.whoislist[prefix] = params
def handleCommand(self, command, prefix, params):
"""Determine the function to call for the given command and call
it with the given arguments.
"""
method = getattr(self, "irc_%s" % command, None)
try:
# all handler methods are now threaded.
if method is not None:
thread.start_new_thread(method, (prefix, params))
else:
thread.start_new_thread(self.irc_unknown, (prefix, command, params))
except:
irc.log.deferr()
def irc_RPL_WHOISCHANNELS(self, prefix, params):
"""docstring for irc_RPL_WHOISCHANNELS"""
self.whoislist[prefix] = params
def irc_RPL_ENDOFWHOIS(self, prefix, params):
self.whois_status = 'ACK'

Categories