Bryan P
Bryan P

Reputation: 5051

How to create a new script file via Apps Script & Drive SDK

Trying to create a new project with files with a call to the Drive SDK within Apps Script.

Where exactly would the following go in a UrlFetchApp request...

{
  "files": [
    {
      "id":"9basdfbd-749a-4as9b-b9d1-d64basdf803",
      "name":"Code",
      "type":"server_js",
      "source":"function doGet() {\n  return HtmlService.createHtmlOutputFromFile(\u0027index\u0027);\n}\n"
    },
    {
      "id":"3asf7c0d-1afb-4a9-8431-5asdfc79e7ae",
      "name":"index",
      "type":"html",
      "source":"\u003chtml\u003e\n  \u003cbody\u003e\n    New message!!\n  \u003c/body\u003e\n\u003c/html\u003e"
    }
  ]
}

It's from the import/export docs and in the example video Dan mentions the calls are for languages outside of Apps Script but requesting a list of script file types and the content of those files does work once the authorization is setup with Eric's oAuth2 library.

My most recent guess...

function createProject( ) {
  var token = getDriveService().getAccessToken(); // from Eric's oAuth2 lib

  var url = 'https://www.googleapis.com/upload/drive/v2/files?convert=true';

  // Where does this go?
  var files = {
    "files": [
      {
        "name":"Code",
        "type":"server_js",
        "source":"function doGet() {\n  return HtmlService.createHtmlOutputFromFile(\u0027index\u0027);\n}\n"
      },
      {
        "name":"index",
        "type":"html",
        "source":"\u003chtml\u003e\n  \u003cbody\u003e\n    Hello, world!!\n  \u003c/body\u003e\n\u003c/html\u003e"
      }
    ]
  };

  // Where does this go too?
  var metadata = {
    'title': 'script-test1',
    'mimeType': 'application/vnd.google-apps.script',
    "parents": [
      {
        "id": "0B2VkNbQMTnaCODBRVjZQcXBXckU"
      }
    ],
  };

  var options = {
    'headers' : {
      'Authorization': 'Bearer ' +  token,
      'Content-Type': 'application/vnd.google-apps.script+json',
    },
    'method' : 'POST',
    'payload' : files  // probably not right

  };

  var response = UrlFetchApp.fetch(url, options);
  Logger.log(response.getResponseCode());

}

An untitled Drive file of unknown type does get created and the payload does get inserted into it, but it's not converted to a script file type.

Going another route and just using...

var file = {
    "title": "Test script",
    "mimeType": "application/vnd.google-apps.script",
    "parents": [
      {
        "id": "[INSERT FOLDER ID HERE]"
      }
    ]
  };

Drive.Files.insert(file);

...throws an Internal error.

Also aware of the Drive insert docs that have a client-side JS example, but don't know how much of it should be translated over (if possible) to server-side Apps Script.

Upvotes: 3

Views: 995

Answers (1)

Ryan Roth
Ryan Roth

Reputation: 1424

You're almost there, but you have a few mistakes. Your first approach (using UrlFetch) has some errors in the options variable. Here's a doGet() function that (after verifying authorization) creates a new Apps Script Project and writes the UrlFetch response to the page:

function doGet() {
  var driveService = getDriveService();
  if (!driveService.hasAccess()) {
    var authorizationUrl = driveService.getAuthorizationUrl();
    var template = HtmlService.createTemplate(
        '<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' +
        'Refresh the page when authorization complete.');
    template.authorizationUrl = authorizationUrl;
    var page = template.evaluate();
    return page;
  } else {     
    var url = "https://www.googleapis.com/upload/drive/v2/files?convert=true";   
    var requestBody =  {
      "files": [
        {
          "name":"Code",
          "type":"server_js",
          "source":"function doGet() {\n  return HtmlService.createHtmlOutputFromFile(\u0027index\u0027);\n}\n"
        },
        {
          "name":"index",
          "type":"html",
         "source":"\u003chtml\u003e\n  \u003cbody\u003e\n    Created with Apps Script.\n  \u003c/body\u003e\n\u003c/html\u003e"
        }
      ]
    };

    var options = {
      "headers": {
         'Authorization': 'Bearer ' +  driveService.getAccessToken(),
       }, 
      "contentType": "application/vnd.google-apps.script+json",
      "method" : "post",
      "payload": JSON.stringify(requestBody)
    }

    var response = UrlFetchApp.fetch(url, options);
    return HtmlService.createHtmlOutput(response.getContentText());
  }
}

This code creates an Apps Script project file called "Untitled" in the root Drive folder. The options object should specify POST as the method for creating projects (default is GET), and the payload needs to be converted to a string from a JSON object to be understood by UrlFetch.

Alternatively, you can do the same thing by using the Advanced Drive Service in Apps Script instead of UrlFetch. The following code creates the same Apps Script project (but places it in the specified folder and names the file 'Test script'):

function createGoogleFileInFolder3() {  
    var requestBody =  {
      "files": [
        {
          "name":"Code",
          "type":"server_js",
          "source":"function doGet() {\n  return HtmlService.createHtmlOutputFromFile(\u0027index\u0027);\n}\n"
        },
        {
          "name":"index",
          "type":"html",
          "source":"\u003chtml\u003e\n  \u003cbody\u003e\n    Created with Apps Script.\n  \u003c/body\u003e\n\u003c/html\u003e"
        }
      ]
    };

  var resource = {
    "title": "Test script",
    "parents": [
      {
        "id": "<parent folder id here>"
      }
    ]
  };

  var blob = Utilities.newBlob(JSON.stringify(requestBody), "application/vnd.google-apps.script+json");

  Drive.Files.insert(resource, blob, {"convert":"true"});
}

Upvotes: 4

Related Questions