Uploading file to spreadsheet requires special permissions - google-apps-script

I'm writing a script for Google Sheets which opens a form for uploading a file, and calls server-side function to handle the uploaded file. The problem I have is that the server-side function does not get called and failure handler is invoked with error message saying that I have no permissions to do the operation.
If I call the server side function with null argument instead of passing in the form then the function successfully gets called.
Here is the script I have:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var csvMenuEntries = [{name: "Process bank statement file", functionName: "openUploadPaymentsDialog"}];
ss.addMenu("AG_Menu", csvMenuEntries);
}
function openUploadPaymentsDialog(e) {
var html = HtmlService.createHtmlOutputFromFile('UploadPaymentsDialog');
SpreadsheetApp.getUi().showModalDialog(html, 'Upload .NDA file');
Logger.log('dialog opened');
}
function handleFileUpload(theForm) {
Logger.log('file uploaded');
}
And HTML form:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form>
<input type="file" name="theFile"/><br/><br/>
<input type="button" value="Submit" onclick="onSubmit(this.parentNode);"/>
</form>
<div id="output"/>
<script>
function onSubmit(theForm) {
google.script.run
.withSuccessHandler(onSuccess)
.withFailureHandler(onFailure)
.handleFileUpload(theForm);
//if I call handleFileUpload with null as argument then call succeeds
}
function onFailure(error){
var div = document.getElementById('output');
div.innerHTML = "ERROR: " + error.message;
}
function onSuccess(f){
google.script.host.close();
}
</script>
</body>
</html>
The script is bound to the spreadsheet and I'm not the owner of the spreadsheet, but I have permissions to edit. I'm running the script from my user (not owner).
Is it so that only owner can upload files? Why is that?

I found out that it is probably some problem with browser I'm using. It is Google Chromium under Debian Linux. I have just tried it with Firefox and it works OK.

Related

Make a google Script Run from a HTML front

I have a script that will run an HTTP request to our server and bring the most recent orders.
We want to be able to run the script on request but also be able to Install it as an addon to different sheets for our different stores
The front End of the app is generated by this html
<link href="https://ssl.gstatic.com/docs/script/css/add-ons.css"
rel="stylesheet">
<div class="sidebar">
<div class="block form-group">
<button class="blue" id="load_orders">Import Order Data</button>
</div>
<div id='orders'></div>
</div>
<script>
$(function onSuccess(load_orders) {
});
withSuccessHandler(onSuccess).importcogs();
});
</script>
Then on the .gs I have a script to show the app (before we Deploy it) and the import orders script
function onInstall() {
onOpen();
}
function onOpen() {
SpreadsheetApp.getUi()
.createAddonMenu() // Add a new option in the Google Docs Add-ons Menu
.addItem("Import Order Data", "showSidebar")
.addToUi(); // Run the showSidebar function when someone clicks the menu
}
function showSidebar() {
var html = HtmlService.createTemplateFromFile("Front")
.evaluate()
.setTitle("Import Order - Search"); // The title shows in the sidebar
SpreadsheetApp.getUi().showSidebar(html);
}
function importcogs() {
Logger.log("import begin");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var urlsheet = ss.getSheetByName("GetInfo");
var request = urlsheet.getRange(5,2).getValue();
Logger.log(request);
var response = UrlFetchApp.fetch(request);
Logger.log("download data finish");
Logger.log(response.getContentText());
var sheet = ss.getSheetByName("Data");
var obj = JSON.parse(response);
let vs = obj.data.map(o => Object.values(o));//data
vs.unshift(Object.keys(obj.data[0]));//add header
sheet.getRange(1,1,vs.length, vs[0].length).setValues(vs);//output to spreadsheet
}
I Haven't been able to link the "Import orders" button to the script for some reason .
As what Cooper has said in the above comment, it is not a standalone function:
Sample Usage:
google.script.run.withSuccessHandler(onSuccess).importcogs();
This will in return runs the importcogs function and will trigger onSuccess function if the function successfully finished. Parameters of the onSuccess will be the return of the function called importcogs if it has any.

How to get file(s) from an HTML file input and send it as an attachment to an email in Google Apps Script?

