How to configure Google Workspace Alert Center to publish alerts to a PubSub topic? - publish-subscribe

I'm building a notification system that will notify employees on slack when they take an action that triggers a DLP Rule.
The ideal flow I'm trying to get at is:
Employee takes action > Rule triggered > Alert is published to PubSub topic > Triggers Cloud function that renders the slack message and sends it to the user.
The point where I'm stuck is having the API alert center to publish the alert the to the PubSub topic.
I have done something like this in the past with the Gmail API, to publish to the topic when an particular account received an email. And there was a watch request to configure the account to publish to the topic.
I looked through the Alert Center API documentation and havenĀ“t found a watch request or anything that does something similar.
Is there a way to achieve this? Or is this just impossible?
I searched through the Google Alert Center API reference and the Alert Center console for any options to configure publishing to a pubsub topic or a webhook.

After a couple of hours of trial and error I found the solution to this.
We have to update the settings by making and updateSetting, and send a settings object in the body.
Here's some python code to do that using a service account with domain wide delegation:
from google.oauth2 import service_account
from googleapiclient.discovery import build
import json
def main():
# Authenticate the service account
scopes = ['https://www.googleapis.com/auth/apps.alerts']
admin_to_impersonate = '******'
credentials = service_account.Credentials.from_service_account_file(
'client_secrets.json', scopes=scopes, subject=admin_to_impersonate
)
# Build the service
service = build('alertcenter', 'v1beta1', credentials=credentials)
settings = {
'notifications': [
{
'cloudPubsubTopic': {
'topicName': '<YOUR TOPIC NAME>',
'payloadFormat': 'JSON'
}
}
]
}
# Execute a updateSetting request
response = service.v1beta1().updateSettings(body=settings).execute()
print(response)
if __name__ == '__main__':
main()

Related

Teams not displaying email sent via SendGrid

I'm trying to post to a Teams channel via the email address using SendGrid. However, the emails I send via SendGrid are not appearing. I ended up adding my personal email address as well, and I do receive that one as well as seeing the Teams email address in the To: field. I can also see in SendGrid dashboard that the email was send and delivered to the Teams channel address. I have validated that this address is correct, and have also posted via my non-work email address to that channel, so I know it's not because of a typo or an external email address. My guess is that there is something in the email meta data that is making Teams reject the email? Anyone have ideas 1) why Teams won't post the email coming from SendGrid and 2) how I might modify my request in SendGrid so that it works? Also, alternative suggestions on sending emails (for free) from nodejs are welcome.
Here is the code I'm using to send the email for reference:
var msg = {
to: ['TEAMSCHANNELID#amer.teams.ms','mycompanyemail#company.com'], // ChatBot Support Team, General Channel
from: 'noreply#chatbotapimonitor.com',
subject: `Service Interruption Notice: API ${test} is down (via ${functionName})`,
text: `API ${test} failed with error ${error}`,
html: `API ${test} failed with error ${error}`
};
try {
await sgMail.send(msg);
} catch (err) {
context.log(err);
}
It turns out that Teams won't accept incoming emails if the From address domain does not match the actual "sent from" domain. I recognized this by the "Sent via sendgrid.net" message I saw in Outlook when the emails were sent to me as well.
I was able to get the out of the box Incoming Webhooks enabled, and using that instead of SendGrid emails got around the problem. I got the URL from the webhook configuration and then was able to call it like so:
var headers = { 'ContentType': 'application/json'}
var body = {
'#context': 'https://schema.org/extensions',
'#type': 'MessageCard',
'themeColor': 'FF0000',
'title':`API ${test} is down: Service Interruption Notice`,
'text': `API ${test} failed with error ${error}.\n\r\n\rReported by ${functionName} during test started on ${now.toString()}`
};
var res = await request({
url: url,
method: 'POST',
headers: headers,
json: body,
rejectUnauthorized: false
});
The themeColor doesn't appear in all channels, but I have it working as a nice red/green indicator on Teams desktop.
Perhaps your organization limits the sending ability to only certain domains? Someone with admin rights can check it under Teams settings => Email integration
yeah that's what I meant - making your own Connector app and side-loading. If you go ahead with it, please let me know - would love to know how it works out
Yes exactly making your own Connector would work.

How to interact with html response from http request in Flutter

