Socket
Socket
Sign inDemoInstall

utils-google-drive

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

utils-google-drive - npm Package Compare versions

Comparing version 2.1.0 to 3.0.0

lib/batch.js

6

CHANGELOG.md

@@ -0,1 +1,7 @@

### v3.0.0 — *November 11, 2020*
* Added batch requests
* Better error handling: Errors are logged for individual files in `download` and `upload`, thrown elsewhere
* Fixed `listFiles` only searching in trash when ignoreTrash parameter set to false
* Security update ([CVE-2020-7720](https://github.com/advisories/GHSA-92xj-mqp7-vmcj))
### v2.1.0 — *August 19, 2020*

@@ -2,0 +8,0 @@ * Added API request throttling

10

index.js

@@ -9,2 +9,3 @@ #!/usr/bin/env node

const update = require('./lib/update');
const batch = require('./lib/batch');
const drive = require('./lib/drive');

@@ -54,8 +55,9 @@ const throttledQueue = require('throttled-queue');

this.del = del.del;
this.batch = batch.batch;
this.throttle = throttle;
this.Error = UtilsGDriveError;
this._resolveId = utils._resolveId;
this._resolveIdFromString = utils._resolveIdFromString;
this._handleListFilesResponse = utils._handleListFilesResponse;
this.Error = UtilsGDriveError;
this._resolveId = utils._resolveId;
this._resolveIdFromString = utils._resolveIdFromString;
this._checkUniqueIdent = utils._checkUniqueIdent;
/* eslint-enable no-multi-spaces */

@@ -62,0 +64,0 @@ };

11

lib/delete.js

@@ -13,3 +13,3 @@ 'use strict';

* Also accepts a string containing the file/folder
* id or path (can be partial) to the file/folder in Google Drive.
* id or path (can be partial) to the file/folder in Google Drive
* @param {string} identifiers.fileId - File/folder id

@@ -31,10 +31,5 @@ * @param {string} identifiers.fileName - File/folder name

async function del(identifiers) {
let responseData;
try {
const fileId = await this._resolveId(identifiers);
responseData = await this.api('files', 'delete', {fileId});
} catch (err) {
console.error(err);
}
const fileId = await this._resolveId(identifiers);
const responseData = await this.api('files', 'delete', {fileId});
return responseData.files;
}

@@ -17,3 +17,3 @@ 'use strict';

* Also accepts a string containing the file/folder
* id or path (can be partial) to the file/folder in Google Drive.
* id or path (can be partial) to the file/folder in Google Drive
* @param {string} identifiers.fileId - File/folder id

@@ -27,3 +27,3 @@ * @param {string} identifiers.fileName - File/folder name

* // download the folder "folderName" to the local directory "localDir"
* utilsGDrive.download({folderName: "folderName"}, "path/to/localDir");
* utilsGDrive.download({fileName: "folderName"}, "path/to/localDir");
*

@@ -39,7 +39,3 @@ * // download the file with id "fileId" to the current working directory

} else {
try {
fileId = await this._resolveId(identifiers);
} catch (err) {
return console.error(err);
}
fileId = await this._resolveId(identifiers);
}

@@ -55,9 +51,8 @@

const metadata = await this.getFiles({
fileId,
fields: 'name, mimeType',
fileId, fields: 'name, mimeType',
});
if (!metadata) return;
fileName = metadata.name;
mimeType = metadata.mimeType;
}
// write location

@@ -69,7 +64,3 @@ if (!out) out = '.';

out = path.join(out, fileName);
try {
fs.mkdirSync(out);
} catch (err) {
return console.error(err);
}
fs.mkdirSync(out);
const children = await this.listChildren({fileId});

@@ -88,5 +79,12 @@ if (children) {

}
// handle file
// handle file
} else {
await this._downloadFile(fileId, fileName, out);
// error while downloading a file doesn't stop execution
try {
await this._downloadFile(fileId, fileName, out);
} catch (e) {
console.error(
`Error while downloading file with id ${fileId} (${fileName})`);
console.error(e);
}
}

