Skip to content

Commit

Permalink
add drive.x.hexid(), code, tests, and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
DrPaulBrewer committed May 13, 2018
1 parent 958f968 commit b6c0191
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 35 deletions.
37 changes: 26 additions & 11 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ const pReduce = require('p-reduce');
const Boom = require('boom');
const digestStream = require('digest-stream');
const ssgd = require('search-string-for-google-drive');
const crypto = require('crypto');

const folderMimeType = 'application/vnd.google-apps.folder';

function extensions(drive, request, rootFolderId, spaces) {
function extensions(drive, request, rootFolderId, spaces, salt) {
const x = {};

function addNew(meta) {
Expand Down Expand Up @@ -45,6 +46,21 @@ function extensions(drive, request, rootFolderId, spaces) {
}

x.aboutMe = driveAboutMe;

async function driveHexid(){
if (!salt) throw Boom.badImplementation("missing salt");
if (!crypto) throw Boom.badImplementation("missing crypto");
const info = await driveAboutMe();
const salty = salt+(info.user.emailAddress.trim().replace('@','.'));
return (
crypto
.createHash('sha1')
.update(salty)
.digest('hex')
);
}

x.hexid = driveHexid;

function driveSearcher(options) {
let limit = (options.limit || 1000);
Expand Down Expand Up @@ -376,21 +392,21 @@ function extensions(drive, request, rootFolderId, spaces) {
return x;
}

function decorate(drive, request) {
function decorate(drive, request, salt) {
// drive is delivered from googleapis frozen, so we'll refreeze after adding extensions
const extras = {};
extras.x = extensions(drive, request, 'root', 'drive');
extras.x.appDataFolder = extensions(drive, request, 'appDataFolder', 'appDataFolder');
extras.x = extensions(drive, request, 'root', 'drive', salt);
extras.x.appDataFolder = extensions(drive, request, 'appDataFolder', 'appDataFolder', salt);
return Object.freeze(Object.assign({}, drive, extras));
}

function decoratedGoogleDrive(googleapis, request, keys, tokens) {
function decoratedGoogleDrive(googleapis, request, keys, tokens, salt) {
if (!googleapis)
throw new Error("googleapis not defined");
throw Boom.badImplementation("googleapis not defined");
if (!googleapis.auth)
throw new Error("googleapis.auth not defined");
throw Boom.badImplementation("googleapis.auth not defined");
if (!googleapis.auth.OAuth2)
throw new Error("googleapis.auth.OAuth2 not defined");
throw Boom.badImplementation("googleapis.auth.OAuth2 not defined");
const OAuth2 = googleapis.auth.OAuth2;
const auth = new OAuth2(keys.key, keys.secret, keys.redirect);
// possible patch for googleapis 23.0.0 missing .setCredentials bug
Expand All @@ -403,10 +419,9 @@ function decoratedGoogleDrive(googleapis, request, keys, tokens) {
}
const drive = googleapis.drive({ version: 'v3', auth });
if (typeof(drive) !== 'object')
throw new Error("drive is not an object, got: " + typeof(drive));
return decorate(drive, request);
throw Boom.badImplementation("drive is not an object, got: " + typeof(drive));
return decorate(drive, request, salt);
}


decoratedGoogleDrive.decorate = decorate;
module.exports = decoratedGoogleDrive;
20 changes: 19 additions & 1 deletion test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const str = require('string-to-stream');
const Boom = require('boom');
const folderMimeType = 'application/vnd.google-apps.folder';

const salt = "100% Pure Sea Salt";

const keys = {
key: process.env.GOOGLE_DRIVE_CLIENT_ID,
secret: process.env.GOOGLE_DRIVE_SECRET,
Expand All @@ -34,7 +36,7 @@ describe('decorated-google-drive:', function () {
describe(' initializing ', function () {
it('should not throw an error', function () {
function init() {
drive = driveZ(google, request, keys, tokens);
drive = driveZ(google, request, keys, tokens, salt);
}
init.should.not.throw();
});
Expand Down Expand Up @@ -67,6 +69,22 @@ describe('decorated-google-drive:', function () {
});
});
});
const sha1Regex = /^[0-9a-f]{40}$/;
describe(' drive.x.hexid ', function(){
it('should return a 40 char hex id', async function(){
const hex = await drive.x.hexid();
return hex.should.match(sha1Regex);
});
it('should consistently return the same 40 char hex when called 3 times', async function(){
return Promise
.all([drive.x.hexid(), drive.x.hexid(), drive.x.hexid()])
.then(([a,b,c])=>{
a.should.match(sha1Regex);
a.should.equal(b);
a.should.equal(c);
});
});
});
describe(' drive.x.appDataFolder.upload2: upload a string to appDataFolder ', function () {
let uploadResult;
before(function () {
Expand Down
28 changes: 27 additions & 1 deletion testDoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- [decorated-google-drive:](#decorated-google-drive)
- [ initializing ](#decorated-google-drive-initializing-)
- [ drive.x.aboutMe ](#decorated-google-drive-drivexaboutme-)
- [ drive.x.hexid ](#decorated-google-drive-drivexhexid-)
- [ drive.x.appDataFolder.upload2: upload a string to appDataFolder ](#decorated-google-drive-drivexappdatafolderupload2-upload-a-string-to-appdatafolder-)
- [ drive.x.upload2: upload a file README.md to Drive folder /path/to/test/Files](#decorated-google-drive-drivexupload2-upload-a-file-readmemd-to-drive-folder-pathtotestfiles)
- [ after drive.x.upload2 ](#decorated-google-drive-after-drivexupload2-)
Expand All @@ -19,7 +20,7 @@ should not throw an error.

```js
function init() {
drive = driveZ(google, request, keys, tokens);
drive = driveZ(google, request, keys, tokens, salt);
}
init.should.not.throw();
```
Expand Down Expand Up @@ -67,6 +68,31 @@ return Promise.all([
});
```

<a name="decorated-google-drive-drivexhexid-"></a>
## drive.x.hexid
should return a 40 char hex id.

```js
async function (){
const hex = await drive.x.hexid();
return hex.should.match(sha1Regex);
}
```

should consistently return the same 40 char hex when called 3 times.

```js
async function (){
return Promise
.all([drive.x.hexid(), drive.x.hexid(), drive.x.hexid()])
.then(([a,b,c])=>{
a.should.match(sha1Regex);
a.should.equal(b);
a.should.equal(c);
});
}
```

<a name="decorated-google-drive-drivexappdatafolderupload2-upload-a-string-to-appdatafolder-"></a>
## drive.x.appDataFolder.upload2: upload a string to appDataFolder
uploading the string to appDataFolder file myaccount should resolve with expected file metadata.
Expand Down
47 changes: 25 additions & 22 deletions testResults.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,33 @@
✓ drive should not be undefined
✓ drive.x should be an object
drive.x.aboutMe
✓ should return the test users email address (399ms)
✓ should return a storageQuota object with properties limit, usage (238ms)
✓ drive.about.get still works, as well, and the outputs match (176ms)
✓ should return the test users email address (404ms)
✓ should return a storageQuota object with properties limit, usage (173ms)
✓ drive.about.get still works, as well, and the outputs match (166ms)
drive.x.hexid
✓ should return a 40 char hex id (172ms)
✓ should consistently return the same 40 char hex when called 3 times (173ms)
drive.x.appDataFolder.upload2: upload a string to appDataFolder
✓ uploading the string to appDataFolder file myaccount should resolve with expected file metadata
✓ drive.x.appDataFolder.searcher should report there is exactly one myaccount file in the folder and it should match upload file id
✓ drive.x.appDataFolder.contents should resolve to contents Hello-World-Test-1-2-3
drive.x.upload2: upload a file README.md to Drive folder /path/to/test/Files
✓ uploading the README.md file to /path/to/test/Files/README.md should resolve with expected file metadata
✓ the parents[0] folder should have the name 'Files' (180ms)
✓ searching the parents[0] folder for README.md find a file with matching id (235ms)
✓ the parents[0] folder should have the name 'Files' (154ms)
✓ searching the parents[0] folder for README.md find a file with matching id (242ms)
after drive.x.upload2
✓ searching root for anything should yield folder 'path' with .isFolder===true (298ms)
✓ searching root for folders should yield folder 'path' with .isFolder===true (247ms)
✓ searching root for non-folders should be empty (212ms)
✓ searching all folders for any non-trashed file should be non-empty and include file README.md in results (303ms)
✓ searching all folders or a file with appProperties: { 'role': 'documentation' } should be empty (1061ms)
✓ checking existence of /path/to/test/Files/README.md with drive.x.findPath should yield expected file metadata (1276ms)
✓ checking existence of /path/to/test should yield expected folder metadata (720ms)
✓ checking existence on wrong path should throw Boom.notfound (242ms)
✓ downloading content with drive.x.download should yield contents string including 'License: MIT' (1419ms)
✓ updating README.md appProperties to {'role': 'documentation'} should succeed (1748ms)
✓ searching all folders or a file with appProperties: { 'role': 'documentation' } should find README.md (350ms)
✓ drive.x.upload2 uploading the file again with {clobber:false} will throw Boom.conflict error because file already exists (1191ms)
✓ searching root for anything should yield folder 'path' with .isFolder===true (211ms)
✓ searching root for folders should yield folder 'path' with .isFolder===true (207ms)
✓ searching root for non-folders should be empty (245ms)
✓ searching all folders for any non-trashed file should be non-empty and include file README.md in results (246ms)
✓ searching all folders or a file with appProperties: { 'role': 'documentation' } should be empty (213ms)
✓ checking existence of /path/to/test/Files/README.md with drive.x.findPath should yield expected file metadata (1184ms)
✓ checking existence of /path/to/test should yield expected folder metadata (718ms)
✓ checking existence on wrong path should throw Boom.notfound (254ms)
✓ downloading content with drive.x.download should yield contents string including 'License: MIT' (1647ms)
✓ updating README.md appProperties to {'role': 'documentation'} should succeed (1697ms)
✓ searching all folders or a file with appProperties: { 'role': 'documentation' } should find README.md (222ms)
✓ drive.x.upload2 uploading the file again with {clobber:false} will throw Boom.conflict error because file already exists (1154ms)
drive.x.upload2: upload test/test.zip to Drive folder /path/to/test/Files
✓ uploading the test.zip file to /path/to/test/Files/test.zip should resolve with expected file metadata and md5 match
create folder /path/to/test2
Expand All @@ -43,12 +46,12 @@
use folderId of /path/to/test2 to upload test.zip
✓ uploading the test.zip file to /path/to/test2/test.zip should resolve with expected file metadata and md5 match
cleanup via drive.x.janitor
✓ janitor hopefully deletes the README.md file(s) OK and resolves correctly (1766ms)
✓ drive.x.findPath will throw Boom.notFound if the file was successfully deleted (1205ms)
✓ janitor will throw an error if told to delete an invalid file (150ms)
✓ janitor hopefully deletes the README.md file(s) OK and resolves correctly (1730ms)
✓ drive.x.findPath will throw Boom.notFound if the file was successfully deleted (1193ms)
✓ janitor will throw an error if told to delete an invalid file (147ms)
✓ janitor should not throw an error if given an empty filelist
✓ final cleanup: delete the path folder and check non-existence (1127ms)
✓ final cleanup: delete the path folder and check non-existence (1349ms)


38 passing (45s)
40 passing (25s)

0 comments on commit b6c0191

Please sign in to comment.