How to send a message to google hangouts with python? - google-api

I am trying to create a simple "chat bot" for google hangouts that sends regular messages on a chat. I found this documentation but I find it tremendously complicated.
It contains a "Complete example" but I am not sure about how to find the "space" ID for an existing google hangout chat. This is nowhere explained. How do I find the "space" ID for an existing google chat?
And in addition: Is there a SIMPLE (!!!) documentation somewhere how to just simply post a message to an existing chat?

Answer:
You can either use spaces.list to get a list of spaces the bot is a member of followed by spaces.get for additional information on the space, or alternatively set up a room-specific Webhook.
Additional Information:
To send messages to a room without a respond trigger, you must use a service account
Bot-initiated message documentation can be found here.
Important Note: You can only use the Google Hangouts Chat API if you have a Google Workspace account - it will not work with Gmail alone. The second solution, which uses a Webhook, requires access to https://chat.google.com which is only available to Google Workspace domains. Unfortunately this is not at all possible using a consumer #gmail.com account.
Using the Hangouts Chat API:
Once you have a service account set up as per Step 1 on this page, you can download the credentials for the service account from the Google Cloud Project UI, by clicking on the ⋮ button to the right of the service account name, and following the Create key button and selecting JSON as the key type. Make sure to save this file well as there is only one copy of this key.
With this JSON file downloaded, you can use it in your python code as the credentials when setting up your service object:
from httplib2 import Http
from oauth2client.service_account import ServiceAccountCredentials
from apiclient.discovery import build
scopes = 'https://www.googleapis.com/auth/chat.bot'
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'credentials.json', scopes)
chat_service = build('chat', 'v1', http=credentials.authorize(Http()))
To make the spaces.list request, you can use this newly built chat_service, and extract hte list of spaces from the response:
def extract(n):
return n['name']
spaces_list = chat_service.spaces().list().execute()
all_spaces = map(extract, spaces_list['spaces'])
You can then use one of these spaces to send a message from the python program:
response = chat_service.spaces().messages().create(
parent=all_spaces[0],
body={'text': 'Test message'}).execute()
print(response)
Things to Remember:
Make sure the Hangouts Chat API is enabled for your project at https://console.cloud.google.com
Once enabled, make sure the bot is configured with a name, logo and description.
The Connection settings for the bot must also be set up; the method is not so important; you can for example choose Apps Script project and enter the deployment ID for an empty deployed project.
Using a Webhook:
Instead of directly using the API, you can instead set up a webhook for a specific chat and with a hardcoded URL, you can send messages to a room from an external script.
The full steps are set out on this page but I'll go through it here also.
Go to the room to which you wish to send a message at https://chat.google.com, and from the dropdown menu next to the room's name, select Manage Webhooks.
Enter a name and an optional avatar for your bot, and press SAVE. This will give you a webhook URL to use in your python script.
Locally, make sure you have httplib2 installed in your environment, and copy the following script into a new .py file:
from json import dumps
from httplib2 import Http
def main():
"""Hangouts Chat incoming webhook quickstart."""
url = 'webhook-url'
bot_message = {
'text' : 'Hello from a Python script!'}
message_headers = {'Content-Type': 'application/json; charset=UTF-8'}
http_obj = Http()
response = http_obj.request(
uri=url,
method='POST',
headers=message_headers,
body=dumps(bot_message),
)
print(response)
if __name__ == '__main__':
main()
Manking sure to replace the webhook-url string with the webhook provided in the Chat UI in the previous step.
Now you can just save the file and run it - this will send a message automatically to the aforementioned chat space:
References:
Creating new bots | Google Chat API | Google Developers
Method: spaces.list | Google Chat API | Google Developers
Method: spaces.get | Google Chat API | Google Developers
REST Resource: spaces | Google Chat API | Google Developers

See this API, it's very interesting:
https://pypi.org/project/hangups/
There is some projects who uses Hangups, among then, HangupsBot:
https://github.com/xmikos/hangupsbot

Related

How to use Google Oauth2.0 to authenticate user via Telegram Bot

