From f5955eaf8c2555e48668d2a36dfef02c74c258b1 Mon Sep 17 00:00:00 2001 From: rcpeters Date: Fri, 24 Feb 2017 13:29:44 -0800 Subject: [PATCH] refactored into local module --- client-app.js | 211 +++------------------------ helpers/config.js | 3 +- local_modules/orcid-google-sheets.js | 148 +++++++++++++++++++ package.json | 16 +- 4 files changed, 181 insertions(+), 197 deletions(-) create mode 100644 local_modules/orcid-google-sheets.js diff --git a/client-app.js b/client-app.js index a7e2d34..60cfe2f 100644 --- a/client-app.js +++ b/client-app.js @@ -1,7 +1,6 @@ var // load config from file bodyParser = require('body-parser'), - googleSpreadsheet = require('google-spreadsheet'), config = require('./helpers/config'), createServer = require("auto-sni"), express = require('express'), @@ -9,7 +8,10 @@ var httpLogging = require('./helpers/http-logging'), querystring = require("querystring"), request = require('request'), - session = require('express-session'); + session = require('express-session'), + OrcidGoogleSheet = require('./local_modules/orcid-google-sheets.js').OrcidGoogleSheet; + +var ogSheet = new OrcidGoogleSheet(); // Init express var app = express(); @@ -45,175 +47,11 @@ var orcidOutput = fs.createWriteStream('./orcidout.log'); var orcidErrorOutput = fs.createWriteStream('./orciderr.log'); var orcidLogger = new console.Console(orcidOutput, orcidErrorOutput); -// Google sheets via google-spreadsheet -var doc = new googleSpreadsheet(config.GOOGLE_DOC_KEY, 'private'); -var creds = require(config.GOOGLE_SERVICE_ACCOUNT_KEY); - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Other Google sheets... -// copied from https://developers.google.com/sheets/quickstart/nodejs -// we'll need to refactor and clean up - -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/sheets.googleapis.com-nodejs-quickstart.json -var SCOPES = ['https://www.googleapis.com/auth/spreadsheets']; -var TOKEN_DIR = 'credentials/'; - -function getGOauth2Client() { - var credentials = JSON.parse(fs.readFileSync('credentials/client_secret.json')); - var clientSecret = credentials.web.client_secret; - var clientId = credentials.web.client_id; - var redirectUrl = null; - for (var i in credentials.web.redirect_uris) - if (credentials.web.redirect_uris[i].startsWith(config.HOST)) - redirectUrl = credentials.web.redirect_uris[i]; - var auth = new googleAuth(); - var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl); - return oauth2Client; -} - -/** - * Create an OAuth2 client with the given credentials, and then execute the - * given callback function. - * - * @param {Object} spreadsheetId spreedsheet we are working with. - * @param {function} callback The callback to call with the authorized client. - */ -function authorize(spreadsheetId, callback) { - var oauth2Client = getGOauth2Client(); - // Check if we have previously stored a token. - fs.readFile(tokenPath(spreadsheetId), function(err, token) { - if (err) { - console.log(tokenPath(spreadsheetId)); - console.log("Default spreedsheet has no token please visit /" + spreadsheetId + '/has_token.json') - } else { - oauth2Client.credentials = JSON.parse(token); - callback(oauth2Client, spreadsheetId); - } - }); -} - -/** - * 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 {spreadsheetId} - * @param {getEventsCallback} callback The callback to call with the authorized - * client. - */ -function getNewToken(oauth2Client, spreadsheetId, callback) { - var authUrl = oauth2Client.generateAuthUrl({ - access_type: 'offline', - scope: SCOPES, - state: spreadsheetId - }); - 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, spreadsheetId); - callback(oauth2Client); - }); - }); -} - -function tokenPath(spreadsheetId) { - return TOKEN_DIR + 'sheets_token_'+spreadsheetId +'.json'; -} - -/** - * Store token to disk be used in later program executions. - * - * @param {Object} token The token to store to disk. - */ -function storeToken(token, spreadsheetId) { - try { - fs.mkdirSync(TOKEN_DIR); - } catch (err) { - if (err.code != 'EEXIST') { - throw err; - } - } - fs.writeFile(tokenPath(spreadsheetId), JSON.stringify(token)); - console.log(tokenPath(spreadsheetId)); -} - - -function listFirstRow(auth, spreadsheetId) { - var sheets = google.sheets('v4'); - sheets.spreadsheets.values.get({ - auth: auth, - spreadsheetId: spreadsheetId, - range: 'Sheet1!A1:D4', - }, function(err, response) { - if (err) { - console.log('The API returned an error: ' + err); - return; - } - var rows = response.values; - if (rows == undefined) - write_with_google_googleapis(['Date', 'ORCID iD', 'Name',], spreadsheetId); - else if (rows.length == 0) - console.log('No data found.'); - else - console.log('First row %s, %s, %s, %s', rows[0][0], rows[0][1], rows[0][2], rows[0][3]); - }); -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Adding to the above example with what we need - -function write_with_google_googleapis(arr, spreadsheetId) { - // Authorize a client with the loaded credentials, then call the - // Google Sheets API. - authorize(spreadsheetId, function(auth) { - append(auth, arr, spreadsheetId); - }); -} - -// adding append funtion -function append(auth, arr, spreadsheetId) { - var sheets = google.sheets('v4'); - sheets.spreadsheets.values.append({ - auth: auth, - spreadsheetId: spreadsheetId, - range: 'Sheet1', - valueInputOption: 'USER_ENTERED', - resource: { - "range": "Sheet1", - majorDimension: "ROWS", - "values": - [arr] - }, - }, - function(err, response) { - if (err) { - console.log('The API returned an error: ' + err); - return; - } - console.log('append response: ' + JSON.stringify(response)); - }); -} app.get(['/'], function(req, res) { // Index page - req.session.GOOGLE_DOC_KEY = req.query.spreadsheetId ? req.query.spreadsheetId : config.GOOGLE_DOC_KEY; + var docKey = req.query.spreadsheetId ? req.query.spreadsheetId : config.DEFAULT_GSHEET_ID; // link we send user to authorize our requested scopes var auth_link = config.ORCID_URL + '/oauth/authorize' + '?' + querystring.stringify({ @@ -222,6 +60,8 @@ app.get(['/'], function(req, res) { // Index page 'response_type':'code', 'client_id': config.CLIENT_ID, 'show_login': 'true', + 'state': docKey //state maps to current google sheet + }); // reset any session on reload of '/' req.session.regenerate(function(err) { @@ -242,39 +82,36 @@ app.get('/orcid-id.json', function(req, res) { app.get('/google_oauth_redirect_uri', function(req, res) { console.log("here"); - oauth2Client = getGOauth2Client(); - oauth2Client.getToken(req.query.code, function(err, token) { + ogSheet.getGOauth2Client().getToken(req.query.code, function(err, token) { if (err) { console.log('Error while trying to retrieve access token', err); return; } var spreadsheetId = req.query.state; - storeToken(token, spreadsheetId); - authorize(spreadsheetId, listFirstRow); - res.redirect("/token_has_been_stored"); + ogSheet.storeToken(token, spreadsheetId); + ogSheet.authorize(spreadsheetId, ogSheet.listFirstRow); + res.send("token has been stored"); }); }); app.get('/:spreadsheetId/has_token.json', function(req, res) { // Load client secrets from a local file. - fs.readFile(tokenPath(req.param.spreadsheetId), function processClientSecrets(err, content) { - if (err) + console.log(req.params.spreadsheetId); + token = ogSheet.getToken(req.params.spreadsheetId); + + if (token == null) res.json({ name: req.params.spreadsheetId, has_token : false, - authorization_uri: - getGOauth2Client().generateAuthUrl({ - access_type: 'offline', - scope: SCOPES, - state: req.params.spreadsheetId - }) - }); + authorization_uri: ogSheet.generateGAuthUrl(req.params.spreadsheetId) + }); else res.json({ name: req.params.spreadsheetId, has_token : true}); - }); -}); + }); app.get('/redirect-uri', function(req, res) { // Redeem code URL + var state = req.query.state; + console.log("spreed sheet from /redirect-uri url " + state); if (req.query.error == 'access_denied') { // User denied access var auth_link = config.ORCID_URL + '/oauth/authorize' + '?' @@ -284,8 +121,8 @@ app.get('/redirect-uri', function(req, res) { // Redeem code URL 'response_type':'code', 'client_id': config.CLIENT_ID, 'show_login': 'true', + 'state': state //state maps to current google sheet }); - res.render('pages/access_denied', {'authorization_uri': auth_link,'orcid_url': config.ORCID_URL }); } else { // exchange code @@ -296,10 +133,10 @@ app.get('/redirect-uri', function(req, res) { // Redeem code URL console.log(token); var date = new Date(); //Log ORCID info to file - orcidLogger.log(date, token.name, token.orcid, req.session.GOOGLE_DOC_KEY); + orcidLogger.log(date, token.name, token.orcid, req.query.state); req.session.orcid_id = token.orcid; - // token state is mapped to spreedsheet we want to save in - write_with_google_googleapis([new Date(), token.orcid, token.name], req.session.GOOGLE_DOC_KEY); + //state maps to current google sheet + ogSheet.write_with_google_googleapis([new Date(), token.orcid, token.name], state); res.render('pages/success', { 'body': JSON.parse(body), 'authorization_uri': auth_link, 'orcid_url': config.ORCID_URL}); } else // handle error diff --git a/helpers/config.js b/helpers/config.js index 24024bc..e4a4441 100644 --- a/helpers/config.js +++ b/helpers/config.js @@ -5,8 +5,7 @@ module.exports = config = { REDIRECT_URI: 'https://localhost:8443/redirect-uri', ORCID_URL: 'https://sandbox.orcid.org', //Google API config - GOOGLE_DOC_KEY: '13MkfJqOOXfY3uotB0c0uagahWueT4NP5hxojbl2TxQM',//Key from Google spreadsheet URL - GOOGLE_SERVICE_ACCOUNT_KEY: './key.json',//Path to key file downloaded from Google API console https://console.developers.google.com/apis/credentials + DEFAULT_GSHEET_ID: '1_srGxfEjCHq_kUDTAO3mJxOjCQ0UJQGjymlvBMNe4Zc',//Key from Google spreadsheet URL https://docs.google.com/spreadsheets/d/1_srGxfEjCHq_kUDTAO3mJxOjCQ0UJQGjymlvBMNe4Zc/edit?usp=sharing //Server SSL config FORCE_SSL: 'true', // must be 'true' or 'false' LETSENCRYPT_ISSUES_EMAIL: 'orcid-id-to-gdoc@mailinator.com', // Where to email when certificates expire. diff --git a/local_modules/orcid-google-sheets.js b/local_modules/orcid-google-sheets.js new file mode 100644 index 0000000..aed5d83 --- /dev/null +++ b/local_modules/orcid-google-sheets.js @@ -0,0 +1,148 @@ +var fs = require('fs'), +readline = require('readline'), +googleAuth = require('google-auth-library'), +google = require('googleapis'); + +var OrcidGoogleSheet = function () { + this.oauth2Client = null; +}; + +var TOKEN_DIR = 'credentials/'; + +// If modifying these scopes, delete your previously saved credentials +// at ~/.credentials/sheets.googleapis.com-nodejs-quickstart.json +var SCOPES = ['https://www.googleapis.com/auth/spreadsheets']; + + +OrcidGoogleSheet.prototype.tokenPath =function(spreadsheetId) { + return TOKEN_DIR + 'sheets_token_'+spreadsheetId +'.json'; +} + +OrcidGoogleSheet.prototype.generateGAuthUrl =function(spreadsheetId) { + return this.getGOauth2Client().generateAuthUrl({ + access_type: 'offline', + scope: SCOPES, + prompt: 'consent', + state: spreadsheetId + }); +} + +/** + * Store token to disk be used in later program executions. + * + * @param {Object} token The token to store to disk. + */ +OrcidGoogleSheet.prototype.storeToken = function (token, spreadsheetId) { + try { + fs.mkdirSync(TOKEN_DIR); + } catch (err) { + if (err.code != 'EEXIST') { + throw err; + } + } + fs.writeFileSync(this.tokenPath(spreadsheetId), JSON.stringify(token)); + console.log("written google sheet token" + this.tokenPath(spreadsheetId)); +} + +OrcidGoogleSheet.prototype.getToken = function (spreadsheetId) { + try { + var tokenStr = fs.readFileSync(this.tokenPath(spreadsheetId)); + } catch (eer) { + //do nothing + } + return tokenStr ? JSON.parse(tokenStr) : null; +} + + +OrcidGoogleSheet.prototype.getGOauth2Client= function() { + if (this.oauth2Client == null) { + var credentials = JSON.parse(fs.readFileSync('credentials/client_secret.json')); + var clientSecret = credentials.web.client_secret; + var clientId = credentials.web.client_id; + var redirectUrl = null; + for (var i in credentials.web.redirect_uris) + if (credentials.web.redirect_uris[i].startsWith(config.HOST)) + redirectUrl = credentials.web.redirect_uris[i]; + var auth = new googleAuth(); + this.oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl); + } + return this.oauth2Client; +} + + +OrcidGoogleSheet.prototype.listFirstRow = function (auth, spreadsheetId) { + var sheets = google.sheets('v4'); + sheets.spreadsheets.values.get({ + auth: auth, + spreadsheetId: spreadsheetId, + range: 'Sheet1!A1:D4', + }, function(err, response) { + if (err) { + console.log('The API returned an error: ' + err); + return; + } + var rows = response.values; + if (rows == undefined) + write_with_google_googleapis(['Date', 'ORCID iD', 'Name',], spreadsheetId); + else if (rows.length == 0) + console.log('No data found.'); + else + console.log('First row %s, %s, %s, %s', rows[0][0], rows[0][1], rows[0][2], rows[0][3]); + }); +} + +OrcidGoogleSheet.prototype.write_with_google_googleapis = function(arr, spreadsheetId) { + // Authorize a client with the loaded credentials, then call the + // Google Sheets API. + var ogSheet = this; + this.authorize(spreadsheetId, function(auth) { + ogSheet.append(auth, arr, spreadsheetId); + }); +} + +// adding append funtion +OrcidGoogleSheet.prototype.append = function(auth, arr, spreadsheetId) { + var sheets = google.sheets('v4'); + sheets.spreadsheets.values.append({ + auth: auth, + spreadsheetId: spreadsheetId, + range: 'Sheet1', + valueInputOption: 'USER_ENTERED', + resource: { + "range": "Sheet1", + majorDimension: "ROWS", + "values": + [arr] + }, + }, + function(err, response) { + if (err) { + console.log('The API returned an error: ' + err); + return; + } + console.log('append response: ' + JSON.stringify(response)); + }); +} + + +/** + * Create an OAuth2 client with the given credentials, and then execute the + * given callback function. + * + * @param {Object} spreadsheetId spreedsheet we are working with. + * @param {function} callback The callback to call with the authorized client. + */ +OrcidGoogleSheet.prototype.authorize = function(spreadsheetId, callback) { + var oauth2Client = this.getGOauth2Client(); + // Check if we have previously stored a token. + console.log("spreedsheet " + spreadsheetId); + var credentials = this.getToken(spreadsheetId); + if (credentials == null) + console.log("Spreedsheet has no token please visit /" + spreadsheetId + '/has_token.json') + else { + oauth2Client.credentials = credentials; + callback(oauth2Client, spreadsheetId); + } +} + +exports.OrcidGoogleSheet = OrcidGoogleSheet; \ No newline at end of file diff --git a/package.json b/package.json index a54bb1f..e54b006 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,15 @@ "main": "client-app.js", "dependencies": { "auto-sni": "^1.5.1", - "body-parser": "^1.15.2", - "ejs": "^1.0.0", - "express": "^4.12.4", - "express-session": "^1.14.1", - "global-request-logger": "^0.0.1", - "google-auth-library": "^0.9.9", + "body-parser": "^1.16.1", + "ejs": "^2.5.6", + "express": "^4.14.1", + "express-session": "^1.15.1", + "global-request-logger": "^0.1.1", + "google-auth-library": "^0.10.0", "google-spreadsheet": "^2.0.3", - "googleapis": "^14.1.0", - "request": "^2.57.0" + "googleapis": "^17.1.0", + "request": "^2.79.0" }, "repository": { "type": "git",