Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update (Overwrite) one Apps Script file with another Apps Script file using Apps Script Code

Overwrite file. Overwrite Apps Script file.

This is not a question to create a new Apps Script file. That won't help me. I need to update an existing Apps Script file. This question is similar to creating a new file, but it's not the same issue. The syntax for an update, and the requirements for an update may be different enough from creating a new file, that I can't get a solution from the answer about creating a new file. I've looked at an answer for creating a new file, and that has not answered my question.

I have tried using the Advanced Drive Service to update an existing Apps Script file with another Apps Script file.

function updateMyScript() {
  var targetFileID = 'File ID';

  var dataSource = {
    "files": [
      {
        "id":"739a57da-f77c-4e1a-96df-7d86ef227d62",
        "name":"Code",
        "type":"server_js",
        "source":"function doGet() {\n  return HtmlService.createHtmlOutputFromFile(\u0027index\u0027);\n}\n"
      },
      {
        "id":"2c7e8b5a-dbc5-4cd2-80e9-77b6291b3167",
        "name":"index",
        "type":"html",
        "source":"\u003chtml\u003e\n  \u003cbody\u003e\n    New message!!\n  \u003c/body\u003e\n\u003c/html\u003e"
      }
    ]
  };

  var filesResource = Drive.Files.get(targetFileID);
  var blob = Utilities.newBlob(JSON.stringify(dataSource), "application/vnd.google-apps.script+json");
  var whatRezult = Drive.Files.update(filesResource, targetFileID, blob, {"convert":"true"});

  Logger.log('whatRezult: ' + whatRezult);
};

The id properties in the dataSource object are id's of each specific .gs or html file inside of the project. I got those id's by downloading the "target" Apps Script file to JSON, then opening up the JSON file and copying out the file id's. So, I know that those are correct. I'd like a way to retrieve those individual file ID's from the project with code. The post about creating a new apps script file, does not explain how to get the "sub" ID's from the project file. The project file ID is not the same as each file ID inside of the project. The name and type properties are obvious. And there are only two types of files which, from the example, have types of server_js and "html". It looks like the source for the internal files to the Apps Script project file can be a string literal. So, you can just type in whatever you want the replacement content to be.

The target ID is self explanatory.

If there is a way to do this with either the Advanced Drive Service or UrlFetchApp.fetch() that will answer my question. I only want to use Apps Script. So, I'm not looking for a solution written in some other language, or that is run from outside of Apps Script.

With the above code, I'm getting an error from the next to last line:

Drive.Files.update(filesResource, targetFileID, blob, {"convert":"true"});

The error is:

The app does not have the required scope to update Apps Scripts.

So, obviously, it's looking for a scope setting to be indicated somewhere. I'm guessing that it would go into the the fourth parameter for the options.

like image 297
Alan Wells Avatar asked Jan 07 '23 22:01

Alan Wells


1 Answers

You need to ask for the special Drive-AppsScript scope:

https://www.googleapis.com/auth/drive.scripts

Since you cannot tell Apps Script to ask this scope for you (it determines its own scopes automatically by analyzing your code). You need to do the oAuth dance yourself (by using Eric's lib for example). But then since you also cannot set this token you retrieved yourself for the script to use in its built-in or advanced service calls (not that I know of anyway), you'll have to do the UrlFetch call manually too, and pass your "custom" token in the header (like shown in the "create new script" question.

The UrlFetch call to update is very similar to the insert one. Just change the method to PUT and add the apps script project id in the path.

var url = "https://www.googleapis.com/upload/drive/v2/files/" + scriptID;
var requestBody = ...; //the same
var options = {
  "headers": {
     'Authorization': 'Bearer ' +  yourManuallyFetchedToken,
   }, 
  "contentType": "application/vnd.google-apps.script+json",
  "method" : "PUT", //changed here from POST to PUT
  "payload": JSON.stringify(requestBody)
}
like image 121
Henrique G. Abreu Avatar answered Feb 05 '23 12:02

Henrique G. Abreu