This is my first time interacting with Google API and I'm using python3.9 with this library Python Telegram Bot
I want to access a user Google API Calendar via a telegram bot and I can't seem to find any article to guide me through it. My key problem (I think) is redirecting the success authorization flow back to telegram bot.
This is what I have in mind:
In the telegram app, user send '/send' to bot
Bot receive message and return a google an authorization link to user
User clink on authorization link and allow access
Bot receive authorization access and completes the Oauth flow
The problem lies betweeen step 3 and 4. A standard authorization link is
https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=<clientid>&redirect_uri=<redirect_uri>&scope=<scope>&state<state>&access_type=offline
How do I send the authorization link back to my telegram bot? Should I create another API endpoint to receive that authorization link? Or can I send telegram api send_message() in the <redirect_uri> to redirect the success message to my bot.
Update 1
Thanks to CallMeStag, I manage to figure out a way to complete the oauth process. For people who faced the same problem, this is what I did
Pre-requisite: Credentials is created in google console api - Web application. redirect_uri set as localhost:8000 (During development phase)
User send '/send' to bot
Bot receive message and return an authorization link https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=<clientid>&redirect_uri=http://localhost:8000/&scope=<scope>&state<state>&access_type=offline
User click on link to authenticate and it will redirect to http://localhost:8000. Used fastapi as a webhook to receive the message. Capture the authorization code, use google.oauthlib.flow to complete the authorization process. Next, redirect user back to telegram link https://t.me/<botname>
Start using user google calendar
It's currently indeed not very straight forward for a PTB-application to listen for external updates (the auth verification in this cas) - see also this issue. Currently it might be easiest for you to set up a custom webhook application that runs in parallel to the Updater - e.g. using flask/django/starlette/fastapi/…. Alternatively, if you're using webhooks for your bot anyway, you can patch the Updater to do the job for you. Although that requires some manual work - see here for an example.
Once you are able to listen to updates coming from Google, handling them can be done via PTBs usual handler setup, specifically via the TypeHandler or even a custom Handler subclass - see this FAQ entry.
Regarding the redirect url: You'll want to redirect your user back to your bot, so you'll have to provide a link that does that. Bot.link should probably do the trick.
Disclaimer: I'm currently the maintainer of python-telegram-bot.

Google Meet integration api (like Hangouts app for Slack)