This HTML code takes file inputs using Google Script's class HTML service :
(SEE BELOW)
I would like to get the value(s)(the files) of the input field, send to the my .gs file and send that as an attachment to the email.
Getting the value from the input field simply returns the directory of the file, which is no help because Google Apps Script can't obtain files from local drive.
I have done a lengthy research with this problem and I can't find anyone with a similar issue.
Stack Code.gs
function myFunction() {
var html = HtmlService.createHtmlOutputFromFile('Stack HTML').setWidth(250).setHeight(250);
SpreadsheetApp.getUi().showModalDialog(html,'Get File');
}
function processEmail(files){
var subject = 'Subject';
var message = 'Test';
var recipient = 'test#gmail.com';
GmailApp.sendEmail(recipient, subject, message, {attachments: files, htmlBody: message, name:'Stack Overflow Test'}); // Doesn't work
}
Stack HTML.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form method="post" enctype="multipart/form-data">
<div>
<input type="file" id= "file" multiple = "true">
</div>
</form>
<br><div style="text-align:center"> <input type="submit" name = "submitButton" onclick = "send()" id = "sendButton" value="Send"></div>
<script>
function done(e){
google.script.host.close();
}
function send(){
var files = document.getElementById("file").value;
console.log(files);
google.script.run.withSuccessHandler(done).processEmail(files);
}
</script>
</body>
</html>
You want to upload multiple files from local PC to Google Drive using HTML and Javascript.
You want to send the uploaded files as the attachment files of an email.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this modification? Please think of this as just one of several answers.
Solution:
From your question, the files are used as the attachment files of an email. So I thought that the following flow can be used for your situation.
Retrieve all files from the local PC.
All files are summarized as an object.
At this time, the files are converted to the base64 string value.
Send the object to Google side.
Convert the object to file blob at GAS side.
Modified script:
Please modify send() in HTML side as follows.
function send() {
const f = document.getElementById('file');
Promise.all([...f.files].map((file, i) => {
const fr = new FileReader();
return new Promise(r => {
fr.onload = e => {
const data = e.target.result.split(",");
r({fileName: file.name, mimeType: data[0].match(/:(\w.+);/)[1], data: data[1]});
}
fr.readAsDataURL(file);
});
}))
.then(obj => {
google.script.run.withSuccessHandler(done).processEmail(obj);
});
}
And please modify processEmail() in GAS side as follows.
function processEmail(obj){
var files = obj.map(function(e) {return Utilities.newBlob(Utilities.base64Decode(e.data), e.mimeType, e.fileName)});
var subject = 'Subject';
var message = 'Test';
var recipient = 'test#gmail.com';
GmailApp.sendEmail(recipient, subject, message, {attachments: files, htmlBody: message, name:'Stack Overflow Test'});
}
References:
FileReader
Class Utilities
Uploading Multiple Files From Local To Google Drive using Google Apps Script

How to make a form using Google Sheets script editor

I need to create a Google sheet with 3 columns (column A: Name, column B: Gender and column C: E-mail)
Then I need to add a script to the sheet to make a form (For some reasons I can not use google forms) with the three related questions we just added in the sheet
I can do the form.html code but I am not so much familiar with JavaScript to connect the form to the sheet once submitted
I think it is something like this:
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('form.html');
}
function update spreadsheet {
var sheet = "get active spreadsheet"
...
I am not able to complete the above code, can anybody can help me with this?
You can deploy Apps Script as a Web App [1]. You'll need to create a html file [2] in which you'll put the form you want. Here [3] is well explain how to execute Apps Script functions with JavaScript in the html. Finally, in an Apps Script function you can use the SpreadsheetApp class to insert the values you want [4].
This would be an example code found on the documentation:
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// Prevent forms from submitting.
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
}
function updateUrl(url) {
var div = document.getElementById('output');
div.innerHTML = 'Got it!';
}
</script>
</head>
<body>
<form id="myForm" onsubmit="handleFormSubmit(this)">
<input name="myFile" type="file" />
<input type="submit" value="Submit" />
</form>
<div id="output"></div>
</body>
</html>
code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function processForm(formObject) {
var formBlob = formObject.myFile;
var driveFile = DriveApp.createFile(formBlob);
return driveFile.getUrl();
}
[1] https://developers.google.com/apps-script/guides/web
[2] https://developers.google.com/apps-script/guides/html/
[3] https://developers.google.com/apps-script/guides/html/communication
[4] https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app

The script completed but the returned value is not a supported return type?

I am working on a way to create a form from the ground up, I have no intentions of using google forms as it limits my options. But I am running into a problem when running my script. I get this error message when reaching the url extracted when I publish as a web app:
"The script completed but the returned value is not a supported return
type."
Here is the script I am using:
function doGet() {
return HtmlService.createTemplateFromFile('Index')
}
function doSomething(form) {
var spreadsheetKey = "1C26wx6zBCGvkQEVF2xMVRoR8L0NCXQAvjdJSlnE3Y7g";
var sheet = SpreadsheetApp.openById(spreadsheetKey).getActiveSheet();
var textBoxValue = form.textBoxName;
var lastRow = sheet.getLastRow();
var targetRange = sheet.getRange(lastRow+1,1,1,1).setValues([[textBoxValue]]);
}
and the correspnding index file, simply titled "Index":
<script>
function formSubmit() {
google.script.run.doSomething(document.forms[0]):
}
</script>
<form>
<input type="button" value"Not Clicked"
onclick="formSubmit()" />
<input type ="text" name="textBoxName" />
</form>
any suggestions on what might be wrong, I got this from somewhere else where it seemed to be working, but that was 2 years ago. Maybe something has changed in the mean time?
.evaluate() is needed after .createTemplate(), .createTemplateFromFile()

Google App Script - Display PDF on Form Submit

I have a current Google Form and App Script where the Apps Script is taking the form data, putting it into a spreadsheet template (which does some calculations) then e-mails that spreadsheet as a PDF.
Is there a way in Google Apps Script to have this PDF displayed in the web browser rather than being sent in an e-mail?
You can use this workround .
pag.html
<html>
<input type="submit" onclick="downloadPDF()"/>
Click here to open
<script>
function sucess(e) {
alert(e);
var downloadLink = document.getElementById("myDownloadLink");
downloadLink.href=e;
downloadLink.style.display = 'block';
}
function downloadPDF() {
google.script.run.withFailureHandler(alert).withSuccessHandler(sucess).getFile();
}
</script>
</html>
code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile("pag");
}
function getFile() {
return DriveApp.getFileById("1pczv0kRvgpI87owXWUXTtm4wXXsiG8-ErVWFtv05izI").getUrl();
}