NodeJS & Gmail API - Access last 3 emails based on "To:" recipient - node.js

I am currently utilising NodeJS and the Gmail API to access my gmail account and return the last email I've received which is obviously only going to be 1 email using this code: (which is a slightly modified version of the example seen here: https://www.codediesel.com/nodejs/how-to-access-gmail-using-nodejs-and-the-gmail-api/
var fs = require('fs');
var readline = require('readline');
var {google} = require('googleapis');
// If modifying these scopes, delete your previously saved credentials
// at TOKEN_DIR/gmail-nodejs.json
var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];
// Change token directory to your system preference
var TOKEN_DIR = ('./');
var TOKEN_PATH = TOKEN_DIR + 'gmail-nodejs.json';
var gmail = google.gmail('v1');
//exports.confirmationEmailFinal;
// Load client secrets from a local file.
fs.readFile('client_secret.json', function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the
// Gmail API.
authorize(JSON.parse(content), getRecentEmail);
});
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
*
* #param {Object} credentials The authorization client credentials.
* #param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
var clientSecret = credentials.installed.client_secret;
var clientId = credentials.installed.client_id;
var redirectUrl = credentials.installed.redirect_uris[0];
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, function(err, token) {
if (err) {
getNewToken(oauth2Client, callback);
} else {
oauth2Client.credentials = JSON.parse(token);
callback(oauth2Client);
}
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
*
* #param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
* #param {getEventsCallback} callback The callback to call with the authorized
* client.
*/
function getNewToken(oauth2Client, callback) {
var authUrl = oauth2Client.generateAuthUrl({access_type: 'offline', scope: SCOPES});
console.log('Authorize this app by visiting this url: ', authUrl);
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', function(code) {
rl.close();
oauth2Client.getToken(code, function(err, token) {
if (err) {
console.log('Error while trying to retrieve access token', err);
return;
}
oauth2Client.credentials = token;
storeToken(token);
callback(oauth2Client);
});
});
}
/**
* Store token to disk be used in later program executions.
*
* #param {Object} token The token to store to disk.
*/
function storeToken(token) {
try {
fs.mkdirSync(TOKEN_DIR);
} catch (err) {
if (err.code != 'EEXIST') {
throw err;
}
}
fs.writeFileSync(TOKEN_PATH, JSON.stringify(token));
console.log('Token stored to ' + TOKEN_PATH);
}
/**
* Lists the labels in the user's account.
*
* #param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
function listLabels(auth) {
gmail.users.labels.list({auth: auth, userId: 'me',}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
var labels = response.data.labels;
if (labels.length == 0) {
console.log('No labels found.');
} else {
console.log('Labels:');
for (var i = 0; i < labels.length; i++) {
var label = labels[i];
console.log('%s', label.name);
}
}
});
}
/**
* Get the recent email from your Gmail account
*
* #param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
function getRecentEmail(auth) {
// Only get the recent email - 'maxResults' parameter
gmail.users.messages.list({auth: auth, userId: 'me', maxResults: 1,}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
// Get the message id which we will need to retreive tha actual message next.
var message_id = response['data']['messages'][0]['id'];
// Retreive the actual message using the message id
gmail.users.messages.get({auth: auth, userId: 'me', 'id': message_id}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
// Access the email body content, like this...
try {
const message_raw = response.data.payload.body.data;
data = message_raw;
buff = new Buffer.from(data, 'base64');
text = buff.toString();
console.log(text);
}
catch (err){
const message_raw = response.data.payload.parts[0].body.data;
console.log('error');
data = message_raw;
buff = new Buffer.from(data, 'base64');
text = buff.toString();
console.log(text);
}
});
});
}
Although this works perfectly fine, I am looking to find the 3 latest emails (not just 1) based on the email's "TO:" recipient which I currently have stored as the email variable.
Any help would be appreciated!

Have a look at here: https://developers.google.com/gmail/api/guides/filtering.
You can search or filter files using the messages.list and
threads.list methods. These methods accept the q parameter which
supports the same advanced search syntax as the Gmail web-interface.

Use filters via q property:
const email = 'myEmail#example.com';
gmail.users.messages.list({
auth: auth,
userId: 'me',
maxResults: 1,
q: `to:${email}`
}
Beside to:address you can use all other search/filter params, like is:unread etc.

Related

Insufficient permission error when trying to fetch user Youtube Channels

I have authenticated against a Youtube Account and have successfully gotten the access token. Now I wish to fetch the user's Youtube Channels using the code below:
async fetchYoutubeChannels() {
let accessToken = ....;
const authCredentials = accessToken;
const oauth2Client = initOAuth2Client(); //Oauth2 Client initialized at the top with secret, redirect url and and client id
oauth2Client.setCredentials(authCredentials);
oauth2Client.on('tokens', async (tokens) => {
if (tokens.refresh_token) {
//Save new token
}
});
let service = google.youtube('v3');
service.channels.list({
auth: oauth2Client,
part: 'snippet,contentDetails,statistics',
}, function (err, response) {
if (err) {
console.log('The Youtube API returned an error: ' + err);
return;
}
let channels = response.data;
console.log(`Retrieved Channels = ${JSON.stringify(channels, null, 2)}`);
});
}
But All I keep getting is this error message:
The Youtube API returned an error: Error: Insufficient Permission
What am I missing?
Any idea would be greatly appreciated.
Thank you.
Error: Insufficient Permission
Means that the user has authorized your application but they have not granted you the permissions you need to access this method.
I am going to assume you are following quickstart nodejs and have just neglected to follow some of the code.
Notice how the get channel method passes the auth parameter which was created as part of the authorization. You appear to be trying to create it manually by setting an access token. You should let the code create the access token as it will be created with the proper scope.
var fs = require('fs');
var readline = require('readline');
var {google} = require('googleapis');
var OAuth2 = google.auth.OAuth2;
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/youtube-nodejs-quickstart.json
var SCOPES = ['https://www.googleapis.com/auth/youtube.readonly'];
var TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
process.env.USERPROFILE) + '/.credentials/';
var TOKEN_PATH = TOKEN_DIR + 'youtube-nodejs-quickstart.json';
// Load client secrets from a local file.
fs.readFile('client_secret.json', function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the YouTube API.
authorize(JSON.parse(content), getChannel);
});
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
*
* #param {Object} credentials The authorization client credentials.
* #param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
var clientSecret = credentials.installed.client_secret;
var clientId = credentials.installed.client_id;
var redirectUrl = credentials.installed.redirect_uris[0];
var oauth2Client = new OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, function(err, token) {
if (err) {
getNewToken(oauth2Client, callback);
} else {
oauth2Client.credentials = JSON.parse(token);
callback(oauth2Client);
}
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
*
* #param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
* #param {getEventsCallback} callback The callback to call with the authorized
* client.
*/
function getNewToken(oauth2Client, callback) {
var authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
console.log('Authorize this app by visiting this url: ', authUrl);
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', function(code) {
rl.close();
oauth2Client.getToken(code, function(err, token) {
if (err) {
console.log('Error while trying to retrieve access token', err);
return;
}
oauth2Client.credentials = token;
storeToken(token);
callback(oauth2Client);
});
});
}
/**
* Store token to disk be used in later program executions.
*
* #param {Object} token The token to store to disk.
*/
function storeToken(token) {
try {
fs.mkdirSync(TOKEN_DIR);
} catch (err) {
if (err.code != 'EEXIST') {
throw err;
}
}
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) throw err;
console.log('Token stored to ' + TOKEN_PATH);
});
}
/**
* Lists the names and IDs of up to 10 files.
*
* #param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
function getChannel(auth) {
var service = google.youtube('v3');
service.channels.list({
auth: auth,
part: 'snippet,contentDetails,statistics',
forUsername: 'GoogleDevelopers'
}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
var channels = response.data.items;
if (channels.length == 0) {
console.log('No channel found.');
} else {
console.log('This channel\'s ID is %s. Its title is \'%s\', and ' +
'it has %s views.',
channels[0].id,
channels[0].snippet.title,
channels[0].statistics.viewCount);
}
});
}
From comments
How do I get the username of a youtube account. is it the user display name retrieved during the oauth2 process?
The youtube api is channel based not user based. You are given access to a users channel. Not techincally the user themselves activites might give you some info as to what channel the user authorized you to access but i haven't actually tried.
Error: No filter selected. Expected one of: mySubscribers, id, categoryId, mine, managedByMe, forUsername
Channels: list requires that you send a filter. Check the section Filters (specify exactly one of the following parameters)

Error: Unauthorized while working with the Youtube Data API

I have a web application through which I'd like to be able create playlists, add videos to a playlist, delete a video etc, to my youtube channel. I've followed the example YouTube API quickstart for nodejs and gotten everything working locally for the past almost 2 weeks but seemingly out of nowhere, I'm getting hit with Error: Unauthorized, every time I try to call the API to create a playlist for example.
{
message: 'Unauthorized',
status: undefined,
stackHighlighted: 'Error: Unauthorized\n' +
' at Gaxios._request (c:\\apps\\node\\myapp\\node_modules\\gaxios\\build\\src\\<mark>gaxios.js:89:23</mark>)\n' +
' at processTicksAndRejections (internal/process/<mark>task_queues.js:93:5</mark>)\n' +
' at async OAuth2Client.requestAsync (c:\\apps\\node\\myapp\\node_modules\\google-auth-library\\build\\src\\auth\\<mark>oauth2client.js:343:18</mark>)\n' +
' at async createPlaylist (file:///c:/apps/node/myapp/controllers/youtube.<mark>controller.js:76:22</mark>)'
}
Line 76 is where I'm calling youtube.playlists.insert.
The only thing that has changed is that I moved the app to a live server, so now both my local copy and the one on the server are both not working. My code basically works like the following.
var fs = require('fs');
var readline = require('readline');
var {google} = require('googleapis');
var OAuth2 = google.auth.OAuth2;
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/youtube-nodejs-quickstart.json
var SCOPES = ['https://www.googleapis.com/auth/youtube'];
var TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
process.env.USERPROFILE) + '/.credentials/';
var TOKEN_PATH = TOKEN_DIR + 'youtube-nodejs-quickstart.json';
// Load client secrets from a local file.
fs.readFile('client_secret.json', function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the YouTube API.
authorize(JSON.parse(content), getChannel);
});
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
*
* #param {Object} credentials The authorization client credentials.
* #param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
var clientSecret = credentials.installed.client_secret;
var clientId = credentials.installed.client_id;
var redirectUrl = credentials.installed.redirect_uris[0];
var oauth2Client = new OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, function(err, token) {
if (err) {
getNewToken(oauth2Client, callback);
} else {
oauth2Client.credentials = JSON.parse(token);
callback(oauth2Client);
}
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
*
* #param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
* #param {getEventsCallback} callback The callback to call with the authorized
* client.
*/
function getNewToken(oauth2Client, callback) {
var authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
console.log('Authorize this app by visiting this url: ', authUrl);
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', function(code) {
rl.close();
oauth2Client.getToken(code, function(err, token) {
if (err) {
console.log('Error while trying to retrieve access token', err);
return;
}
oauth2Client.credentials = token;
storeToken(token);
callback(oauth2Client);
});
});
}
/**
* Store token to disk be used in later program executions.
*
* #param {Object} token The token to store to disk.
*/
function storeToken(token) {
try {
fs.mkdirSync(TOKEN_DIR);
} catch (err) {
if (err.code != 'EEXIST') {
throw err;
}
}
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) throw err;
console.log('Token stored to ' + TOKEN_PATH);
});
}
/**
* Lists the names and IDs of up to 10 files.
*
* #param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
function getChannel(auth) {
var service = google.youtube('v3');
service.channels.list({
auth: auth,
part: 'snippet,contentDetails,statistics',
forUsername: 'GoogleDevelopers'
}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
var channels = response.data.items;
if (channels.length == 0) {
console.log('No channel found.');
} else {
console.log('This channel\'s ID is %s. Its title is \'%s\', and ' +
'it has %s views.',
channels[0].id,
channels[0].snippet.title,
channels[0].statistics.viewCount);
}
});
}
I don't understand why this is. Any insight would be much appreciated.

YouTube account authentication nodejs

I am making an application that searches for YouTube videos, and creates a playlist with those videos.
I've figured how to search for videos just using the API key provided, but am completely lost on how to do stuff as a user. At first, I thought that I could just use a service account to host all of the playlist, but I've learned quickly that YouTube doesn't support that.
My ultimate goal is to just create a playlist on my personal YouTube account, so I want that account to be hardcoded in.
I am struggling on changing it from using a service account to my personal account. Many other solutions I've seen use an express server with a frontend component, neither of which I have.
import { google } from 'googleapis';
import fs from 'fs';
const config = JSON.parse(fs.readFileSync('config.json', 'utf8'));
const key = require('./credentials.json');
const scopes = "https://www.googleapis.com/auth/youtube";
const jwt = new google.auth.JWT(key.client_email, null, key.private_key, scopes);
jwt.authorize((err, response) => {
const yt = google.youtube({
version: 'v3',
auth: jwt,
});
yt.search.list({
part: 'snippet',
q: 'study music | zen music -livestream -live',
maxResults: 1,
}, (err, data) => {
if (err) console.error(err);
if (data) {
console.log(data.data.items);
// TODO: create playlist with these items
}
});
});
Currently, it's using a service account to search for videos. I haven't done the playlist creation part yet because it would just keep giving an error as I'm using a service account.
The YouTube API does not support service accounts. You will need to use Oauth2 and save the refresh token. You can then use your refresh token to request a new access token whenever you need.
I recommend following quickstart
var fs = require('fs');
var readline = require('readline');
var {google} = require('googleapis');
var OAuth2 = google.auth.OAuth2;
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/youtube-nodejs-quickstart.json
var SCOPES = ['https://www.googleapis.com/auth/youtube.readonly'];
var TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
process.env.USERPROFILE) + '/.credentials/';
var TOKEN_PATH = TOKEN_DIR + 'youtube-nodejs-quickstart.json';
// Load client secrets from a local file.
fs.readFile('client_secret.json', function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the YouTube API.
authorize(JSON.parse(content), getChannel);
});
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
*
* #param {Object} credentials The authorization client credentials.
* #param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
var clientSecret = credentials.installed.client_secret;
var clientId = credentials.installed.client_id;
var redirectUrl = credentials.installed.redirect_uris[0];
var oauth2Client = new OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, function(err, token) {
if (err) {
getNewToken(oauth2Client, callback);
} else {
oauth2Client.credentials = JSON.parse(token);
callback(oauth2Client);
}
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
*
* #param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
* #param {getEventsCallback} callback The callback to call with the authorized
* client.
*/
function getNewToken(oauth2Client, callback) {
var authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
console.log('Authorize this app by visiting this url: ', authUrl);
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', function(code) {
rl.close();
oauth2Client.getToken(code, function(err, token) {
if (err) {
console.log('Error while trying to retrieve access token', err);
return;
}
oauth2Client.credentials = token;
storeToken(token);
callback(oauth2Client);
});
});
}
/**
* Store token to disk be used in later program executions.
*
* #param {Object} token The token to store to disk.
*/
function storeToken(token) {
try {
fs.mkdirSync(TOKEN_DIR);
} catch (err) {
if (err.code != 'EEXIST') {
throw err;
}
}
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) throw err;
console.log('Token stored to ' + TOKEN_PATH);
});
console.log('Token stored to ' + TOKEN_PATH);
}
/**
* Lists the names and IDs of up to 10 files.
*
* #param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
function getChannel(auth) {
var service = google.youtube('v3');
service.channels.list({
auth: auth,
part: 'snippet,contentDetails,statistics',
forUsername: 'GoogleDevelopers'
}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
var channels = response.data.items;
if (channels.length == 0) {
console.log('No channel found.');
} else {
console.log('This channel\'s ID is %s. Its title is \'%s\', and ' +
'it has %s views.',
channels[0].id,
channels[0].snippet.title,
channels[0].statistics.viewCount);
}
});
}

How to pass value on command line at runtime while node js running app with forever?

When I run an app in node as 'node server.js', after calling an api it will ask to enter some value and I can enter the value on cmd. but when I run the same app with forever module I am not able to enter the value. Is there any way to do that?
ex :
Authorize this app by visiting this url: https://someurl.com/o/oauth2/auth?dd
Enter the code from that page here:
I need to enter that value once. Please suggest
var fs = require('fs');
var readline = require('readline');
var google = require('googleapis');
var googleAuth = require('google-auth-library');
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-nodejs-quickstart.json
var SCOPES = ['https://www.googleapis.com/auth/calendar'];
var TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
process.env.USERPROFILE) + '/.credentials/';
var TOKEN_PATH = TOKEN_DIR + 'calendar-nodejs-quickstart.json';
var calendar = google.calendar('v3');
module.exports.auth = function (callback) {
console.log('TOKEN_DIR', TOKEN_DIR);
fs.readFile('client_secret.json', function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the
// Google Calendar API.
authorize(JSON.parse(content), callback);
});
};
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
*
* #param {Object} credentials The authorization client credentials.
* #param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
var clientSecret = credentials.installed.client_secret;
var clientId = credentials.installed.client_id;
var redirectUrl = credentials.installed.redirect_uris[0];
var auth = new googleAuth();
var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, function (err, token) {
if (err) {
getNewToken(oauth2Client, callback);
} else {
oauth2Client.credentials = JSON.parse(token);
callback(oauth2Client);
}
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
*
* #param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
* #param {getEventsCallback} callback The callback to call with the authorized
* client.
*/
function getNewToken(oauth2Client, callback) {
var authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
console.log('Authorize this app by visiting this url: ', authUrl);
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', function (code) {
rl.close();
oauth2Client.getToken(code, function (err, token) {
if (err) {
console.log('Error while trying to retrieve access token', err);
return;
}
oauth2Client.credentials = token;
storeToken(token);
callback(oauth2Client);
});
});
}
/**
* Store token to disk be used in later program executions.
*
* #param {Object} token The token to store to disk.
*/
function storeToken(token) {
try {
fs.mkdirSync(TOKEN_DIR);
} catch (err) {
if (err.code != 'EEXIST') {
throw err;
}
}
fs.writeFile(TOKEN_PATH, JSON.stringify(token));
console.log('Token stored to ' + TOKEN_PATH);
}
/**
* Lists the next 10 events on the user's primary calendar.
*
* #param {google.auth.OAuth2} auth An authorized OAuth2 client.
*/
module.exports.listEvents = function (auth, callback) {
calendar.events.list({
auth: auth,
calendarId: 'primary',
timeMin: (new Date()).toISOString(),
maxResults: 10,
singleEvents: true,
orderBy: 'startTime'
}, callback);
};
this line is aksing for the value
rl.question('Enter the code from that page here: '

Store Events List from Google Calendar Node.js Example in Express.js Application

Being a javascript/node.js/express.js newbie, I'm banging my head on this one. Looking at "Google Calendar API Node.js Quickstart", I've been able to sucessfully print a list of upcoming events when running node quickstart.js. I'd now like to present this data in the browser by passing it into the view renderer. I've copied over the code from quickstart.js into my routes/calendar.js file. This is what routes/calendar.js currently looks like:
var express = require('express');
var router = express.Router();
var fs = require('fs');
var readline = require('readline');
var google = require('googleapis');
var googleAuth = require('google-auth-library');
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-nodejs-quickstart.json
var SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'];
var TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
process.env.USERPROFILE) + '/.credentials/';
var TOKEN_PATH = TOKEN_DIR + 'calendar-nodejs-quickstart.json';
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
*
* #param {Object} credentials The authorization client credentials.
* #param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
var clientSecret = credentials.installed.client_secret;
var clientId = credentials.installed.client_id;
var redirectUrl = credentials.installed.redirect_uris[0];
var auth = new googleAuth();
var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, function(err, token) {
if (err) {
getNewToken(oauth2Client, callback);
} else {
oauth2Client.credentials = JSON.parse(token);
callback(oauth2Client);
}
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
*
* #param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
* #param {getEventsCallback} callback The callback to call with the authorized
* client.
*/
function getNewToken(oauth2Client, callback) {
var authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
console.log('Authorize this app by visiting this url: ', authUrl);
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', function(code) {
rl.close();
oauth2Client.getToken(code, function(err, token) {
if (err) {
console.log('Error while trying to retrieve access token', err);
return;
}
oauth2Client.credentials = token;
storeToken(token);
callback(oauth2Client);
});
});
}
/**
* Store token to disk be used in later program executions.
*
* #param {Object} token The token to store to disk.
*/
function storeToken(token) {
try {
fs.mkdirSync(TOKEN_DIR);
} catch (err) {
if (err.code != 'EEXIST') {
throw err;
}
}
fs.writeFile(TOKEN_PATH, JSON.stringify(token));
console.log('Token stored to ' + TOKEN_PATH);
}
function listEvents(auth) {
var calendar = google.calendar('v3');
calendar.events.list({
auth: auth,
calendarId: 'primary',
timeMin: (new Date()).toISOString(),
maxResults: 10,
singleEvents: true,
orderBy: 'startTime'
}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
var events = response.items;
if (events.length == 0) {
console.log('No upcoming events found.');
} else {
console.log('Upcoming 10 events:');
for (var i = 0; i < events.length; i++) {
var event = events[i];
var start = event.start.dateTime || event.start.date;
console.log('%s - %s', start, event.summary);
}
}
});
}
/* GET events listing. */
router.get('/', function(req, res, next) {
fs.readFile('client_secret.json', function processClientSecrets(err, content) {
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the
// Google Calendar API.
authorize(JSON.parse(content), listEvents);
});
// TODO: How can I pass 'events' from 'listEvents' into the view renderer?
res.render('calendar', { title: 'TS Calendar', current: 'calendar', events: events });
});
module.exports = router;
When I visit http://localhost:3000/calendar in my browser, I do get an error about 'events' not being defined, but my console does print out the calendar events, so I know it's working on at least some level.
It seems to me to be just a mess of callbacks, and I can't quite wrap my head around how to extract/store var events = response.items; from within listEvents() so it's usable within router.get(). Any suggestions? A good example would be fantastic.
Also, for bonus points, I'm a little weary of including all this logic/code into the routes/calendar.js file. Is there a more expressjs-esque or appropriate place for it?
I'm thinking I was in the wrong mindset here. Instead, I went with client-side javascript and used the quickstart guide for that. I've made progress going this route, but I have a feeling I'm going to quickly find out it's not going to lend itself nicely to a kiosk application where a keyboard isn't present to authenticate. Might need to ask that question when I get to that point.

Resources