@@ -110,7 +108,7 @@ }

{responseType: 'stream'},
(err, response) => {
if (err) return console.error(err);
response.data
(err, resp) => {
if (err) throw err;
resp.data
.on('error', (err) => {
console.error('Error while downloading', fileName + ':', err);
throw err;
})

@@ -117,0 +115,0 @@ .on('end', () => {

@@ -14,3 +14,3 @@ 'use strict';

* Also accepts a string containing the file/folder
* id or path (can be partial) to the file/folder in Google Drive.
* id or path (can be partial) to the file/folder in Google Drive
* @param {string} identifiers.fileId - File/folder id

@@ -27,8 +27,3 @@ * @param {string} identifiers.fileName - File/folder name

async function rename(identifiers, newName) {
let fileId;
try {
fileId = await this._resolveId(identifiers);
} catch (err) {
return console.error(err);
}
const fileId = await this._resolveId(identifiers);
const params = {fileId, resource: {name: newName}};

@@ -44,3 +39,3 @@ return this.updateFiles(params);

* Also accepts a string containing the file/folder
* id or path (can be partial) to the file/folder in Google Drive.
* id or path (can be partial) to the file/folder in Google Drive
* @param {string} identifiers.fileId - File/folder id

@@ -52,3 +47,3 @@ * @param {string} identifiers.fileName - File/folder name

* <code>identifiers</code> but for the new parent.
* File will be moved to root folder if this parameter isn't specified.
* File will be moved to root folder if this parameter isn't specified
* @return {undefined} None

@@ -66,13 +61,6 @@ * @example

async function move(identifiers, newParentIdentifiers) {
let fileId;
let oldParentId;
let newParentId;
try {
fileId = await this._resolveId(identifiers);
const responseData = await this.getFiles({fileId, fields: 'parents'});
oldParentId = responseData.parents[0];
newParentId = await this._resolveId(newParentIdentifiers);
} catch (err) {
return console.error(err);
}
const fileId = await this._resolveId(identifiers);
const responseData = await this.getFiles({fileId, fields: 'parents'});
const oldParentId = responseData.parents[0];
const newParentId = await this._resolveId(newParentIdentifiers);
const params = {

@@ -79,0 +67,0 @@ fileId,

@@ -41,3 +41,3 @@ 'use strict';

* <code>parents</code> is a list with a single string corresponding
* to the parent id.
* to the parent id
* @return {undefined} None

@@ -76,3 +76,3 @@ * @access private

* folderName: "newFolder",
* parentName: "parentFolder"
* parentIdentifiers: {parentName: "parentFolder"}
* });

@@ -97,14 +97,9 @@ *

let responseData;
try {
const parentId = await this._resolveId(parentIdentifiers);
fileMetadata.parents = [parentId];
if (overwrite) this._overwrite(fileMetadata);
responseData = await this.api('files', 'create', {
resource: fileMetadata,
fields: 'id',
});
} catch (err) {
return console.error(err);
}
const parentId = await this._resolveId(parentIdentifiers);
fileMetadata.parents = [parentId];
if (overwrite) this._overwrite(fileMetadata);
const responseData = await this.api('files', 'create', {
resource: fileMetadata,
fields: 'id',
});
return responseData.id;

@@ -132,3 +127,3 @@ }

* localPath: "path/to/folderName",
* parentName: "parentName"
* parentIdentifiers: {parentName: "parentFolder"}
* });

@@ -144,3 +139,3 @@ *

}) {
// handle string
// parent id
let parentId;

@@ -150,15 +145,11 @@ if (typeof(arguments[0]) === 'string') {

parentId = 'root';
} else {
parentId = await this._resolveId(parentIdentifiers);
}
// file name
const fileName = path.basename(localPath);
const isDir = fs.lstatSync(localPath).isDirectory();
// parent id
try {
parentId = await this._resolveId(parentIdentifiers);
} catch (err) {
return console.error(err);
}
// MIME type
const isDir = fs.lstatSync(localPath).isDirectory();
let mimeType;

@@ -182,12 +173,7 @@ if (isDir) {

if (isDir) {
let parentIdChildren;
try {
parentIdChildren = await this.makeFolder({
folderName: fileName,
parentIdentifiers: parentId,
overwrite,
});
} catch (err) {
return console.error(err);
}
const parentIdChildren = await this.makeFolder({
folderName: fileName,
parentIdentifiers: parentId,
overwrite,
});
fileId = parentIdChildren;

@@ -207,3 +193,10 @@ const children = fs.readdirSync(localPath);

if (overwrite) this._overwrite(fileMetadata);
fileId = await this._uploadFile(localPath, fileMetadata);
// error while uploading file doesn't stop execution
try {
fileId = await this._uploadFile(localPath, fileMetadata);
} catch (e) {
console.error(
`Error while uploading file ${localPath}`);
console.error(e);
}
}

@@ -220,3 +213,3 @@

* <code>parents</code> is a list with a single string corresponding
* to the parent id.
* to the parent id
* @return {undefined} None

@@ -230,13 +223,8 @@ * @access private

};
let responseData;
try {
responseData = await this.api('files', 'create', {
resource: fileMetadata,
media: media,
fields: 'id',
});
} catch (err) {
return console.error(err);
}
const responseData = await this.api('files', 'create', {
resource: fileMetadata,
media: media,
fields: 'id',
});
return responseData.id;
}

