Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using google drive appDataFolder to store app state with javascript on the client side

I've been trying to create this very simple web app that is using google drive appDataFolder to store and read its state, in json format. However, the documentation for v3 drive api doesn't contain comprehensive examples on how to achieve this easily.

So far I'm able to authorize and load the google drive api, but I wasn't able to create the configuration json file if it doesn't exist, or update its contents or read if it exists.

The calls I'm making are to: gapi.client.drive.files.get to retrieve the config json, gapi.client.drive.files.create to create the config json and gapi.client.drive.files.update to update its contents.

I've been trying to use the javascript Blob object to represent my file and its contents, but nothing has worked.

Given I have the config like for example { test: true } stringified and the file name my-app.json, how would I call the gapi.client.drive.files API to be able to create/update/read this config?

The retrieve part I tried to do it by first getting a list of the files in the app folder, match the config file by name, get its id, then request again for that file using the id. But since I wasn't able to create the file, I'm not sure if it works.

Code currently looks like this (important to note that this code gets build and it's run in the client browser, not on the server):

var config = require('../config/google-drive-config');

var authorize = function (immediate) {
  return gapi.auth.authorize({
    'client_id': config.clientId,
    scope: config.scopes.join(' '),
    immediate: !!immediate
  });
};

var loadDriveAPI = function () {
  return gapi.client.load(
    config.apiName,
    config.apiVersion
  );
};

var loadAppDataFileId = function () {
  return gapi.client.drive.files
    .list({
      spaces: 'appDataFolder'
    })
    .then(function(response) {
      return _(response.files)
        .find({ name: config.appDataFile })
        .get('id')
        .value();
    });
};

var loadAppData = function (fileId) {
  return gapi.client.drive.files
    .get({
      'fileId': fileId
    });
};

var saveAppData = function (appData, fileId) {
  var resource = {
    'name': config.appDataFile,
    'parents': 'appDataFolder'
  };

  var media = {
    mimeType: 'application/json',
    body: new Blob([JSON.stringify(appData)], { type: 'application/json' })
  };

  if (fileId) {
    return gapi.client.drive.files
      .update({
        fileId: fileId,
        media: media
      });
  }

  return gapi.client.drive.files
    .create({
      resource: resource,
      media: media,
      fields: 'id'
    });
};

module.exports = {
  authorize: authorize,
  loadDriveAPI: loadDriveAPI,
  loadAppDataFileId: loadAppDataFileId,
  loadAppData: loadAppData,
  saveAppData: saveAppData
};
like image 292
Adrian Bota Avatar asked Jul 05 '16 21:07

Adrian Bota


1 Answers

After a lot of trial and error, I finally got it working. I couldn't get gapi.client.drive.files.update to work, but it works with gapi.client.request:

var auth = function (immediate) {
  return gapi.auth.authorize({
    'client_id': 'YOUR CLIENT ID GOES HERE',
    // Permissions here can be more restrictive
    scope: 'https://www.googleapis.com/auth/drive',
    immediate: immediate
  });
};

var silentAuth = function () {
  return auth(true);
};

var popupAuth = function () {
  return auth(false);
};

var loadDriveAPI = function () {
  return global.gapi.client.load('drive', 'v3');
};

var getAppDataFile = function () {
  return gapi.client.drive.files
    .list({
      q: 'name="your-app-data-file-name.json"',
      spaces: 'appDataFolder',
      fields: 'files(id)'
    }).then(
      function (data) {
        if (_.isEmpty(data.result.files)) {
          throw "no files found";
        }

        return {
          fileId: data.result.files[0].id
        }
      }
    );
};

var createAppDataFile = function () {
  return gapi.client.drive.files
    .create({
      resource: {
        name: 'your-app-data-file-name.json',
        parents: ['appDataFolder']
      },
      fields: 'id'
    }).then(function (data) {
      return {
        fileId: data.result.id
      };
    });
};

var getAppDataFileContent = function (fileId) {
  return gapi.client.drive.files
    .get({
      fileId: fileId,
      // Download a file — files.get with alt=media file resource
      alt: 'media'
    }).then(function (data) {
      return {
        fileId: fileId,
        appData: data.result
      };
    });
};

var saveAppData = function (fileId, appData) {
  return gapi.client.request({
    path: '/upload/drive/v3/files/' + fileId,
    method: 'PATCH',
    params: {
      uploadType: 'media'
    },
    body: JSON.stringify(appData)
  });
};

module.exports = {
  silentAuth: silentAuth,
  popupAuth: popupAuth,
  loadDriveAPI: loadDriveAPI,
  getAppDataFile: getAppDataFile,
  createAppDataFile: createAppDataFile,
  getAppDataFileContent: getAppDataFileContent,
  saveAppData: saveAppData
};

All the methods above return a promise. There is a dependency on lodash

like image 181
Adrian Bota Avatar answered Oct 17 '22 01:10

Adrian Bota