Is there a way to web invoke from PowerShell connection to web app created in google app script ?
When im running the request on normal sites I will receive back information containing Forms[], Images[], InputFields[] etc. However when I'm trying to run the same request on a https://script.google.com/a/macros/ web app all those fields are blank and i can only see a variable called el linking to field called sandboxFrame.
The app is a simple upload site to one of my google folders, everything is working when I'm in browser. I'm trying to automate the process through PowerShell script
HTML file
<!DOCTYPE html>
<html>
<body>
<input name="file" id="files" type="file" multiple>
<input type='button' value='Upload' onclick='getFiles()'>
</body>
<script>
function getFiles() {
const f = document.getElementById('files');
[...f.files].forEach((file, i) => {
const fr = new FileReader();
fr.onload = (e) => {
const data = e.target.result.split(",");
const obj = {fileName: f.files[i].name, mimeType: data[0].match(/:(\w.+);/)[1], data: data[1]};
google.script.run.withSuccessHandler((id) => {
console.log(id);
}).saveFile(obj);
}
fr.readAsDataURL(file);
});
}
</script>
</html>
GS script
function saveFile(obj) {
var folder = DriveApp.getFolderById('1w586veZcOZN_NnB90jaTZ12DF-jP005u');
var blob = Utilities.newBlob(Utilities.base64Decode(obj.data), obj.mimeType, obj.fileName);
return folder.createFile(blob).getId();
}
You would need to take advantage of the doPost function.
I assume you already know about the doGet function, but there is another function that you can use as part of a web app called doPost. This allows you to post data using something like the following from powershell:
Invoke-WebRequest https://script.google.com/a/macros/[SCRIPTID]?[QUERYSTRING] -Method POST
Where the [QUERYSTRING] is something like:
name=bartosz&stack=BartoszWolas&reputation=1000
Then within the doPost on the web app side you would write a function like this:
function doPost(e) {
const name = e.parameter.name; // bartosz
const stackAlias = e.parameter.stack; // BartoszWolas
const reputation = e.parameter.reputation; // 1000
}
Reference
web app
Related
I've read that you can make a Google Apps Script that shows a Facebook Feed, and then embed this in a Google Site, but I can't find any more information on how to do it and I can't figure it out myself.
When I try to make an Apps Script web app with a Facebook feed I get errors like:
Uncaught DOMException: Failed to set the 'domain' property on 'Document': Assignment is forbidden for sandboxed iframes.
This is from copying the "Facebook Javascript SDK" and "Page Feed" from Facebook Developers into an HTML file and deploying it as a web app. I gather it has something to do with how Apps Script sandboxes your code but I don't know what I have to do here.
For that matter, even if I try to make a simpler Apps Script with some static HTML, when I try to embed it from Drive into the site I get an error "Some of the selected items could not be embedded".
The New Google Sites doesn't support Google Apps Script.
Related question: Google App Scripts For New Google Sites Release
The new Google Sites does now support embedding apps script (make sure to deploy the apps script as a web app, set the right permissions, and use the /exec url and not your /dev one to embed).
I found I couldn't use the facebook SDK for videos because of the sandboxing. I used an iframe solution instead for videos, but maybe you could try something like this for the feed (I'm assuming you've registered your app in fb so you can get generate tokens):
In apps script, create a .gs file and an html file, roughly along the lines below (I haven't actually worked with returning feeds, so check the returned data structure and adjust accordingly)
//**feed.gs**
function doGet(e) {
return HtmlService
.createTemplateFromFile('my-html-file')
.evaluate();
}
function getToken() { //use your fb app info here (and make sure this script is protected / runs as you
var url = 'https://graph.facebook.com'
+ '/oauth/access_token'
+ '?client_id=0000000000000000'
+ '&client_secret=0x0x0x0x0x0x0x0x0x0x0x0x'
+ '&grant_type=client_credentials';
var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
var json = response.getContentText();
var jsondata = JSON.parse(json);
return jsondata.access_token;
}
function getFeed() {
var url = 'https://graph.facebook.com'
+ '/your-page/feed'
+ '?access_token=' + encodeURIComponent(getToken());
var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
var json = response.getContentText();
var jsondata = JSON.parse(json);
//Logger.log(jsondata); //check this and adjust following for loop and html showFeed function accordingly
var posts = {};
for (var i in jsondata) {
posts[i] = {"post":jsondata[i].message};
}
return posts;
}
<!--**my-html-file.html**-->
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
// The code in this function runs when the page is loaded (asynchronous).
$(function() {
google.script.run
.withSuccessHandler(showFeed)
.withFailureHandler(onFailure)
.getFeed(); //this function is back in .gs file and must return an array or object which gets auto-passed to the showFeed function below
});
function showFeed(posts) { //parameter name must match array or object returned by getFeed in gs file
var html = '';
for (var p in posts) {
html += '<p>' + posts[p].post + '</p>'; //instead of a string, you can build an array for speed
}
$('#feed').empty().append(html); //if you used an array for the html, you'd split it here
}
function onFailure(error) {
$('#feed').empty().append("Unable to retrieve feed: " + error.message); ;
}
</script>
</head>
<body>
<div id="feed">
Loading...
</div>
</body>
</html>
I created a web app form using Google Apps Script and the HTMLService.
It is a one-page form with a submit button at the bottom.
When submitted, the form validates whether the data input into the form is valid, and if valid, it logs the form data to a spreadsheet.
That all works so far.
I now need the user to be sent to a confirmation page, and the confirmation page needs to be able to have parameters passed to it (to display certain information on the confirmation page).
main.gs:
function doGet(e) {
var template = HtmlService.createTemplateFromFile('form');
return template.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function processFormSubmission(formData) {
Logger.log('starting processPoRequest');
Logger.log('po: ' + JSON.stringify(formData, null, 2));
// code for appending data to sheet here
}
form.html:
<!DOCTYPE html>
<form id="form1" name="form1">
<label for="info" id="info_label">Info</label>
<input id="info" name="info" type="text">
<input class="btn" id="button" onclick="onClickFunctions(document.getElementById('form1'))" type="submit" value="Submit">
</form>
<script>
function onClickFunctions(formData) {
console.log('starting onClickFunctions');
var allDataValid = validateForm(formData);
if (allDataValid === true) {
google.script.run.withSuccessHandler().processFormSubmission(formData);
}
}
function validateForm(form) {
console.log('starting validateForm');
var errors = 0;
var element = document.getElementById('info');
if (!form.info) { element.classList.add("validation_error"); errors++; if (errors === 1) element.focus(); }
else element.classList.remove("validation_error");
if (errors > 0) return false;
else return true;
}
</script>
confirmation.html:
<!DOCTYPE html>
<?!= confirmationMessage ?>
I don't know what to put in .withSuccessHandler() to make it so that the user is brought to the confirmation page.
I've Googled this extensively and found these results on Stack Overflow, and each one suggests a different solution, but none of them actually include complete working code for a solution:
Possible solutions using doPost:
Send form by email and track responses in spreadsheet
HtmlService doPost With Google Docs Form
HtmlService doPost
I messed around with doPost but I couldn't figure out how to get it to be invoked, and I couldn't find any official documentation in the HTMLService docs.
Possible solution using the link to the web app in an a href:
href in HtmlService
If my button was a link that looked like a button, I'm not sure how I would execute the form validation function when the link is clicked.
I have done this two different ways.
had a hidden statement that gets shown, and the form gets hidden.
or
use .withSuccessHandler(google.script.host.close()), but have the processFormSubmission function open a new dialogue.
Hi the below script has allowed me to upload files to Google drive however I can not seem to get the data entered in 'Name' and 'Date" to enter in to a spreadsheet.
Can anyone help me create or link a spreadsheet for the data to populate into.
Thanks
code.gs
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('form.html');
}
function uploadFiles(form) {
try {
var dropbox = "Operation Overview";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folder.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folders.createFile(blob);
file.setDescription("Uploaded by "+ form.myName);
return "File uploaded successfully ";
} catch (error) {
return error.toString();
}
}
form.html
<form id="myForm">
<input type="text" name="myName" placeholder="Your name.">
<input type="text" name="myDate" placeholder="Date.">
<input type="file" name="myFile">
<input type="submit" value="Upload File"
onclick="this.value='Uploading..';
google.script.run.withSuccessHandler(fileUploaded)
.uploadFiles(this.parentNode);
return false;">
</form>
<div id="output"></div>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
input { display:block; margin: 20px; }
</style>
You need to use the Spreadsheet Service:
Google Documentation - Apps Script Spreadsheet Service
You can use Append Rows:
Append Rows
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// Appends a new row with 2 columns to the bottom of the
// spreadsheet containing the values in the array
sheet.appendRow(["Jackson Jones", "jJones#email.com"]);
The above example uses the getActiveSpreadsheet() method. You won't be using that. You need a reference to the file.
You can open a spreadsheet file by id, or url.
Google Documentation - Open a Spreadsheet by ID
// The code below opens a spreadsheet using its ID and logs the name for it.
// Note that the spreadsheet is NOT physically opened on the client side.
// It is opened on the server only (for modification by the script).
var ss = SpreadsheetApp.openById("abc1234567");
Logger.log(ss.getName());
Notice the Logger.log() statement. To view the log, use the View menu in the Apps Script code editor.
It's critical to understand, that SpreadsheetApp.openById() returns a CLASS. It returns the SPREADSHEET CLASS
Google Documentation - Spreadsheet Class
Once you get the Spreadsheet Class, then you can take the next step and use methods available to the Spreadsheet Class.
var ss = SpreadsheetApp.openById("abc1234567");
Logger.log(ss.getName());
ss.appendRow(["Jackson Jones", "jJones#email.com"]);
In the above example, the data is hard coded, but you need variables instead of the constant values in double quotes.
So you need to get the data out of the form object, and into variables or a direct reference.
ss.appendRow([form.myName, "jJones#email.com"]);
I did check your code, and form.myName did return the name I entered into the name field.
I'm using fine-uploader to take multiple (large) files and pass the filename along with an additional user-input parameter. I do that by creating a text input box (called 'allele_freq') next to each file and I pass the filename and the allele_freq parameter to my cgi script.
What happens next (or what will happen next) is that I analyse the data in the file, using the allele_freq parameter and then some images are returned to the page for the user to look at.
If the user wants to re-analyse the data with a new allele_freq, all I want to do is to pass the filename along with the new allele_freq, i.e. I don't want to have to upload the file again.
I've pasted my working code below (it uploads multiple files along with user input for each file) and then the code that I can't get to work (it produces a 'resubmit' button, but doesn't appear to do anything), along with some comments/musings within the code.
Any information on how I would do this will be gratefully received. I'm very new to both fine-uploader and Javascript (as you can probably tell), so please feel free to criticise (constructively of course!) any of my code.
Many thanks,
Graham
<link href="fineuploader/fineuploader-3.6.4.css" rel="stylesheet">
<script src="fineuploader/jquery-2.0.1.js"></script>
<script src="fineuploader/jquery.fineuploader-3.6.4.js"></script>
<div id="multiFineUploader"></div>
<div id="triggeredUpload" class="btn btn-primary" style="margin-top: 10px;">
<i class="icon-upload icon-white"></i> Upload now
</div>
<script>
$('#multiFineUploader').fineUploader({
request: {
endpoint: 'src/lib/upload.cgi'
},
autoUpload: false,
text: {
uploadButton: '<i class="icon-plus icon-white"></i> Select Files'
}
})
.on('submitted', function(event, id, name) {
var fileItemContainer = $(this).fineUploader('getItemByFileId', id);
$(fileItemContainer)
.append('<input type="text" name="allele_freq">');
})
.on('upload', function(event, id, name) {
var fileItemContainer = $(this).fineUploader('getItemByFileId', id),
enteredAlleleFreq = $(fileItemContainer).find('INPUT[name="allele_freq"]').val();
$(this).fineUploader('setParams', {allele_freq: enteredAlleleFreq}, id);
});
$('#triggeredUpload').click(function() {
$('#multiFineUploader').fineUploader('uploadStoredFiles');
});
</script>
above code works fine
code below doesn't
<div id="resubmitFreqs"></div>
<div id="retry" class="btn btn-success" style="margin-top: 10px;">
<i class="icon-upload icon-white"></i> Resubmit
</div>
<script>
$('#resubmitFreqs').fineUploader({
request: {
//use a different script as shouldn't need to handle all the upload stuff
endpoint: 'src/lib/resubmit.cgi'
}
)}
//get the information from the allele_freq box. Should it still be in scope?? If not, how do I get at it?
.on('upload', function(event, id, name) {
var fileItemContainer = $(this).fineUploader('getItemByFileId', id),
enteredAlleleFreq = $(fileItemContainer).find('INPUT[name="allele_freq"]').val();
$(this).fineUploader('setParams', {allele_freq: enteredAlleleFreq}, id);
});
$('#retry').click(function() {
//I presumably don't want to use 'uploadStoredFiles', but I'm not sure how to post my new parameters into the resubmit.cgi server-side script
$('#resubmitFreqs').fineUploader('uploadStoredFiles');
});
</script>
It seems like you are trying to bend Fine Uploader into something that it is not. Fine Uploader should probably not be involved with this step of your process, as its job is to upload files to your server. It is not meant to be an all-in-one web application. If you want to send additional data to your server at some point in time after the file has been sent, simply send a POST request with that data via XHR.
How can I upload files to google drive?
I want to create a web app using google app script - htmlservice.
I don't know how to point form in html to existing google app script.
I am having hard time to find a right example in google documentation.
I found hundreds of examples using UI but according to https://developers.google.com/apps-script/sunset it will be deprecated soon.
Thank you in advance!
Janusz
<html>
<body>
<form>
<input type="file"/>
<input type="button">
</form>
</body>
</html>
Script
function doGet() {
return HtmlService.createHtmlOutputFromFile('myPage');
}
function fileUploadTest()
{
var fileBlob = e.parameter.upload;
var adoc = DocsList.createFile(fileBlob);
return adoc.getUrl();
}
Have the button run the server side function using google.script.run, passing in the entire form as the only parameter. (Inside the button's onClick, 'this' is the button, so 'this.parentNode' is the form.) Make sure to give the file input a name.
<html>
<body>
<form>
<input type="file" name="theFile">
<input type="hidden" name="anExample">
<input type="button" onclick="google.script.run.serverFunc(this.parentNode)">
</form>
</body>
</html>
On the server, have your form handling function take one parameter - the form itself. The HTML form from the client code will be transformed into an equivalent JavaScript object where all named fields are string properties, except for files which will be blobs.
function doGet() {
return HtmlService.createHtmlOutputFromFile('myPage');
}
function serverFunc(theForm) {
var anExampleText = theForm.anExample; // This is a string
var fileBlob = theForm.theFile; // This is a Blob.
var adoc = DocsList.createFile(fileBlob);
return adoc.getUrl();
}
If you actually want to use that URL you are generating and returning, be sure to add a success handler to the google.script call. You can modify it like this:
// Defined somewhere before the form
function handler(url) {
// Do something with the url.
}
<input type="button" onclick=
"google.script.run.withSuccessHandler(handler).serverFunc(this.parentNode)">
try: return HtmlService.createTemplateFromFile('myPage').evaluate();
More: html service reference
I found an answer for my question.
Submit a Form using Google App Script's HtmlService
The code in the Google App Script link below is:
function doGet(e) {
var template = HtmlService.createTemplateFromFile('Form.html');
template.action = ScriptApp.getService().getUrl();
return template.evaluate();
}
function doPost(e) {
var template = HtmlService.createTemplateFromFile('Thanks.html');
template.name = e.parameter.name;
template.comment = e.parameter.comment;
template.screenshot = e.parameter.screenshot;
return template.evaluate();
}
https://script.google.com/d/1i65oG_ymE1lreHtB6WBGaPHi3oLD_-wPd5Ter1nsN7maFAWgUA9DbE4C/edit
Thanks!