@@ -14,3 +14,3 @@ 'use strict';

_resolveId,
_handleListFilesResponse,
_checkUniqueIdent,
getMime,

@@ -29,8 +29,8 @@ listChildren,

* @param {Object} params - Method parameters
* @return {Object} Data from response
* @return {Object} Response data
* @example
* // Use the files resource and list method to
* // use the files resource and list method to
* // get ids of files with the name "fileName"
* utilsGDrive.api("files", "list", {
* q: "name = 'fileName'",
* q: "name = 'fileName',
* fields: "files(id)"

@@ -42,3 +42,3 @@ * });

this.throttle(() => {
this.drive[resource][method](params, (err, response) => {
this.drive[resource][method](params, (err, resp) => {
if (err) {

@@ -48,3 +48,3 @@ reject(err);

}
resolve(response.data);
resolve(resp.data);
});

@@ -61,10 +61,10 @@ });

* @param {Object} params - Method parameters,
* two of which are highlighted below.
* two of which are highlighted below
* @param {string} [params.q] - Query string used to search for files/folders
* @param {string} [params.fields] - Data fields to request.
* Should follow the pattern <code>"files(fiel1, field2,...)"</code>.
* Should follow the pattern <code>"files(field1, field2,...)"</code>.
* Default value is <code>"files(name, id, mimeType)"</code>
* @param {boolean} [ignoreTrash=true] - Whether to include trash
* as a search location
* @return {Object} Data from response
* @return {Object} Response data
* @example

@@ -79,10 +79,11 @@ * // search for files with the name "fileName" and get their ids

if (!params.fields) params.fields = 'files(name, id, mimeType)';
if (params.q) {
if (params.q && ignoreTrash) {
const regEx = new RegExp('(and)? trashed ?= ?(true|false)');
const matches = regEx.exec(params.q);
if (matches) params.q = params.q.replace(matches[0], '');
params.q += ' and trashed=' + !ignoreTrash;
params.q += ' and trashed=false';
}
return this.api('files', 'list', params)
.catch((err) => console.error(err));
return this.api('files', 'list', params);
}

@@ -95,5 +96,5 @@

* @param {Object} params - Method parameters.
* <code>fileId</code> is a required property.
* <code>fileId</code> is a required property
* @param {string} params.fileId - File/folder id
* @return {Object} Data from response
* @return {Object} Response data
* @throws Throws an error when file/folder id isn't specified.

@@ -109,10 +110,5 @@ * More specifically, when <code>params.fileId</code> is falsy

function getFiles(params) {
if (!params.fileId) {
const err = new this.Error('File id not specified.');
// wrapping in Promise.resolve ensures chainability
return Promise.resolve(console.error(err));
}
if (!params.fileId) throw new this.Error('File id not specified.');
if (!params.fields) params.fields = 'name, id, mimeType';
return this.api('files', 'get', params)
.catch((err) => console.error(err));
return this.api('files', 'get', params);
}

@@ -122,14 +118,15 @@

* Makes a request to the API's files resource using
* its update method, which can be used
* to change a file or folders's name or to move a file to a different location
* within Google Drive.
* its update method, which can be used to change a
* file or folder's name or to move a file to a
* different location within Google Drive.
* @see Wraps {@link api}
* @param {Object} params - Method parameters
* <code>fileId</code> is a required property.
* @param {Object} params - Method parameters.
* <code>fileId</code> is a required property
* @param {string} params.fileId - File/folder id
* @return {Object} Data from response
* @return {Object} Response data
* @throws Throws an error when file/folder id isn't specified.
* More specifically, when <code>params.fileId</code> is falsy
* @example
* // change the name of a file whose id is "fileId" to "newFileName"
* // change the name of a file
* // whose id is "fileId" to "newFileName"
* utilsGDrive.updateFiles({

@@ -141,9 +138,4 @@ * fileId: "fileId"

function updateFiles(params) {
if (!params.fileId) {
const err = new this.Error('File id not specified.');
// wrapping in Promise.resolve ensures chainability
return Promise.resolve(console.error(err));
}
return this.api('files', 'update', params)
.catch((err) => console.error(err));
if (!params.fileId) throw new this.Error('File id not specified.');
return this.api('files', 'update', params);
}

@@ -161,3 +153,3 @@

const responseData = await this.getFiles({fileId, fields: 'name'});
if (responseData) return responseData.name;
return responseData.name;
}

@@ -169,21 +161,20 @@

* @see Called by <code>getFileId</code>
* @param {Object} responseData - Response data from
* @param {Object} filesData - Response data from
* <code>listFiles</code>
* @param {string} fileName - <code>fileName</code>
* from <code>getFileId</code>
* @return {undefined|UtilsGDriveError} <code>undefined</code>
* if only 1 file found. <code>UtilsGDriveError</code>
* if 0 or more than 1 file found
* @return {undefined} None
* @throws {UtilsGDriveError} Throws an error when
* 0 or more than 1 file found given identifiers.
* @access private
*/
function _handleListFilesResponse(responseData, fileName) {
const nFiles = responseData.length;
let e;
function _checkUniqueIdent(filesData, fileName) {
const nFiles = filesData.length;
if (nFiles === 0) {
e = new this.Error('No files found matching identifiers specified.');
throw new this.Error(
`No files found matching identifiers specified: ${fileName}.`);
} else if (nFiles > 1) {
e = new this.Error(
throw new this.Error(
`Multiple files found: ${fileName}. Consider specifying parent.`);
}
return e;
}

@@ -248,4 +239,6 @@

if (typeof(arguments[0]) === 'string') {
if (arguments[0].indexOf(path.sep) + 1) {
// path given
if (arguments[0].indexOf(path.sep) > -1) {
return this._resolveIdFromString(arguments[0]);
// file name given
} else {

@@ -263,12 +256,3 @@ fileName = arguments[0];

} else if (parentName) {
const responseData = await this.listFiles({
q: 'name="' + parentName + '"',
fields: 'files(id)',
});
if (responseData) {
const files = responseData.files;
const e = this._handleListFilesResponse(files, fileName);
if (e) return console.error(e);
p = files[0].id;
}
p = await this.getFileId(parentName);
}

@@ -279,8 +263,5 @@ q += ' and "' + p + '" in parents';

const responseData = await this.listFiles({q, fields: 'files(id)'});
if (responseData) {
const files = responseData.files;
const e = this._handleListFilesResponse(files, fileName);
if (e) return console.error(e);
return files[0].id;
}
const filesData = responseData.files;
this._checkUniqueIdent(filesData, fileName);
return filesData[0].id;
}

@@ -306,2 +287,5 @@

async function _resolveId(identifiers) {
// pass fileId through if already specified
if (identifiers.fileId) return identifiers.fileId;
// handle string

@@ -312,5 +296,2 @@ if (typeof(identifiers) === 'string') {

// pass fileId through if already specified
if (identifiers.fileId) return identifiers.fileId;
// default to root if empty object

@@ -335,3 +316,3 @@ if (!Object.keys(identifiers).length) return 'root';

* Also accepts a string containing the file/folder
* id or path (can be partial) to the file/folder in Google Drive.
* id or path (can be partial) to the file/folder in Google Drive
* @param {string} identifiers.fileId - File/folder id

@@ -344,3 +325,3 @@ * @param {string} identifiers.fileName - File/folder name

* // get MIME type of file whose id is "fileId"
* utilsGDrive.getMime("fileId")
* utilsGDrive.getMime("fileId");
*

@@ -358,13 +339,7 @@ * // get MIME type of file using path

async function getMime(identifiers) {
let fileId;
try {
fileId = await this._resolveId(identifiers);
} catch (err) {
return console.error(err);
}
const fileId = await this._resolveId(identifiers);
const responseData = await this.getFiles({
fileId,
fields: 'mimeType',
fileId, fields: 'mimeType',
});
if (responseData) return responseData.mimeType;
return responseData.mimeType;
}

@@ -378,3 +353,3 @@

* Also accepts a string containing the file/folder
* id or path (can be partial) to the file/folder in Google Drive.
* id or path (can be partial) to the file/folder in Google Drive
* @param {string} identifiers.fileId - File/folder id

@@ -398,15 +373,8 @@ * @param {string} identifiers.fileName - File/folder name

async function listChildren(identifiers, fields = 'files(name, id, mimeType)') {
let folderId;
try {
folderId = await this._resolveId(identifiers);
} catch (err) {
return console.error(err);
}
const folderId = await this._resolveId(identifiers);
const listFilesParams = {
q: '"' + folderId + '" in parents',
fields: fields,
q: '"' + folderId + '" in parents', fields,
};
const responseData = await this.listFiles(listFilesParams);
if (responseData) return responseData.files;
return responseData.files;
}
{
"name": "utils-google-drive",
"version": "2.1.0",
"version": "3.0.0",
"description": "A simple and flexible package for interacting with Google Drive",

@@ -32,3 +32,3 @@ "main": "index.js",

"dependencies": {
"googleapis": "^39.2.0",
"googleapis": "^64.0.0",
"throttled-queue": "^1.0.7"

@@ -38,8 +38,8 @@ },

"docdash": "^1.2.0",
"eslint": "^7.5.0",
"eslint": "^7.13.0",
"eslint-config-google": "^0.14.0",
"fs-extra": "^9.0.1",
"mocha": "^8.1.1",
"mocha": "^8.2.1",
"nyc": "^15.1.0"
}
}

@@ -11,8 +11,13 @@ # **utils-google-drive**

- Get metadata
- Change name
- Download
- Upload
- Move
- Rename
- Delete
- Make folders
Also features:
- Flexible file/folder specification
- Request throttling
- Batch requests

@@ -24,42 +29,72 @@ ## **Flexible file/folder specification**

If specifying a path, partial paths can be used and are encouraged. Ideally, you would specify a partial path that contains just enough information to uniquely identify the file in Google Drive. For example, suppose you wanted to download the file "annualReport.pdf" in the folder "reports2020". If there are multiple files named "annualReport.pdf" in Google Drive but no other folders with the name "reports2020", you could use the partial path `"reports2020/annualReport.pdf"` to identify the file of interest. This path is preferable to a longer one because it finds the file quicker, jumping in at the uniquely-named folder "reports2020" and not worrying itself with folders higher up the chain.
If specifying a path, partial paths can be used and are encouraged. Ideally, you would specify a partial path that contains just enough information to uniquely identify the file in Google Drive. For example, suppose you wanted to download the file 'annualReport.pdf' in the folder 'reports2020'. If there are multiple files named 'annualReport.pdf' in Google Drive but no other folders with the name 'reports2020', you could use the partial path `'reports2020/annualReport.pdf'` to identify the file of interest. This path is preferable to a longer one because it finds the file quicker, jumping in at the uniquely-named folder 'reports2020' and not worrying itself with folders that are higher up in the hierarchy.
There is some variation in how to specify a file or folder across utils-google-drive methods. Consult the [docs](https://curtcommander.github.io/utils-google-drive/) for details.
## **Request Throttling**
utils-google-drive uses [throttled-queue](https://www.npmjs.com/package/throttled-queue) to throttle API requests. The default rate is 2 requests per 200 ms which complies with the Google Drive API's default rate limit of 1,000 requests per 100 seconds per user. You can adjust the throttle rate using the `nRequests` and `interval` variables in this package's index.js file. Note that setting an interval of less than 200 ms can cause performance issues.
## **Examples**
```javascript
const utilsGDrive = require("utils-google-drive");
const utilsGDrive = require('utils-google-drive');
// get id of folder in Google Drive whose name is "mainFolder"
// and whose parent folder is named "parentFolder"
/* get metadata */
// get id of file in Google Drive whose name is 'fileName'
// and whose parent folder is named 'parentName'
utilsGDrive.getFileId({
fileName: "mainFolder",
parentName: "parentFolder"
});
fileName: 'fileName',
parentName: 'parentName'
}).then(fileId => {console.log(fileId)});
// change name of folder from "beforeName" to "afterName"
utilsGDrive.rename({folderName: "beforeName"}, "afterName");
// download file "excelFile.xlsx" in the folder "dataFolder"
// to the local folder "driveDownloads"
/* download */
// download file 'excelFile.xlsx' in the folder 'dataFolder'
// to the local folder 'driveDownloads'
utilsGDrive.download({
fileName: "excelFile.xlsx",
parentName: "dataFolder"
}, "path/to/driveDownloads");
fileName: 'excelFile.xlsx',
parentName: 'dataFolder'
}, 'path/to/driveDownloads');
// upload file "report.pdf" to the folder in Google Drive
// with the id "folderId"
/* upload */
// upload file 'report.pdf' to the folder in Google Drive
// with the id 'folderId'
utilsGDrive.upload({
localPath: "path/to/report.pdf",
parentId: "folderId"
localPath: 'path/to/report.pdf',
parentId: 'folderId'
});
// move folder "reports2020" to the folder "reports"
utilsGDrive.move("path/to/reports2020", "path/to/reports");
/* move */
// move folder 'reports2020' to the folder 'reports'
utilsGDrive.move('path/to/reports2020', 'path/to/reports');
// delete file with id "fileId"
utilsGDrive.del("fileId");
/* rename */
// change name of folder from 'beforeName' to 'afterName'
utilsGDrive.rename({folderName: 'beforeName'}, 'afterName');
// make a new folder in the folder "parentFolder"
utilsGDrive.makeFolder("newFolder", {parentName: "parentFolder"});
/* delete */
// delete file with id 'fileId'
utilsGDrive.del('fileId');
/* make folder */
// make a new folder named 'newFolder' in the folder 'parentFolder'
utilsGDrive.makeFolder('newFolder', {parentName: 'parentFolder'});
/* batch request */
// create array of objects
// each object in the array represents a request
const requests = [
{
url: 'https://www.googleapis.com/drive/v3/files?q=name%20%3D%20%22Daily%20Logs%22',
method: 'GET',
},
{
url: 'https://www.googleapis.com/drive/v3/files?q=name%20%3D%20%22Reports%22',
method: 'GET'
}
];
// make batch request
utilsGDrive.batch(requests)
.then(responses => {console.log(responses)});
```

@@ -69,3 +104,3 @@

```
npm install utils-google-drive
npm i utils-google-drive
```

@@ -85,1 +120,4 @@

Follow the link and enter the code. A file named tokenGDrive.json containing an authorization token will be created in your working directory and setup will then be complete.
## **Contributions**
Contributions are welcome. There are many features of the Google Drive API that utils-google-drive doesn't currently address. Feel free to submit issues and enhancement requests as well.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc