How to call an API running locally from Apps Script - google-apps-script

I am building a Container Bound Script using AppsScript wrt Google Sheets.
I am taking input by adding a menu on the google sheet as shown below,
And when clicked, prompted with a HTML form, in which we can upload a PDF, which is saved on Google Drive and the information regarding the file upload in saved on the google sheets, but I also want to send to a FastAPI running locally on my machine.
File Information stored on Google Sheets
Code for saving on Google Drive
function uploadFilesToGoogleDrive(data,name,type){
var datafile = Utilities.base64Decode(data)
//create a new blob with decode data, name, type
var blob2 = Utilities.newBlob(datafile, type, name);
var folder = DriveApp.getFolderById("<url>");
//Create new file (property of final user)
var newFile = folder.createFile(blob2);
var rowData = [
newFile.getName(),
newFile.getUrl(),
newFile.getDateCreated()
];
SpreadsheetApp.getActive().getSheetByName("sheet1").appendRow(rowData);
return newFile.getUrl()
}
For sending data to external API I came across Run app script function from website/localhost and Upload files from google drive to external api using google apps script
I am not getting a method through which I can send to API running locally without localtunnel.

It's not possible to run a Google Apps Scripts project locally, Google Apps Scripts projects run on Google Servers.
You can find more information here.
In your case, the only viable way I can think of for you to can call an API being served locally, would be to expose the appropriate endpoints from your API to the web. That way, the Google Servers responsible to run your script will have access to your API.
I understand that perhaps this solution is against the purpose of having an API server locally (since it won't be locally anymore), however Google Apps Script is designed to work on the Cloud.
In any case, you may find the Apps Script Class UrlFetchApp useful for making HTTP requests for your own API of any other.

Related

Add/Remove editors in Google sites using Google Apps Script

I am writing a google apps script to process bulk add/remove editors for some new Google Sites.
I am aware that google apps script currently doesn't support new google sites so I am trying to use DriveApp to manage the editors.
However the script doesn't work and returns the following:
Exception: Service error: Drive
whenever file.addEditor() or file.removeEditor() is used. I guess this just doesn't work for new Google Sites.
Are there other workarounds?
Make sure you're using the correct FileId with Sites as it's not quite as simple to acquire compared to other file types on Google Drive. When you're editing a Site page, the FileId can be found in the URL between /d/ and /p/.
Example: https://sites.google.com/d/????? this the file id ?????/p/!!!! not here !!!!/edit
I just successfully ran the below code to add/remove editors of a new Google Site.
const zFile= DriveApp.getFileById("????? this the file id ?????");
function addEditor(){
zFile.addEditor("pgsystemtester#gmail.com");
}
function removeEditor(){
zFile.removeEditor("pgsystemtester#gmail.com");
}

Is it possible to programmatically change Cloud Platform Project of a container-bound script?

I am essentially asking the same question from this post.
It is from a year+ ago, and it seems like it was never answered. I tried commenting to ask the original poster whether they were able to solve the problem, but my reputation to comment there is less than 50.
I am hoping that this helps bring the issue to the attention of more people too.
A Cloud Platform Project can not programatically be associated with an Apps Script project. There is an Apps Script API, which is capable of doing various things with Apps Script files, but the Apps Script API doesn't provide a way to associate an Apps Script project with a different Cloud project. That can only be done manually.
Some of the things that the Apps Script API can do:
Create a new Apps Script file with a base manifest file. https://developers.google.com/apps-script/api/reference/rest/v1/projects/create
Put content into an existing Apps Script file. Including updating the appsscript.json file: https://developers.google.com/apps-script/api/reference/rest/v1/projects/updateContent
An Apps Script project can be used as the basis for different things:
A Web App
An Add-on - Editor Add-on or G Suite
A library
API Executable
Bound to a document (Sheet, Form, Doc, Slides)
How the Apps Script file behaves is controlled through the manifest file. The manifest file can be configured to be a web app:
https://developers.google.com/apps-script/manifest#webapp
So, the manifest file can be configured to make the Apps Script project a Web App and the Apps Script API can update the manifest file. Therefore, you can create an Apps Script file as a Web App programmatically. But creating the Apps Script file and configuring it through the manifest file to be a Web App doesn't publish it.
Once the manifest file is configured to define the Apps Script file as a Web App, when the Apps Script project is deployed, it automatically is deployed as a Web App.
An Apps Script file can be programmatically deployed:
https://developers.google.com/apps-script/api/reference/rest/v1/projects.deployments/create
You can see the changes in "Deployments" dialog box by opening up the Deployments dialog before the project has been published as a Web App. The Deployments dialog is opened up from the code editor. If you compare the Deployments dialog content before and after the project has been published as a Web App, you'll see the difference.
If you manually publish an Apps Script file as a Web App, and then you look at the "Publish Menu" -> "Deploy From Manifest" dialog box, you'll see that a new version has been created, and you'll see an icon of the world. I believe that the world icon is the indicator of the type of deployment being a Web App.
So if you want to do this completely programmatically, there are multiple steps.
Create the Apps Script file
Update the Apps Script file with content including the appsscript.json file
Create a new deployment
And the Apps Script API can be used from an Apps Script project by using the REST API and UrlFetchApp.fetch(url,options)
You don't need to use an OAuth library to do this from Apps Script. An
access token can be obtained with:
var accessTkn = ScriptApp.getOAuthToken()
The structure of the content to update the Apps Script file is described at:
https://developers.google.com/apps-script/api/reference/rest/v1/projects/updateContent#request-body
An example of the code to overwrite an existing Apps Script file is:
function overWriteAppsScriptFile_(scriptId,content,theAccessTkn) {
try{
var options,payload,response,url;
if (!content) {
throw new Error('failed to pass in content');
return;
}
if (!theAccessTkn) {
theAccessTkn = ScriptApp.getOAuthToken();
}
url = "https://script.googleapis.com/v1/projects/" + scriptId + "/content";
options = {
"method" : "PUT",
"muteHttpExceptions": true,
"headers": {
'Authorization': 'Bearer ' + theAccessTkn
},
"contentType": "application/json",//If the content type is set then you can stringify the payload
"payload": JSON.stringify(content)
};
response = UrlFetchApp.fetch(url,options);
//llz('typeof response 38',typeof response)
//llz('response.getResponseCode() 39',response.getResponseCode())
//llz('response 39',JSON.stringify(response).slice(0,45))
return response;
} catch(e) {
myErrorHandling_(e,'Error updating Apps Script file');
//llz('error',e.message)
//llz('stack',e.stack)
}
};
There is also gcloud commands that can be used for managing Google Cloud projects.
Gcloud commands can be run from the Google Cloud Shell.
https://cloud.google.com/sdk/gcloud/reference/projects
I don't know if you can start with the Google Cloud project, and then associate a different Apps Script project to it.

Authorizing Google Charts to access private spreadsheets

I am trying to create a Web App using Google Apps Script to query data from my Google Sheet using Google Charts.
I have been able to successfully query the spreadsheet when the Google Sheet is publicly shared, however since the spreadsheet contains confidential info I would rather do it privately using authorizations.
The reason why I want to use Google Charts visualisation functions (as opposed to the server side Spreadsheet App) is because of the speed of querying large data sets.
I have tried following the steps in the above documentation. That is, creating a client id then using the gapi.auth library to authenticate myself but I continue to receive an error.
When i add the authorization library and first part of the code from the documentation (with console.log simply to see where it get's up to):
<script src="https://apis.google.com/js/auth.js?onload=init"></script>
<script>
var clientId = '1234.apps.googleusercontent.com';
var scopes = 'https://spreadsheets.google.com/feeds';
function init() {
console.log("here");
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true},handleAuthResult);
}
</script>
I receive the following error:
1289869776-mae_html_user_bin_i18n_mae_html_user.js:41 dropping
postMessage.. was from unexpected window
Any guidance is appreciated.
Since you are creating your web app using Google Apps Script, it's not necessary to "authorize Google Charts to access private charts" because you could use Google Apps Script services and methods to get the data from the spreadsheets and pass them to Google Charts.
On Converting from UiApp + Chart Service to Html Service + Google Visualization API it's shown how to convert the old dashboard example from from UiApp + Chart Service to HtmlService + Google Visualization API. This illustrates how to create a Google Apps Script web app that builds a chart from Google Spreadsheet data without "requiring authorization" as it's "implicitly" handled by Google Apps Script.
From the above link
Two functions cooperate to retrieve the dashboard’s data and display it. As soon as the visualization API is loaded, the sendQuery() function is invoked. Using the google.script.run facility, it sends its request to the server-side getSpreadsheetData() function. This is an asynchronous operation, so two callbacks are provided, a successHandler and a failureHandler. One or the other will receive the result of the server call, depending on the outcome.
H/T to jfllmartin, author of an answer to Converting my google dashboard app from the UI service to the HTML service where the above link was shared.
Related
How to create google dashboard including piechart and range select filter from a spreadsheet?
Display Spreadsheet data in Sites with Html Service
can I suggest you change from using Google sheets to using firebase with Google sheets or just Firebase, and then with Google appscript in the back end.
I often use a Google script to problematically update Firebase with data from the Google sheet. I then enjoy the speed and security of Firebase to deliver a super fast user experience.
There are two go to pages for using Firebase in appscript. The example page and the quick start.
Furthermore, I gave up using Google's own charting library and starting using high charts or chartJS, as they are more accessible.

