Last active
January 14, 2020 14:40
-
-
Save DinoChiesa/78789a90de46445f1016344879e5b344 to your computer and use it in GitHub Desktop.
boilerplate for building a command-line app in nodejs that uses OAuth2 client id to update Google sheets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// updateSheets.js | |
// ------------------------------------------------------------------ | |
// | |
// created: Tue Jan 14 05:22:42 2020 | |
// last saved: <2020-January-14 06:34:31> | |
const fs = require('fs'), | |
path = require('path'), | |
util = require('util'), | |
{google} = require('googleapis'), | |
readline = require('readline'), | |
clipboardy = require('clipboardy'), | |
opn = require('opn'); | |
const GOOG_APIS_SCOPES = ['https://www.googleapis.com/auth/spreadsheets']; | |
// ================================================================== | |
// The following nonsense is required in order to get | |
// ctrl-v (paste) events to work in readline on Windows. | |
readline.emitKeypressEvents(process.stdin); | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
process.stdin.setRawMode(true); | |
process.stdin.on('keypress', (str, key) => { | |
if (key.ctrl && key.name === 'v') { | |
rl.write(clipboardy.readSync()); | |
} | |
}); | |
// ================================================================== | |
function sleep (time) { | |
return new Promise((resolve) => setTimeout(resolve, time)); | |
} | |
function getNewGsuiteToken(oAuth2Client, tokenStashPath, projectId, callback) { | |
console.log('\nYou must authorize Sheet updater to create a new sheet.\n'); | |
console.log('This script will now open a browser tab. After granting consent, you will'); | |
console.log('receive a one-time code. Return here and paste it in, to continue....\n'); | |
sleep(4200) | |
.then(() => { | |
const authUrl = oAuth2Client.generateAuthUrl({ | |
access_type: 'offline', | |
scope: GOOG_APIS_SCOPES | |
}); | |
// Authorize this app by visiting the url | |
opn(authUrl, {wait: false}); | |
rl.question('Paste the one-time-code: ', (code) => { | |
oAuth2Client.getToken(code, (e, token) => { | |
console.log(`Thanks! You have successfully authorized ${projectId} to do its thing.`); | |
if (e) { | |
console.log('cannot get token?'); | |
console.log(e); | |
return callback(e); | |
} | |
oAuth2Client.setCredentials(token); | |
// Store the token to disk for later program executions | |
let dataToStore = JSON.stringify(token, null, 2) + '\n'; | |
fs.writeFile(tokenStashPath, dataToStore, (e) => { | |
if (e) { | |
console.error(e); // this is a non-fatal condition | |
} | |
else { | |
console.log('stored token in token stash: ' + tokenStashPath); | |
} | |
callback(null, oAuth2Client); | |
}); | |
}); | |
}); | |
}); | |
} | |
/** | |
* 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 oauth2Authorize(credentials, callback) { | |
const {client_secret, client_id, redirect_uris} = credentials; | |
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]); | |
const tokenStashPath = path.join('.', ".gsheets_token_stash.json"); | |
// Check if there is a previously stashed token. | |
//console.log('token stash path: ' + tokenStashPath); | |
fs.readFile(tokenStashPath, (e, data) => { | |
if (e) { | |
console.log('cannot read stashed token: ' + e); | |
return getNewGsuiteToken(oAuth2Client, tokenStashPath, projectId, callback); | |
} | |
let stashedToken = JSON.parse(data); | |
//console.log('read stashed token: ' + util.format(stashedToken)); | |
//let expiry = new Date(stashedToken.expiry_date); | |
//let now = new Date(); | |
//console.log('expires: ' + expiry.toISOString()); | |
//console.log('now: ' + now.toISOString()); | |
// expiry and refresh is handled automagically | |
oAuth2Client.setCredentials(stashedToken); | |
callback(null, oAuth2Client); | |
}); | |
} | |
// for setup, visit console.cloud.google.com | |
// IAM | |
// Create Credentials | |
// OAuth2 client id | |
// Other | |
// (name it) | |
// Save | |
// Edit | |
// Download JSON | |
// The downloaded credentials file ought to look like this: | |
// { | |
// "installed": { | |
// "client_id": "8675309-b9aa47c7aa3ed0bc03ac569c.apps.googleusercontent.com", | |
// "project_id": "my-project-name", | |
// "auth_uri": "https://accounts.google.com/o/oauth2/auth", | |
// "token_uri": "https://www.googleapis.com/oauth2/v3/token", | |
// "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", | |
// "client_secret": "ABCDEFGHIBAADBEEF", | |
// "redirect_uris": [ | |
// "urn:ietf:wg:oauth:2.0:oob", | |
// "http://localhost" | |
// ] | |
// } | |
// } | |
const clientCredentialsFile = path.join(".", "gsheets_client_credentials.json"); | |
fs.readFile(clientCredentialsFile, (e, content) => { | |
if (e) { | |
console.log('Error loading client credentials file:', e); | |
return; | |
} | |
let credentials = JSON.parse(content).installed; | |
oauth2Authorize(credentials, doTheThing(credentials.project_id)); | |
}); | |
function doTheThing(projectId) { | |
return function(e, oAuth2Client) { | |
rl.close(); | |
if (e) { | |
return console.log(e); | |
} | |
console.log(`${projectId} is authorized to do its thing.`); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment