Having 2 auth clients results in 404 on calendar event creation - node.js

I'm trying to create 2 calendar events across 2 calendars using the Google Node.js API client library in a single function. I'm using 2 separate auth objects that I'm retrieving like so:
var auth1 = await google.auth.getClient({ credentials: config.account1Creds, scopes: ["https://www.googleapis.com/auth/calendar.events"] });
var auth2 = await google.auth.getClient({ credentials: config.account2Creds, scopes: ["https://www.googleapis.com/auth/calendar.events"] });
I can create the event on the first calendar fine, but when I create the event on the 2nd calendar, I get a 404 Not Found back from the Google Calendar API server.
If I comment out the first var auth1 = await google.auth... line and only create the event on the 2nd calendar, everything is fine and the event is created successfully.
It kinda feels as if the first time getClient is called, it sets a global auth object that gets used for all remaining API requests and it can't be replaced, but thats just a hunch I have and I don't actually know.
Anybody have any ideas why this is happening?
EDIT:
GetGoogleCalendarService: async function(credentials)
{
var auth = await google.auth.getClient({ credentials: credentials, scopes: ["https://www.googleapis.com/auth/calendar.events"] });
return google.calendar({ version: "v3", auth: auth });
},
InsertCalendarEvent: function(calendar, entry, callback)
{
calendar.events.insert(entry, callback);
},
SendInvitesToEvent: async function (request, response)
{
//build the calendar event
var entry = {
...
}
//insert into operations calendar
var opsCal = await Events.GetGoogleCalendarService(config.GetConfig().OpsCalendarCredentials);
Events.InsertCalendarEvent(mainCal, entry);
//insert into public calendar
var publicCal = await Events.GetGoogleCalendarService(config.GetConfig().PublicCalendarCredentials);
Events.InsertCalendarEvent(publicCal, entry, async function(err, event)
{
//err: 404 Not Found
...
}
}

You want to insert events to 2 calendars using 2 clients.
Client "A" inserts an event to Calendar "A".
Client "B" inserts an event to Calendar "B".
You are using googleapis of Node.js.
If my understanding is correct, how about this modification? In this modification, I separated retrieving auth by each credential.
Modified script:
const { google } = require("googleapis");
function insertEvent(calendar, calendarId) {
// insert event
}
async function getService(c) {
var auth = await google.auth.getClient({
credentials: c,
scopes: ["https://www.googleapis.com/auth/calendar.events"]
});
return google.calendar({ version: "v3", auth: auth });
}
function main() {
getService(config.account1Creds).then(calendar => {
insertEvent(calendar, "### calendarId ###");
});
getService(config.account2Creds).then(calendar => {
insertEvent(calendar, "### calendarId ###");
});
}
main();
Note:
This is a sample script. So please modify this for your situation.
In my environment, I could confirm that this script works. But if this didn't work and this modification was not the result you want, I apologize.
Edit:
From your current script, I modified as follows.
Is opsCal mainCal? In my modification, opsCal is used as mainCal.
Modified script:
From:
//insert into operations calendar
var opsCal = await Events.GetGoogleCalendarService(config.GetConfig().OpsCalendarCredentials);
Events.InsertCalendarEvent(mainCal, entry);
//insert into public calendar
var publicCal = await Events.GetGoogleCalendarService(config.GetConfig().PublicCalendarCredentials);
Events.InsertCalendarEvent(publicCal, entry, async function(err, event)
{
//err: 404 Not Found
...
}
To:
Events.GetGoogleCalendarService(config.GetConfig().OpsCalendarCredentials).then(
opsCal => {
Events.InsertCalendarEvent(opsCal, entry);
}
);
Events.GetGoogleCalendarService(config.GetConfig().PublicCalendarCredentials).then(
publicCal => {
Events.InsertCalendarEvent(publicCal, entry);
}
);

Related

Firebase function TypeError .once is not a function and onCreate not working

I was trying to deploy a function to Firebase to send notifications to all admin accounts when a new user signs up to the app, this is my current code:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.newDoctorNotification = functions.database.ref("/doctors/{pushId}")
.onCreate((snapshot, context) => {
const newDoctorID = context.params.pushId;
const notificationContent = {
notification: {
title: "New Doctor",
body: "A new doctor just signed up! uid: " + newDoctorID,
icon: "default",
sound: "default",
},
};
const adminTokensRef = functions.database.ref("device_tokens/admin");
const tokens = [];
adminTokensRef.once("value", (querySnapshot) => {
querySnapshot.forEach((adminToken) => {
tokens.push(adminToken.val());
});
});
if (tokens.length > 0) {
return admin.messaging().sendToDevice(tokens, notificationContent)
.then(function(result) {
console.log("Notification sent");
return null;
})
.catch(function(error) {
console.log("Notification failed ", error);
return null;
});
}
});
I have tried many variations such as the get() function and on(), but all give me the same error, I was trying to check the docs on this but they only talked about database triggers so I'm not sure if normal retrieval can work or not.
EDIT:
I updated my code to reach the database node through the snapshot given in the onCreate event, and now it works, although I am facing another problem now, if I push a new doctor under the node "doctors" it doesn't call the function.. but if I hit "test" in the Google Cloud console and it calls the function I get "null" in my snapshot.val() and "undefined" in the newDoctorID above, whereas the snapshot.key gives "doctors", why is it not calling the onCreate function?

Why getting this "Authentication_MissingOrMalformed" error during Microsoft Graph API call?

const msRestAzure = require('ms-rest-azure');
const { GraphRbacManagementClient } = require('azure-graph');
module.exports = async function (context, req) {
try{
const credentials = await msRestAzure.loginWithServicePrincipalSecret(clientId, clientSecret, tanent);
const client = new GraphRbacManagementClient(credentials, tenantId);
const results = await client.users.list();
context.res = {
body: results
};
} catch (error) {
console.log('error==> ',error); // Getting error: Authentication_MissingOrMalformed
context.res = {
body: error
};
}
}
I want to get all users list using azure graph sdk. But after calling the client.users.list() function I'm getting the error ("Authentication_MissingOrMalformed"). How do I fix this error and get all users list.
How to get all users list from Azure Active Directory using Azure Graph SDK (Nodejs) ?
The main problem is missing { tokenAudience: 'graph' }, please refer to my code:
const msRestAzure = require('ms-rest-azure');
const { GraphRbacManagementClient } = require('azure-graph');
module.exports = async function (context, req) {
try{
msRestAzure.loginWithServicePrincipalSecret("clientId", "clientSecret", "tenantId", { tokenAudience: 'graph' }, function (err, credentials) {
if (err) return console.log(err);
const client = new GraphRbacManagementClient(credentials, "tenantId");
client.users.list((err, results, request, response) => {
if (err) return console.log(err);
console.log(JSON.parse(response.body).value.length);
});
});
} catch (error) {
console.log('error==> ',error);
context.res = {
body: error
};
}
}
After running the code above, if the number of users in your AD is greater than 100, it will output 100 because graph api can response 100 users in a page(default is 100).
==================================Update================================
Please check if you have added the permission to the application registered in Azure AD. If you didn't add the permission, please follow the below steps:
1. Go to the application which registered in your Azure AD (It's the application which you use its clientId).
2. Add the permission.
3. Click "Grant admin consent for xxx".
4. After a few minutes, run your code again.

Microsoft bot builder V4 nodejs fetching user email

i am using nodejs v4 version of the botbuilder https://learn.microsoft.com/en-us/javascript/api/botbuilder/?view=botbuilder-ts-latest
My current code is picked from echo bot and looks like below
const { ActivityHandler } = require('botbuilder');
class ScanBuddyMsBot extends ActivityHandler {
constructor() {
super();
this.onMessage(async (context:any, next:any) => {
await context.sendActivity(`You said '${ context.activity.text }'`);
// By calling next() you ensure that the next BotHandler is run.
await next();
});
}
}
module.exports.ScanBuddyMsBot = ScanBuddyMsBot;
I am looking a way to fetch user email sending message to my bot. I can see in the context activity, conversation id and service url but not the email id.
in another variation of this i am using below way to get email id and not sure how to make below code work for above
var bot = new builder.UniversalBot(connector, async function(session) {
var teamId = session.message.address.conversation.id;
connector.fetchMembers(
session.message.address.serviceUrl,
teamId,
async (err, result) => {
if (err) {
session.send('We faced an error trying to process this information', err);
return
}
else {
const email = result[0].email
}
In Bot Builder v4, you can access that REST API using the getConversationMembers function:
/**
*
* #param {TurnContext} turnContext
*/
async testTeams(turnContext) {
const activity = turnContext.activity;
const connector = turnContext.adapter.createConnectorClient(activity.serviceUrl);
const response = await connector.conversations.getConversationMembers(activity.conversation.id);
const email = response[0].email;
await turnContext.sendActivity(email);
}
Please refer to the documentation and the samples to better understand how to use the v4 SDK.

How to Patch a BigQuery View using Node.js

I have a Cloud Function written in the Node.js v8 that uses the #google-cloud/bigquery v1.3.0 library.
I like it, I'm able to perform BigQuery changes such as creating a view using the very simple code below without worry about promises and it's synchronous.
const bigquery = new BigQuery({projectId: 'my-project'});
const options = {
view: {
query: 'SELECT * FROM `my-project.my-datatset.my-table`',
useLegacySql: false
}
};
results = await bigquery
.dataset('my-datatset')
.createTable('my-view', options);
But I've been unable to work out how this code can be modified to perform a patch operations. I would expect a very similar syntax to be available but I can't find it. E.g. none of the examples below work:
//bigquery.dataset(datasetId).patchTable(viewId,options);
//bigquery.dataset(datasetId).table(viewId).patch(options);
//bigquery.dataset(datasetId).tables(viewId).patch(options);
I'm able to do the patch operation I want using the rest API through Googles reference documents. But I just can't find a code solution that's consistent with the approach above.
Any ideas?
This solution is longer and asynchronous, but it seems to work. In case anyone runs into the same problem
var {google} = require('googleapis');
var bigQuery = google.bigquery("v2")
google.auth.getApplicationDefault(function(err, authClient) {
if (err) {
//Handle error
}
if (authClient.createScopedRequired && authClient.createScopedRequired()) {
var scopes = [
//Either scope is sufficient according to the spec.
//https://cloud.google.com/bigquery/docs/reference/rest/v2/tables/patch
'https://www.googleapis.com/auth/cloud-platform',
'https://www.googleapis.com/auth/bigquery'
];
authClient = authClient.createScoped(scopes);
}
var request = {
projectId: 'my-project',
datasetId:'my-datatset',
tableId:'my-view',
resource: {
view: {
query: 'SELECT * FROM `my-project.my-datatset.my-table`',
useLegacySql: false
}
},
// Auth client
auth: authClient
};
tables = bigQuery.tables;
tables.patch(request, function(err, response) {
if (err) {
//Handle error
} else {
//Print response
}
});
});

Google Sheets API with NodeJS, Json error

I've been playing with the google sheets API in NodeJS for the past couple of days and I'm having some trouble. I took one of the examples from their docs and edited it to suit my needs, however at one point it started returning an error. The console logs:
The API returned an error: SyntaxError: Unexpected token  in JSON at position 0
Here's my code:
function getApplies(auth) {
const sheets = google.sheets({version: 'v4', auth});
sheets.spreadsheets.values.get({
spreadsheetId: '1g5kYIIQy5f-UTSmOatTBPOto13ccfPvsJKQpxT6lhjE',
range: 'A2:I',
}, (err2, res) => {
if (err2) return console.log('The API returned an error: ' + err2);
const rows = res.data.values;
if (rows.length) {
//saving data here...
}
});
}
Any idea what I could be doing wrong here? Thanks!
From this link:
Go to Google Console
Create a new Credential of type service account key
Download your json file
npm install google-spreadsheet#2.0.3
var GoogleSpreadsheet = require('google-spreadsheet');
var creds = require('./client_secret.json');
var doc = new GoogleSpreadsheet('*spreadsheet ID*');
doc.useServiceAccountAuth(creds, function (err) {
doc.getRows(1, function (err, rows) {
if (err) {
console.log(err);
} else {
console.log(rows.length);
console.log(rows);
for (var i=0; i < rows.length; i++) {
console.log(rows[i].TITLE-NAME-OF-YOUR-FIRST-COLUMN, rows[i].TITLE-NAME-OF-YOUR-SECOND-COLUMN);
}
}
});
});
Replace the spreadsheet ID with the ID found in the spreadsheet URL.
Share the sheet with the service account email. It is in your json file.
Hope this helps!!
For v4 of googleapi use:
const { google } = require("googleapis");
const key = require("service_account_credentials.json");
const client = new google.auth.JWT(key.client_email, null, key.private_key, [
"https://www.googleapis.com/auth/spreadsheets",
]);
client.authorize(function (err, tokens) {
const gsapi = google.sheets({ version: "v4", auth: client });
const opt = {
spreadsheetId: "spreadsheetId",
range: "Sheet1!A:T",
};
gsapi.spreadsheets.values.get(opt).then(res => console.log(res));
});
You need to parse your json file like this, first:
const rows = JSON.parse(res.data.values);

Resources