How to expose a web API to a google apps script

I have a google apps spreadsheet, and I want to write a script that can be accessed via any browser, will generate a response using data from the spreadsheet, and return it to the browser.
I put in a lot of data in the spreadsheet that is required for my app. I want to automate the process of getting the data from the spreadsheet and integrating into the app before creating a build. Right now I run the script manually, download the result, and copy it into the app's data folder.
Ideas?
You can interact with your script via HTTP Post
doPost Trigger
Here is a little example of a doPost function
function doPost(e){
return ContentService.createTextOutput(SpreadsheetApp.openById(id).getSheetByName(name).getDataRange().getValues())
}

Get JSON of container-bound Google Apps-Script through Apps-Script or download

If you create a non-container bound g-apps script (i.e. not as part of a gDoc or a gSheet), you can download it (however not view as a .json directly in the browser from the link) from gDrive as a .json. If you download a gDoc or gSheet, it converts to xlsx or docx and opening these with a zip viewer shows a number of files (many of type xml) however none contain the Google version's attached scripts.
Is there a way to read script files as a .json from within another Google Apps
Script? perhaps using the Drive-API or with g-a-s. DriveApp class?
Is there a way to download or read through DriveApp, the .jsons of
container bound scripts (which are usually invisible from all but within the original gFile)?
Update
Based on Kriggs, added a Logger.log(link) and this works great for stand-alone scripts.
How about for container-bound?
for stand alone script files:
exportLinks={
application/vnd.google-apps.script+json=
script.google.com/feeds/download/export?id=[scriptId]&format=json
}
for container-bound script files, there are links to csv, sheet and pdf, but no script json.
exportLinks= {
text/csv=docs.google.com/spreadsheets/export?id=[sheetId]&exportFormat=csv,
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet=
docs.google.com/spreadsheets/export?id=[sheetId]exportFormat=xlsx,
application/pdf=
docs.google.com/spreadsheets/export?id=[sheetId]&exportFormat=pdf
}
Update
In Google sheet, go to Tools->script Editor->
URL in address bar looks like:
https://script.google.com/macros/d/
[ProjectKey]/edit?uiv=2&mid=[aVeryLongAlphaNum]
this is the download json:
https://script.google.com/feeds/download/export?id=[ProjectKey]
Question is, can we use the Drive API to find [ProjectKey]
Have there been any feature requests for DriveApp/Drive-API methods to seek Project Keys in your account?
Would there be a way to test if a file has a container bound script? Then the question is, is the script included in the file size (this can be easily tested, however it is unknown to the asker at this point).
Something like this may work although it looks computationally costly:
var SizeOfFile = yourFile.getSize();//
var charsInFile = yourFile.getAsString();
var unicodeSizeReference = [];//get bytes per character array
charsInFile.sort()
//find frequency of characters then multiply from unicoseSizeReference.
//there could be other gotchas as well, however this is just testing for feasibility
var SizeOfTextInFile = [/*#of chars in file name and sheetname*/]+[/*#of chars in all sheets*/];
SizeOfTextInFile *= unicodeBytesPerCharacter;//ranges from 1 to 4
var someThreshold = 10;//bytes
var hasScript=0;
if ([SizeOfFile - SizeOfTextInFile] > someThreshold) hasScript=1
Yes you have to get it trough the Drive API with OAuth2, I used the DriveApp to get the fileId, but you can modify to use Drive api aswell. To enable the Drive API go to Resources -> Advanced Google Services, find the Drive API and turn on.
When you send a get with Drive you get back an object of the file which contains the property exportLinks, using it you fetch the URL with OAuth2 authentication (the ScriptApp.getOAuthToken()), the fetched string will be a JSON, which has the Array fileswith the colection of scripts.
function getAppsScriptAsJson( fileName ) {
var fileDrive = Drive.Files.get( DriveApp.getFilesByName( fileName ).next().getId() );
var link = JSON.parse(fileDrive)[ 'exportLinks' ][ 'application/vnd.google-apps.script+json' ];
var fetched = UrlFetchApp.fetch(link, {headers:{'Accept':'application/vnd.google-apps.script+json', "Authorization":'Bearer '+ScriptApp.getOAuthToken()}, method:'get'});
return JSON.parse(fetched.getContentText());
}
As for container bound:
DriveApp can't get it by name
It doesn't display an ID anywhere, just the project key
Drive API can't lookup by the project id, nor DriveApp
Drive API can't find by the name
There's no reference of the script from the returned object from Drive API nor the DriveApp
I guess it is pretty much incognito, doubt there's any way ATM.
You can always make a Standalone app and set it as a library for the Spreadsheet...