I want to utilise Google Meet api, which is used in Hangouts integration for Slack, description follows
TL;DR:
Links such as https://meet.google.com/new?gid=123&gd=qwe987 can be generated, so a modal is shown which can ask user's confirmation and then some request is sent from user's browser (where the Google Meet page is opened) to some endpoint (probably it is determined from gid which seems to be google application id). Is there a way to configure my application to have a webhook, so I can generate these custom links?
There's Google+ Hangouts app for Slack. Here's how it works (after you add the app in your workspace):
you send /hangout command in any Slack channel
slackbot sends an "Only visible to you" message in this channel with a link to start a new hangout. it looks smth like this (I changed data in the link): https://meet.google.com/new?gid=691521906844&gd=THTJ30X6W%7CU01113BD13M%7CD01113BDB5Z%7Csuren%7C%7C1846381238693%7C1%7CB01QFGG5GJF%7CE1MDm4DWcuVa0RbN5ZT9o5KF
when you visit the link, a new meeting is started instantly, and the page shows modal with text "To bring others into this video call, post a link it to your Slack channel" with buttons 'Cancel' and 'Post'.
when you click 'Post', a new message is sent to the Slack channel, where the command was sent. Text is "#Suren Khorenyan has started a Google+ Hangout and would like you to join. Join Hangout." and contains a link to the meet, which was created previously
How can I utilise this integration for another app, like Mattermost (or anything else like Telegram chats via bots)?
As I see, data in the url slightly changes. Probably it's payload for Google Meet to trigger Slack to send a message with link to the channel.
gid seems to be something like google app id
gd seems to be something like google data. If I url-decode it, it becomes THTJ30X6W|U01113BD13M|D01113BDB5Z|suren||1846381238693|1|B01QFGG5GJF|E1MDm4DWcuVa0RbN5ZT9o5KF. This is some kind of payload, separated by pipes (obviously), but I don't know what any part of this means (suren is my username in the Slack workspace, probably this is used for creating an invitation message).
When I click Post, this happens:
a new POST request to https://hooks.slack.com/services/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 is sent with form-data
hangout_id: 1812381238693
hangout_url: https://meet.google.com//abc-iuqx-def
a new message is posted to the Slack channel
Google meet somehow knows where to post back! Is this configured at the Google application (application id is provided via gid)? How can I configure my application for such behaviour? Where can I setup webhook url?
If we breakdown the request, we can see that url contains some parts of the gd payload:
THTJ27X6W - this is the first part of the gd payload
B01ABCD5GJF - last but one
E1MDm4DWcuVa0RbK5ZT9o5KD - the last part of the gd payload
and form-data contains:
hangout_id - this is in the gd payload after my name
hangout_url - obviously, this is the url for the new created meeting
How can I change it for my needs?
I created a new application at Google APIs dashboard (here console.developers.google.com/apis), but can't find any docs for this integration. There's Google+ Hangouts API in API Library, but it says Apps will continue to function until April 25, 2017..
I tried to approach it from another side:
In the API Library there's Google Calendar. I found mattermost-hangout app on GitHub (had to update it a bit, so it works with updated api). Here's how it works:
oauth2 for authorising at google (single account)
it handles POST request, which is meant to be received from Mattermost (triggered by a slash command),
creates a new calendar event using Google Calendar API (with conference),
takes hangouts url from the response and sends a new message in the Mattermost channel with invitation to join the meeting.
But it has some downsides:
you have to use one account to authorise all event creation events (yeah, it can be upgraded to authorise any number of users, but it'll be inconvenient. why to force anyone to provide access to their Google Account, when Google Meet authorisation just happens in browser, we don't need to create events)
account, used for auth, now has events in his calendar. of course, events can be deleted, but it's not the way.
Is there any documentation on utilising gid and gd params?
Generally, I want to find a way to configure a webhook in my app, so when Google Meet finds my application's ID in the gid query param, it looks at the app's config and sends a request to my app (previously configured endpoint (I assume it works this way)).
Of course there's a chance that it's some kind of internal API and it cannot be used by everyone, but I could not find any information on this.

MS Teams Messaging Extension submitTask failing with "v3 agent not found" error

I'm creating my first Microsoft Teams extension. For now I'm just trying to get the basic plumbing for a messaging extension working. I'm trying to build an extension which will allow a user to search for content in my service and then return a card into their compose window in personal and Teams chats.
I've tried to follow the basic guide ( https://learn.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/create-messaging-extension ) for creating a messaging extension using App Studio. I've setup a bot as it describes, and I have built a dummy echobot endpoint for the bot (using Ruby). I am able to "chat" with my bot directly in the Teams client and it is able to respond.
My messaging extension defines an action based command with a taskInfo with a web view URL to render and a fetchTask set to false. I've written a basic static HTML page for this and included the teams-js library. The web view loads and the teams-js library initialization callback is called. I have a submit button which calls microsoftTeams.tasks.submitTask which as I understand it, should be calling my bot with a "composeExtension/submitAction" message to which I would respond with the card. (Based on https://learn.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/action-commands/respond-to-task-module-submit?tabs=json )
I've tried installing my extension in Teams through the "Upload a custom app" option both as a "for me and my teams" and "for " but still have the following issues.
When I open my extension in the Teams client from the compose area and click this submit button in my iframe content, the submit I get a "Unable to reach app. Please try again" error displayed. In the dev console, I can see that the response to the "invoke" http post is {"errorCode":404,"message":"V3 agent not found."}
No traffic is actually sent to my bot during any of this process.
I saw this older post - Compose extension is throwing error : V3 agent not found . The https://dev.botframework.com/bots/ it refers to seems to be outdated, but in the Azure "Bot Channels Registration" console, I have gone to Channels and added "Microsoft Teams" (which I believe is the new equivalent).
Has anyone seen this happen and figured out what was going on? Much thanks!
Here is sample code for composeExtension/submitAction for Bot SDK V3. Make sure you pass the bot id and command text in taskInfo object.
case "composeExtension/submitAction":
string commandid = JsonConvert.DeserializeObject<Models.TaskModuleSubmitData<string>>(activityValue).commandId;
taskInfo = GetTaskInfo(commandid);
taskEnvelope = new Models.TaskEnvelope
{
Task = new Models.Task()
{
Type = Models.TaskType.Continue,
TaskInfo = taskInfo
}
};
return Request.CreateResponse(HttpStatusCode.OK, taskEnvelope);
Hilton had the right answer.
I had grabbed the Subscription ID from the Bot Channels Registration page instead of the App ID from the Azure Active Directory -> Apps Registration page and used that in the messaging extension manifest as the "botId" in the composeExtensions array. After fixing that I'm now getting messages submitted to my bot backend.