I have a Flutter app where I am running a Google Apps Script through an http request. The purpose of the script is to create a Form and link the responses to a spreadsheetID that is passed in. The script is configured to only allow Google accounts access it and I've set up the flutter app to use a Service Account to access the script using the format:
getCredentials().then( (AuthClient client){
response = client.get(url, headers{"Authorization": "Bearer ${client.access_token}");
});
Issue: The issue is that the first time that the Service Account makes a request it will get an HTML response saying that it the account needs to give permission to the script to access its data and I'm not sure how to do that.
I'm fairly new to making http requests and using it with the GoogleAPI so I'm stuck. Any advice?
Goal
Create a web page which anyone can use to submit a Google sheet link and for the app to create a form and link the sheet to that.
Authorization
For this users will require a google account and they will be required to go through the OAuth process to authorize your app.
To create the form and link it from client-side JavaScript you would indeed need to call the Apps Script API, though you cannot do this with a service account.
From: https://developers.google.com/apps-script/api/how-tos/execute
Warning: The Apps Script API doesn't work with service accounts.
Luckily, you don't need a service account to do this.
Instructions
Create an Apps Script project with a function something like:
function createForm(ssID){
form = FormApp.create("Your New Form");
form.setDestination(FormApp.DestinationType.SPREADSHEET, ssID);
let formLink = form.getPublishedUrl();
return formLink;
}
Save and take a note of the ID of the script project.
Set up a GCP project (sounds like you already have one).
Make sure the Apps Script API is enabled in your GCP.
Configure the OAuth consent screen and add the scope - https://www.googleapis.com/auth/forms.
Create an API key and a Client ID - add http://localhost:8000 or whatever port you are testing on to the "Authorized JavaScript Origins"
Create OAuth credentials "web browser (JavaScript)".
Link your Apps Script project to the same GCP project - Instructions
Deploy the Apps Script project as an API executable - take not of the deployment ID, although the documentation says that you need the script ID, it is wrong, at least with the new Apps Script IDE.
Write the client-side JavaScript in your app like what is found in the quickstart. Which will enable users to authorize the app. You need to add in the scopes and keys there too. I recommend just following the quick start steps first to get a feel for it. You can use the authorization parts without modification.
Then add in the function that will call your Apps Script, something like this:
function appsScriptCreateForm(ssId) {
var scriptId = "<DEPLOYMENT_ID>";
// Run your Apps Script function
gapi.client.script.scripts
.run({
scriptId: scriptId,
resource: {
function: "createForm",
parameters: [ssId],
},
})
.then(function (resp) {
var result = resp.result;
// ERROR HANDLING
if (result.error && result.error.status) {
appendPre("Error calling API:");
appendPre(JSON.stringify(result, null, 2));
} else if (result.error) {
var error = result.error.details[0];
appendPre("Script error message: " + error.errorMessage);
if (error.scriptStackTraceElements) {
appendPre("Script error stacktrace:");
for (var i = 0; i < error.scriptStackTraceElements.length; i++) {
var trace = error.scriptStackTraceElements[i];
appendPre("\t" + trace.function + ":" + trace.lineNumber);
}
}
// IF SUCCESSFUL
} else {
console.log("success", resp);
}
});
}
Write your HTML with the buttons and inputs necessary.
Add event listeners where appropriate.
Profit!
Please note
This set up is your project running with the authorization of other accounts.
The API requests count against your quota.
You can see details of all the executions in your GCP Project Dashboard.
Users require a Google account and need to authorize the app.
In the Apps Script function above, you just need to pass in the Spreadsheet ID. Not the whole link. You could ask for the whole link and then use Regex to extract the ID if you wanted.
This can be quite tricky and easy to miss a step or make a mistake, so double check your work.
If, after successful authorization, when trying to run the script you get a 404 error, the request has been built wrong, check your IDs. If you get a 500 error, that can mean that the Apps Script function has successfully been called, but, there was an error within Apps Script and failed, check the executions page of the Apps Script editor.
References
Apps Script How to Execute
Apps Script JS Quickstart - Highly recommended you follow these steps first and get that working!
How to link your Apps Script to GCP

How to impersonate an admin user when using getClient() in the Google API NodeJS client

Per the recommendation in the defaultauth sample, I am trying to access the directory api for a domain which I have created a service account for. Here is the code I am attempting to connect with:
import { google } from 'googleapis'
const authClient = await google.auth.getClient({
scopes: ['https://www.googleapis.com/auth/admin.directory.user.readonly']
})
const service = google.admin('directory_v1')
console.log(
await service.users.list({
auth: authClient,
domain: <redacted>
})
)
However, when I attempt to connect I recieve an error saying Error: Not Authorized to access this resource/api. If I remove the creds.json file in ~/.google, the error changes to saying that it cannot find the credentials file. Also, I am able to access a bucket using the same file, so I'm pretty sure my local environment is set up correctly, authentication wise. I have also worked for the past few days with someone on the support team G Suite API team, who assures me that things are set up correctly on my domain.
After looking around online, it seems the thing I am missing is impersonating an admin account when trying to connect with my service-account. I have found a few examples online of doing this with a JWT auth strategy, but I would like to continue to use the default auth client, in order to abstract away the implementation details. Is this possible? If so, what do I have to change? I have tried setting subject, and delegationEmail in both of the calls (getClient and list).
Any help would be greatly appreciated.
Just set subject of the client object:
authClient.subject = 'your email address'
Google's api documentations highly varies by language. No standart. Something documented in PHP client may be missing in nodejs client and it can take hours to find out how to do it.
You can pass clientOptions.subject in the constructor.
import { google } = from 'googleapis';
const authClient = new google.auth.GoogleAuth({
scopes: ['https://www.googleapis.com/auth/admin.directory.user.readonly'],
clientOptions: {
subject: "your email address"
});

how to respond to user using google assistant after the conversation is ended?

I am making a google action.I have one scenario where calculation requires some time in cloud fulfillment but i don't want to keep user waiting for answer.
I want to respond to user whenever my answer is ready even when conversation with user is ended i want to send my answer in notification or something like that.
I just found this on google actions documents.
https://developers.google.com/actions/assistant/updates
Is this possible in google actions and how?
What you mean here is notifications. You can use it but please pay attention to the warning at the top of the link you provided: "Updates and notifications are currently in Developer Preview. You can build apps using the features described in this article, but you can't currently publish them".
As for the steps to crated a daily notification:
Navigate to your actions.intent.CONFIGURE_UPDATES intent.
Under Responses, go to the Google Assistant tab, click Add Message Content, and select Custom Payload.
In the "Custom Payload" box, add the following code to call the AskToRegisterDailyUpdate helper. Swap INTENT_NAME to the intent that you want to be invoked when the user interacts with your notification.
{
"google": {
"system_intent": {
"intent": "actions.intent.REGISTER_UPDATE",
"data": {"#type": "type.googleapis.com/google.actions.v2.RegisterUpdateValueSpec",
"intent": "INTENT_NAME",
"triggerContext": {
"timeContext": { "frequency": "DAILY" }
}
}
}
}
}
If using a webhook, you can call this API directly via the client library:
appMap.set('setup_update', function(app) {
app.askToRegisterDailyUpdate('INTENT_NAME');
})
})
Add one more intent called "finish_update_setup" and enter actions_intent_REGISTER_UPDATE as its Event.
Set the intent's Action to "finish_update_setup" as well.
In your webhook, open index.js and add the following. Replace Ok, I'll start giving you daily updates and Ok, I won't give you daily updates. with whatever response you want to give the user:
appMap.set('finish_update_setup', function(app)) {
if (app.isUpdateRegistered()) {
app.tell("Ok, I'll start giving you daily updates.");
} else {
app.tell("Ok, I won't give you daily updates.");
}
}
Deploy the webhook to Firebase Functions and enable webhook fulfillment in Dialogflow.
If you want to see how to create a simple notification (not daily one) - please check this doc on push notifications.
If you don't have an immediate reply to send but expect one soon-ish what you do is return a "promise". When you are in a position to reply, "fulfilling" the promise causes your reply to be delivered. I don't know what the actual timeout is but in my case I'm pretty sure at least a few second delay is allowed.
As for the updates or notifications, the API is there but the docs say you can't deploy an Action to production using them. There is a slightly cryptic comment to "contact support" if you need them.
One of these days I might try.

From where get subscription key for api.ai chatbot to be deployed on Microsoft Cortana

I'm trying to build a chatbot using api.ai. I want to integrate this bot with Microsoft Cortana. I followed every step given at this link: https://docs.api.ai/docs/cortana-integration but then to initialize api.ai instance, I have written following code. Client access token is available to me. My question here is from where to get the subscription key?
var config = new AIConfiguration("String subscription key",
"String client_access_token",
SupportedLanguage.English);
apiAi = new ApiAi(config);
apiAi.DataService.PersistSessionId();
Are you sure about the code that you have because at the URL mentioned : https://docs.api.ai/docs/cortana-integration, the code is something like this:
var config = new AIConfiguration("YOUR_CLIENT_ACCESS_TOKEN", SupportedLanguage.English);
So, all you will need is just the Client Access Token, which is available from the Agent Settings page in API.AI