Telegram Webhook doesn't send text from Group Chats - python

I am running a Telegram bot using Webhooks that queries an AWS Lambda function. In a private conversation with just the bot, it functions as expected. In group chats however, the bot fails to respond. In particular, when receiving updates from a group, the Message object is missing the text field (i.e. there is no text associated with messages from group chats).
Here is what I have tried:
Setting privacy mode to disabled (such that the bot can access all messages in groups)
Giving the bot admin privileges
Removing and adding the bot after doing the above
Deleting and recreating a whole new bot after doing the above
Deleting and setting a webhook
Here is the lambda code (it simply echos back whatever it receives):
import requests
import json
def lambda_handler(event, context):
# get the request body from API gateway
body = json.loads(event['body'])
token = 'my secret token'
URL = "https://api.telegram.org/bot{}/".format(token)
chat_id = body['message']['chat']['id']
# This if statement is triggered for EVERY group chat message the bot receives
# which is the error I'm trying to debug
if 'text' not in body['message']:
return { 'statusCode': 500 }
# this only works for direct messages
message = body['message']['text']
send_url = URL + "sendMessage?text={}&chat_id={}".format(message, chat_id)
requests.get(send_url)
response = {
"statusCode": 200
};
return response
Here is what the Message object looks like when received from a group chat (notice that it doesn't have a text field:
{
"message_id":27,
"from":{
"id":id_number,
"is_bot":False,
"first_name":"Jafer",
"last_name":"",
"username":"username",
"language_code":"en"
},
"chat":{
"id":-id_number,
"title":"test",
"type":"group",
"all_members_are_administrators":True
},
"date":1603138229,
"group_chat_created":True
}
Here are some of the resources on stackoverflow that I've already looked at:
Allow bot to access Telegram Group messages
python telegram bot(Telepot) group chat
Since I'm trying to run the bot in a serverless environment, I cannot use a polling mechanism as suggested here: Telegram Bot - how to get a group chat id?
I would very much appreciate some help understanding why my bot struggles with group chats! Thank you!

Your dumped response has "group_chat_created":True and it is a service message which normally doesn't have any text. This messages is created when a group is created (the first message of the group).
Docs says,
Field
Type
Description
group_chat_created
True
Optional. Service message: the group has been created
Your bot only receives this type of message if you create the group by adding the bot as a member first (i.e. when the bot is a member of the group when it is created.) Now, by default bot will not read the text messages, so, you can promote the bot as an admin to read the text messages.
As an example, if I create a group with a bot,
{
"update_id": 989846...,
"message": {
"message_id": 15,
"from": {
"id": 1521565...,
"is_bot": false,
"first_name": "me",
"username": "abc...",
"language_code": "en"
},
"chat": {
"id": -560877...,
"title": "MeAndMyBot...",
"type": "group",
"all_members_are_administrators": true
},
"date": 1614624584,
"group_chat_created": true
}
}
And you can see that,
Now give the appropriate permissions (e.g.: Admin privileges) to access text messages,
Then we can get updates like,
{
"update_id": 989846...,
"message": {
"message_id": 16,
"from": {
"id": 1521565...,
"is_bot": false,
"first_name": "me",
"username": "abc...",
"language_code": "en"
},
"chat": {
"id": -560877...,
"title": "MeAndMyBot...",
"type": "group",
"all_members_are_administrators": true
},
"date": 1614625333,
"text": "Hello there"
}
}

Related

Reading body of Slack event using python-slackclient

I'm trying to create a serverless slack bot in AWS Lambda. I managed to get the app to send a message to a user in Slack with an interactive button, which sends a post back to the app when clicked. The problem is that the body of this message (the one from the button click) has the body of the JSON all garbled. Here is a reduced version of the garble:
'body': 'cGF5bG9hZD0lN0IlMjJ0eXBlJTIyJTNBJTIyYmxvY2tfYWN0aW9...
The rest of the JSON object looks normal.
On the other hand, the button object I'm sending to slack is this one:
{
"type": "button",
"text": {
"type": "plain_text",
"emoji": True,
"text": "Yes"
},
"style": "primary",
"value": "click_me_123"
},
What am I missing? Appreciate all the help I can get!
Solution: It was that the body of the response, it was encoded in Base64, so I had to decode that with:
base64.b64decode('encoded_string').decode('utf-8')

How to publish a View to Slack app for all users?

I have a Slack App that is connected to an AWS Lex bot. Thus, the Request URL for the Slack app is the Postback URL provided by Lex. However, I want to add a Home tab for the app, but am unable to publish a surface for all users. The Slack API only seems to allow you to publish a surface for a specific user (user_id is a required parameter for the POST call). How can I publish this view to all users who use the app?
publish_url = "https://slack.com/api/views.publish"
header = {'content-type':'application/json'}
parameters = {
"token": slack_token,
"user_id": member_id, # <--- This is my problem
"view": json.dumps({
"type": "home",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Welcome to *Survey Analyzer*! ..."
}
},
...
]
})
}
r = requests.post(publish_url, params=parameters, headers=header)
When I use my own member ID, it pushes the view properly to me and me only. I've also tried using the app's ID, but that doesn't seem to push the view to any users.
You can only publish a home tab for each user separately. You can use users.list to retrieve all users of a workspace and then call views.publish for each user in that list.
Alternatively you can subscribe to the app_home_opened event through the Events API. Once a user opens the home tab it will fire an event including the user's id. That way you'll only publish a view for a user who is actually visiting the home tab of your app.