How to message a user in a slack App via API?

When creating a slack app, it creates a new "channel" in the left hand menu. I want to be able to send a message to specific users and not to all users in a workspace who have integrated with the app.
For example, if I make the following request:
curl -X POST -H 'Content-type: application/json' --data '{"text":"Hello, World!"}' https://hooks.slack.com/services/ABxxx/CDxxx/EFxxxxxx
It will send a message to all users who have integrated with my app with the text "Hello World".
But I only want to send a message to user A without User B being notified.
I don't want to message a user directly and it to appear to come from slack bot. I want the message to appear to come from my bot / app.
How can this be achieved via slack API?
I found this quite hard to explain so please let me know if you'd like me to clarify anything.
The problem of your request that you are using a hook URL which is bound to a particular channel (you pick it during Slack App installation).
To send a direct message to the user on behalf of your bot, you need to consider the following things (this is not the single way to achieve it, but works for me):
Ensure you have a bot registered for your Slack App.
Ask for bot and chat:write:bot permissions during App installation process (example for Slack Install button and here).
Store the bot access token on successful installation (see for details).
Now using the bot access token you can send Slack API requests.
To achieve what you need, use chat.postMessage API method. channel argument can be user ID (e.g. U0G9QF9C6). By setting up as_user argument to true, your message will be always sent on behalf (name and icon) of your bot (seems for bot tokens it's always like this, but it's recommend it to specify it explicitly).
Hope it helps. Feel free to ask for details.

Slack api: files.upload to user channel and display as bot-user?

I am trying to create a slack command that takes params, generate image and return and image back to user, also the image upload should display as the bot user.
I follow this post: Can you upload a file to the Slack API using files.upload as a different user?
I tried creating slack app, a bot user according to it, and slack file upload api as follows:
def send_picture(channel_id, graph_details):
sender_token = "xoxb-..." # bot-user token
pic = {
'file' : ('img.png', open('img.png', 'rb'), 'png')
}
payload={
"title" : "Serverless App Report",
"channels" : [channel_id]
}
r = requests.post("https://slack.com/api/files.upload", params=payload, files=pic)
Whenever the user do the slack command(POST with params), I can parse the channel_id to find out the sender and pass it into the channel_id into the file upload api.
Posting it into public channel is working fine. But posting it back to the user who do the command failed with the error: {"ok":false,"error":"invalid_channel","channel":"DXXXXXXX"}
The reason you get this error is that your bot user is apparently not a member of the private channel in which the user invoked your slash command. Therefore your app can not upload any files to it. This normal behavior and part of Slack's security architecture.
There are 3 workarounds for this issue:
You can make sure the bot user from your Slack app is added as member to all private channels where your slash command needs to work
You can request every user to "install" your Slack app once. Thereby providing your app with a user specific Slack token which your app can then use to access the private channel.
You can refrain from uploading files and instead reply with a message, which can include images too. A Slack app can always reply to a Slash command, no matter in which kind of channel it is issued.

Resources