UNPKG

gsweet

Version:

Help with writing scripts to run against gSuite

309 lines (261 loc) 10.7 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: drive/driveOps.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: drive/driveOps.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>// @ts-check /** @module */ /** * @file Handles talking to the Google Spreadsheet API * ## Links to Google Drive documentation * [mime-types](https://developers.google.com/drive/api/v3/mime-types) * [all file meta data](https://developers.google.com/drive/api/v3/reference/files) * [search parameters](https://developers.google.com/drive/api/v3/search-parameters) * a few meta types we aren't using that might be interesting are `starred, shared, description` * * NOTE: Before using init() **MUST** be called and a driveService passed in. * @author Tod Gentille &lt;tod-gentille@pluralsight.com> * @license GPL-3.0-or-later [Full Text](https://spdx.org/licenses/GPL-3.0-or-later.html) */ const ds = require('./driveService') const logger = require('../utils/logger') const MAX_FILES_PER_PAGE = 1000 let _driveService /** Enum for the currently supported google mime-types */ const mimeType = { /** @type {number} */ FOLDER: 1, /** FILE is not a google recognized value, used to mean anything other than a folder. */ FILE: 2, /** @type {number} */ SPREADSHEET: 3, /** @type {number} */ DOC: 4, /** place to store the actual strings that google uses for mime-types */ properties: { 1: {type: 'application/vnd.google-apps.folder'}, 2: {type: 'N/A'}, 3: {type: 'application/vnd.google-apps.spreadsheet'}, 4: {type: 'application/vnd.google-apps.document'}, }, /** Convenience function to return the google mime-types- called with our ENUM value */ getType(value) {return mimeType.properties[value].type}, } const FILE_META_FOR_NAME_SEARCH = 'files(id, name)' const FILE_META_FOR_FOLDER_SEARCH = 'files(id, name, mimeType)' /** Allow access to google drive APIs via the driveService (this version for testing) */ const init = (driveService) => { _driveService = driveService } /** In production just call this to set up access to the drive APIs */ const autoInit = () => { _driveService = ds.init() } /** * Get a list of files/folders that match * @param {{withName:string,exactMatch:boolean}} fileOptions * @returns {Promise&lt;Array.&lt;{id:String,name:String}>>} * @example getFiles({withName:"someName", exactMatch:true}) */ const getFiles = async (fileOptions) => { const {withName} = fileOptions const {exactMatch} = fileOptions // NOTE: The filename has to be quoted const query = `name ${exactMatch ? ' = ' : 'contains'} '${withName}'` const response = await _driveService.files.list( { q: query, pageSize: MAX_FILES_PER_PAGE, fields: `nextPageToken, ${FILE_META_FOR_NAME_SEARCH}`, }) .catch(googleError => { const {errors} = googleError.response.data.error const errMsg = JSON.stringify(errors[0], null, 2) logger.error(errMsg) throw (`For ${withName} - The Google Drive API returned:${errMsg}`) }) const {files} = response.data return files } /** * Get a single file for the passed name. If a single file isn't found an error is thrown. // @ts-ignore * @param {{withName:String}} withName * @returns {Promise&lt;{id:String,name:String}>} a single object that has the FILE_META_FOR_NAME_SEARCH properties * @example getFile({withName:"someName"}) //forces exactMatch:true */ const getFile = async ({withName}) => { const files = await getFiles({withName, exactMatch: true}) if (files.length !== 1) { throw (`Found ${files.length} files.`) } return files[0] } /** * Convenience function that returns the id for a file * @param {{withName:String,exactMatch:Boolean}} withNameObj * @returns {Promise&lt;string>} google id for the file * @example getFileId({withName:"SomeName"}) * */ const getFileId = async (withNameObj) => { const file = await getFile(withNameObj) return file.id } /** * Just get the files for the user. Will only return the google API max * of 1000 files. * @returns {Promise&lt;Array.&lt;{FILE_META_FOR_FOLDER_SEARCH}>>} array of objects, where each object * has the properties specified by the constant `FILE_META_FOR_FOLDER_SEARCH` * @example listFiles() * */ const listFiles = async () => { const response = await _driveService.files.list({ fields: `${FILE_META_FOR_FOLDER_SEARCH}`, pageSize: MAX_FILES_PER_PAGE, }) .catch(error => {throw (error)}) return response.data.files } /** * Example of how to use the nextPageToken to get all the files * in a folder when there are more than 1000 */ // const countAllFiles = async () => { // let nextPage = null // start on first page // let totalCount = 0 // do { // const response = await _driveService.files.list({ // pageToken: nextPage, // fields: `nextPageToken, ${FILE_META_FOR_FOLDER_SEARCH}`, // pageSize: MAX_FILES_PER_PAGE, // }) // .catch(error => { // logger.error(JSON.stringify(error)) // }) // nextPage = response.data.nextPageToken // if (response.data.files !== undefined) { // totalCount += response.data.files.length // } // logger.debug(nextPage) // } while (nextPage !== undefined &amp;&amp; totalCount &lt; 20000) // logger.info(`Total file count: ${totalCount}`) // } /** * Get all the Files in the passed folderId (ofType is optional) * @param {{withFolderId:String,ofType:any}} folderOptions * @returns {Promise&lt;Array&lt;{name, id, mimeType}>>} array of file objects where each object has the properties * specified by the constant `FILE_META_FOR_FOLDER_SEARCH` * @example getFilesInFolder({withFolderId:"someId", ofType:mimeType:SPREADSHEET}) */ const getFilesInFolder = async (folderOptions) => { const {withFolderId} = folderOptions const {ofType} = folderOptions const mimeClause = getMimeTypeClause(ofType) const response = await _driveService.files.list( { q: `parents in '${withFolderId}' ${mimeClause}`, pageSize: MAX_FILES_PER_PAGE, fields: `nextPageToken, ${FILE_META_FOR_FOLDER_SEARCH}`, }) .catch(error => { const errMsg = JSON.stringify(error, null, 2) throw (`\r\nFor parent folder ${withFolderId} - files.list() returned:${errMsg}`) }) const nextToken = response.data.nextPageToken if (nextToken !== undefined) { logger.debug(`NEXT PAGE TOKEN ${response.data.nextPageToken}`) } const {files} = response.data return files } /** * Get just the names of the files in the folder (ofType is optional) * @param {{withFolderId:String,ofType:number}} folderOptions * @returns {Promise&lt;Array.&lt;string>>} array of strings containing filenames * @example getFileNamesInFolder({withFolderId:"someId", ofType:mimeType.SPREADSHEET) */ const getFileNamesInFolder = async (folderOptions) => { const files = await getFilesInFolder(folderOptions) return files.map(e => e.name) } /** * Get the files in the parent folder and all the children folders (ofType is optional) * @param {{withFolderId:String,ofType:number}} folderOptions * @returns {Promise&lt;Array.&lt;{FILE_META_FOR_FOLDER_SEARCH}>>} array of file objects where each object has the properties * specified by the constant `FILE_META_FOR_FOLDER_SEARCH` * @example getFilesRecursively({withFolderId:"someId", ofType:mimeType.SPREADSHEET}) */ const getFilesRecursively = async (folderOptions) => { let result = [] const {ofType} = folderOptions const {withFolderId} = folderOptions const folderType = mimeType.getType(mimeType.FOLDER) const allTypes = {withFolderId, ofType: undefined} const files = await getFilesInFolder(allTypes) for (const entry of files) { if (entry.mimeType === folderType) { const subFolderFiles = await getFilesRecursively({withFolderId: entry.id, ofType}) result = result.concat(subFolderFiles) } else { if ((ofType === undefined) || (entry.mimeType === mimeType.getType(ofType))) { result.push(entry) } } } return result } /** * Private helper function to look up the mimetype string for the passed enum and construct and "and" clause that * can be used in the API search query. The FILE enum isn't a type the API understands * but we use it to mean any type of file but NOT a folder. * @param {number} type * @returns {string} the additional clause to limit the search for the specified type. * For example if mimeType.SPREADSHEET was passed in, then the clause * will be returned. * @example getMimeTypeClause(mimeType.SPREADSHEET) will return `and mimeType = application/vnd.google-apps.spreadsheet` */ const getMimeTypeClause = (type) => { if (type === undefined) { return '' } if (type === mimeType.FILE) { return `and mimeType != '${mimeType.getType(mimeType.FOLDER)}'` } return `and mimeType = '${mimeType.getType(type)}'` } module.exports = { autoInit, init, getFile, getFiles, getFileId, listFiles, getFilesInFolder, getFileNamesInFolder, getFilesRecursively, mimeType, }</code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="Drive_driveOps.module_test.html">test</a></li><li><a href="module-drive_driveOps.html">drive/driveOps</a></li><li><a href="module-Drive_driveOps%2520Integration%2520Tests.html">Drive/driveOps Integration Tests</a></li><li><a href="module-drive_driveService.html">drive/driveService</a></li><li><a href="module-Sheet_sheetOps%2520Integration%2520Tests.html">Sheet/sheetOps Integration Tests</a></li><li><a href="sheets_sheetOps.module_js.html">sheets/sheetOps.js</a></li><li><a href="sheets_sheetService.module_js.html">sheets/sheetService.js</a></li><li><a href="-_sheetOps.module_test.html">test</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Sat May 11 2019 23:52:27 GMT-0700 (Pacific Daylight Time) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>