Slack Bot | Get datepicker value

I'm trying to create my first slack bot with python.
I need your help to explain how I can get the value of the datepicker.
This is my code :
import os
from slack import WebClient
from slack.errors import SlackApiError
import time
client = WebClient(token=os.environ['SLACK_KEY'])
message = "Hey ! Pourrais-tu saisir la date de tes congés ce mois-ci ?"
attachments = [{
"blocks": [
{
"type": "actions",
"elements": [
{
"type": "datepicker",
"initial_date": "1990-04-28",
"placeholder": {
"type": "plain_text",
"text": "Select a date",
}
},
{
"type": "datepicker",
"initial_date": "1990-04-28",
"placeholder": {
"type": "plain_text",
"text": "Select a date",
}
}
]
}
]
}]
def list_users():
users_call = client.api_call("users.list")
if users_call.get('ok'):
return users_call['members']
return None
def send_message(userid):
response = client.chat_postMessage(channel=userid, text=message, username='groupadamin', attachments=attachments)
if __name__ == '__main__':
users = list_users()
if users:
for u in users:
send_message(u['id'])
print("Success!")
My bot sends a private message to all users of the slack. I want to get every one of their answers of the datepicker.
If you want more details, ask me.
In general, you need to be listening to the action.
When the use clicks the datetimepicker, a so-called interaction-payload will be sent to your python slackbot.
That payload is documented here https://api.slack.com/reference/interaction-payloads/block-actions ; you can see you can get the picked date's value by accessing actions.value.
In particular for your use case, given your code sample, it seems you've just built a script that can send messages. This will not allow you to listen to actions. You need rather a python service (an API) that can send as well as receive messages.
For this, I suggest having a look at bolt which is a slack maintained library that will take care of a lot of the heavy lifting for you. Specifically, regarding actions you can check https://slack.dev/bolt-python/concepts#action-listening

Adding attachements to slacker chat message

I'm trying to post a message using slacker python api for Slack messages
I'm not able to attach a link to my messages as my code below :
attachments = [title, link_to_events, "More details"]
print type(attachments) # this is a list
slack = Slacker(slack_api_token)
# Send a message to #general channel
slack.chat.post_message(slack_channel, message, attachments=attachments)
In the slacker code, it looks like we are looking for a "list" type of variable:
https://github.com/os/slacker/blob/master/slacker/init.py
line 241:
# Ensure attachments are json encoded
if attachments:
if isinstance(attachments, list):
attachments = json.dumps(attachments)
return self.post('chat.postMessage',
data={
'channel': channel,
'text': text,
'username': username,
'as_user': as_user,
'parse': parse,
'link_names': link_names,
'attachments': attachments,
'unfurl_links': unfurl_links,
'unfurl_media': unfurl_media,
'icon_url': icon_url,
'icon_emoji': icon_emoji
})
is there a problem with my code ?
fyi : this is what i've found in the slack api documentation https://api.slack.com/custom-integrations :
{
"text": "New Help Ticket Received:",
"attachments": [
{
"title": "App hangs on reboot",
"title_link": "http://domain.com/ticket/123456",
"text": "If I restart my computer without quitting your app, it stops the reboot sequence.\nhttp://domain.com/ticket/123456",
}
]
}
All right i've found it,
I need a list of dicts
one_attachement = {
"title": "App hangs on reboot",
"title_link": "http://example.com/ticket/123456",
"text": "If I restart my computer without quitting your app, it stops the reboot sequence.\nhttp://example.com/ticket/123456",
}
attachements = [one_attachement]
slack.chat.post_message(slack_channel, message, attachments=attachments)

Python facebook-sdk: retrieving names of users who posted a message on a page

I want to use the Python facebook-sdk library to retrieve the names of the persons who posted a message on a Facebook page I created.
This is an example, returned by the Graph API explorer:
{
"feed": {
"data": [
{
"from": {
"name": "Ralph Crützen",
"id": "440590514975673"
},
"message": "Nog een test.",
"created_time": "2015-10-17T19:33:30+0000",
"id": "649463214822976_649745285127205"
},
{
"from": {
"name": "Ralph Crützen",
"id": "440590514975673"
},
"message": "Testing!",
"created_time": "2015-10-16T20:44:17+0000",
"id": "649463214822976_649492455153388"
},
... etc ...
But when I use the following Python code...
graph = facebook.GraphAPI(page_access_token)
profile = graph.get_object('tinkerlicht')
posts = graph.get_connections(profile['id'], 'feed')
print(posts['data'][0]['message'])
print(posts['data'][0]['from']['name'])
...only the message value is printed. Printing the name of the person who posted the message gives the error:
print(posts['data'][0]['from']['name'])
KeyError: 'from'
At first, I thought that I needed the read_page_mailboxes permission. To use this permission, it has to be approved by Facebook, so I submitted a request. But Facebook replied:
"You don't need any additional permissions to post to Pages or blogs that you administer. You only need to submit your app for review if your app will use a public-facing login."
So what exactly is the reason I can't retrieve the from data from the messages feed? (While reading it from the Graph API explorer works fine...)
Btw, I'm using a page access token which never expires. I generated this token the way it's described here.

Categories