I have created a script in google scripts, to take a spreadsheet and fill out multiple google docs successfully. I am trying to apply this logic to filling out an HTML form, basically, we need user-generated info (in our google sheet) to fill out an HTML form on a web page.
How would I get the following function to not only open but write in the data?
This is where I am at (just using an example webpage):
function testNew(){
var js = " \
<script> \
window.open('https://colorlib.com/etc/cf/ContactFrom_v1/index.html', '_blank', 'width=800, height=600'); \
google.script.host.close(); \
</script> \
";
var html = HtmlService.createHtmlOutput(js)
.setHeight(10)
.setWidth(100);
SpreadsheetApp.getUi().showModalDialog(html, 'Now loading.'); // If you use this on Spreadsheet
// DocumentApp.getUi().showModalDialog(html, 'Now loading.'); // If you use this on Document
// SlidesApp.getUi().showModalDialog(html, 'Now loading.'); // If you use this on Slides
}
This is an example of what I did with the google docs, trying to replicate in forms:
function myFunction() {
var data = Sheets.Spreadsheets.Values.get('google sheet ID HERE', 'A2:R300');
// google doc template id, already got deal memo
var templateId = 'google doc ID HERE';
// loop through the values "i" is looping the rows, "#" is the column example: 0=a,1=b
for (var i = 0; i < data.values.length; i++) {
var date = data.values[i][0];
var email = data.values[i][1];
// grab the google doc template, create a copy, and generate the new id
var documentId = DriveApp.getFileById(templateId).makeCopy().getId();
// change the name of the new file
DriveApp.getFileById(documentId).setName(companyName+ '-' + projectName+ '-' + 'Insurance Report');
// get the document body as a variable
var body = DocumentApp.openById(documentId).getBody();
// replace values with google sheet data
body.replaceText('##Date##', date);
body.replaceText('##Email##', email);
I have many functions that I have written that interact with a lot of third party forms and websites. Don't let it fool you that all that a form is, is a human-readable way to "POST" to a url. The easier way to do this is to use the UrlFetchApp.fetch(url, options) function in Google Apps script.
I use Chrome but other browsers have this functionality as well:
open Chrome, navigate to the form and then press F12 to open up the developers window.
Click on 'Network'
fill out the form manually and then review the traffic in the 'Network' window and find the POST that your browser sent to the site,
With that highlighted, you will see a couple other tabs for 'Headers','Preview','Response'
In the 'Headers' tab, scroll to the bottom and it will show you what the request looked like. Screen shot this and send these variables through the UrlFetchApp.fetch() to the website as the 'payload' and formatted like the function below.
Look at the 'Request URL' at the top of that same 'Headers' tab and you will use that as the URL below:
function senddatatoform() {
var url = 'http://theurlthattheformpoststohere.com'; // this is the 'request url' as shown in your browser (not always the url of the form).
var payload = {
datapoint1: datapoint1value,
datapoint2: datapoint2value,
... //continue with all required post data
}
var options = {
method: "POST",
payload: payload
}
var response = UrlFetchApp.fetch(url,options);
/*this is where what you need to do next might vary -- if you're looking for a 'success' page, you might write some code here to verify that the http response is correct based on your needs.
*/
}
Related
I'm trying to send a google slide as an attachment/image in my automated email using google appscripts but i can only send images. I change the slide info everyday so I need it to display the new info hence i dont want to keep changing the image everyday.
// This code fetches the Google and YouTube logos, inlines them in an email
// and sends the email
function inlineImage() {
var googleLogoUrl = "https://i.imgur.com/CWmA6Jv.png";
var youtubeLogoUrl =
"https://i.imgur.com/CWmA6Jv.png";
var googleLogoBlob = UrlFetchApp
.fetch(googleLogoUrl)
.getBlob()
.setName("Scratches Alert");
var youtubeLogoBlob = UrlFetchApp
.fetch(youtubeLogoUrl)
.getBlob()
.setName("Scratches Dashboard");
MailApp.sendEmail({
to: "test#testmail.com",
subject: "Scratches Awareness Program",
htmlBody: "<p>This is to inform about the progress of Scratch Awareness
Programme.<p> Engineers, supervisors & shift leaders are expected to
display and brief thier team on the latest update based on visual comm.
Everyone's involvement is highly appreciated. Please click on the given
link to access Scratches Alert and Dashboard:
https://www.youtube.com/watch?v=dQw4w9WgXcQ</p></p><p><img
src='cid:googleLogo' width='500' height='333'><img src='cid:youtubeLogo'
width='500' height='333'></p>",
inlineImages:
{
googleLogo: googleLogoBlob,
youtubeLogo: youtubeLogoBlob
}
});
}
This code send a text followed by 2 images side by side. I need it to send a text followed by 2 google slide side by side that will automatically update everytime i change anything on the google slide.
Getting Images of Slide Presentations
The first function will store all of your slides as images in a local folder of your choice. It also copies Filename, FileId, height, width, and URL to the active page for later reference. You may wish to modify it in order to just select one image. You will also need to enable to Advanced Slides API in order to use this function because it is at the actual element that is capable of getting access to an image of a slide.
function getImagesOfSlides() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
sh.clearContents();
sh.appendRow(['FileName','FileId','Height','Width','URL']);
var presentationId="Presentation Id";
var fldr=DriveApp.getFolderById("File Folder Id");
var sp=SlidesApp.openById(presentationId);
var slds=sp.getSlides();
var n=1;
for(var i=0;i<slds.length;i++) {
var pageObjectId=slds[i].getPageElements()[0].getParentPage().getObjectId();
if(pageObjectId) {
var respObj=Slides.Presentations.Pages.getThumbnail(presentationId, pageObjectId, {"thumbnailProperties.mimeType":"PNG","thumbnailProperties.thumbnailSize":"MEDIUM"});
var imgBlob=UrlFetchApp.fetch(respObj.contentUrl).getBlob();
var file=fldr.createFile(imgBlob).setName('Slide'+ n++ + '.png');
sh.appendRow([file.getName(),file.getId(),respObj.height,respObj.width,respObj.contentUrl]);
}
}
}
The next function is just a simple example of sending an image file as an attachment to an email.
function sendSlide() {
var fileId="File Id";
var file=DriveApp.getFileById(fileId);
GmailApp.sendEmail('recipient email', 'Sending An Image', 'This is a test file', {attachments:[file]});
}
API Reference This reference is very helpful in figuring out the syntax for API thumbnail options.
Thumbnail Size Options
The rest is just standard DriveApp code.
This is what the Spreadsheet Info looks like:
The context
There is a button on the homepage of each document set in a document library on a SharePoint Online environment. When the button is clicked, an Outlook window opens with the title and body set and all the files in the document set should be added as the attachments.
The code
Here's the code I have so far:
var olApp = new ActiveXObject("Outlook.Application");
var olNs = olApp.GetNameSpace("MAPI");
var olItem = olApp.CreateItem(0);
var signature = olItem.HTMLBody;
signature.Importance = 2;
olItem.To = "";
olItem.Cc = "";
olItem.Bcc = "";
olItem.Subject = "Pre filled title";
olItem.HTMLBody =
"<span style='font-size:11pt;'>" +
"<p>Pre filled body</p>" +
"</span>";
olItem.HTMLBody += signature;
olItem.Display();
olItem.GetInspector.WindowState = 2;
var docUrl = "https://path_to_site/Dossiers/13245_kort titel/New Microsoft Word Document.docx";
olItem.Attachments.Add(docUrl);
The Problem
When I run this code, an Outlook window opens with everything set correctly. But on the line where the attachment is added I get following very vague error message:
SCRIPT8: The operation failed.
I thought it could be the spaces in the url so I replaced them:
docUrl = docUrl.replace(/ /g, "%20");
Also didn't work (same error) and providing all parameters like this also didn't work:
olItem.Attachments.Add(docUrl, 1, 1, "NewDocument");
Passing a path to a local file (e.g. C:/folder/file.txt) or a publicly available url to an image does work. So my guess is it has something to do with permissions or security. Does anybody know how to solve this?
PS: I know using an ActiveX control is not the ideal way of working (browser limitations, security considerations, ...) but the situation is what it is and not in my power to change.
You cannot pass a url to MailItem.Attachments.Add in OOM (it does work in Redemption - I am its author - for RDOMail.Attachments.Add). Outlook Object Model only allows a fully qualified path to a local file or a pointer to another item (such as MailItem).
When you enter an importrange function manually into a spreadsheet you receive a pop up and must 'allow access'.
However, I'm trying to find a way to do this via a script because I'm creating many spreadsheets, each with a query-importrange function (I 'own' the spreadsheet which has data to import). There's too many for me to manually 'allow access' via the pop up and update the function to include the query function.
Hence, I'm looking for a function call in apps script that can perform the same action that the pop up did. Code segment example below.
Does anyone know of a function that can 'allow access'?
Stefan
// create new spreadsheet file
...
var ss = createSpreadsheet(fileName);
var spreadsheet = SpreadsheetApp.open(ss);
var sheet = spreadsheet.getSheetByName("Sheet1");
// Add student as Viewer
spreadsheet.addViewer(studentEmail);
// Add ImportRange function
var sheet = spreadsheet.getSheets()[0];
var cell = sheet.getRange("A1");
var filter = "select * where Col3='" + studentEmail + "'";
var qry = '=QUERY(importRange("' + fileKey + '","14-15S2!A1:AE");"' + filter + '";1)';
cell.setValue(qry);
// I need a function to 'allow access' here, so the function can be allowed access. Otherwise, it throws an error.
...
#Franzi suggested using undocumented approach which works and does not require making a donor/source spreadsheet public. Here's how you can do it from Google App Script:
function addImportrangePermission() {
// id of the spreadsheet to add permission to import
const ssId = SpreadsheetApp.getActiveSpreadsheet().getId();
// donor or source spreadsheet id, you should get it somewhere
const donorId = '1GrELZHlEKu_QbBVqv...';
// adding permission by fetching this url
const url = `https://docs.google.com/spreadsheets/d/${ssId}/externaldata/addimportrangepermissions?donorDocId=${donorId}`;
const token = ScriptApp.getOAuthToken();
const params = {
method: 'post',
headers: {
Authorization: 'Bearer ' + token,
},
muteHttpExceptions: true
};
UrlFetchApp.fetch(url, params);
}
Usually there is no need, but in some rare cases you might want to add the required oauthScopes in appscript.json manifest:
...,
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/script.external_request"
],
...
I had a problem similar to this and found the answer was to alter the permissions of the spreadhseet file from which you are importing data (the "filekey" in your example").
This is the google app script that made "Allow Access" go away for me:
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW)
I'm doing it automatically using the gspread python library by calling the addimportrangepermissions endpoint.
sheet.client.request(
'post',
f'https://docs.google.com/spreadsheets/d/{sheet.spreadsheet.id}/externaldata/addimportrangepermissions',
params={'donorDocId': external_sheet.spreadsheet.id}
)
I know it's not via the apps script, but it could provide you some hints on how to do it there.
Note: I didn't find any doc about this, so I though this could help anyone trying to do the same in any platform (app script, python, etc.).
This code is based on the answer by #kishkin:
/**
* #param {string} fileId - id of the spreadsheet to add permission to import
* #param {string} donorId - donor or source spreadsheet id, you should get it somewhere
*/
function addImportrangePermission_(fileId, donorId) {
// adding permission by fetching this url
var url = 'https://docs.google.com/spreadsheets/d/' +
fileId +
'/externaldata/addimportrangepermissions?donorDocId=' +
donorId;
var token = ScriptApp.getOAuthToken();
var params = {
method: 'post',
headers: {
Authorization: 'Bearer ' + token,
},
muteHttpExceptions: true
};
UrlFetchApp.fetch(url, params);
}
It is compatible with the ES5 engine and easily used as a function outside.
All I did was share the 'source' sheets - the sheets from which ImportRange grabs its data - with the people in my organsation who are using the gsheet template. I edited the template by clicking the authorise access button and all sheets that I have made from the template since have worked.
The ImportRange function works without me having to re-authorise access within each new sheet created from the template. I hope it works for others in my organisation.
I am creating Firefox addon using the Add-on SDK. I want to get data from remote url and inject it in current html. As of now i m able to fetch data using request module of Firefox addon sdk but m not able to inject it in current page.
for example : i am fetching response from website "abc.com".after fetching response i will augment current page with response
// main.js
var widgets = require("sdk/widget");
var tabs = require("sdk/tabs");
var Request = require("sdk/request").Request;
//create addon widget
var widget = widgets.Widget({
id: "div-show",
label: "Show divs",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function() {
//initializing request module to fetch content
quijote.get();
}
});
//fetch content of requested page
var quijote = Request({
url: "http://localhost/abc/",
overrideMimeType: "text/plain; charset=latin1",
onComplete: function (response) {
//check if content is fetched successfully
addContent(response);
}
});
//try and modify current page
function addContent(response){
//initialize page modification module
var pageMod = require("sdk/page-mod");
tabs.activeTab.attach({
contentScript: 'document.body.innerHTML = ' + ' "<h1>'+response.text+'</h1>";'
});
}
Is their any way in which i can augment my current page???
Your code will bitterly fail e.g. when response.text includes a double quote.
Then your code would be (assume it is world):
document.body.innerHTML = "<h1>world</h1>";
This is obviously invalid code.
Your code basically constructs a dynamic script from unsanitized data, which is a bad idea because (other than the escaping problem above)
you'll be running an unsanitized content script if that code is even valid and
if that would succeed, the page might run unsanitized code as well.
This is the web equivalent to SQL injection attacks....
First, lets tackle 1.) with messaging (more):
var worker = tabs.activeTab.attach({
contentScript: 'self.port.on("setdom", function(data) { ' +
+ 'document.body.innerHTML = data; /* still a security issue! */'
+ '});'
});
worker.port.emit("setdom", response.text);
This guarantees that the content script will be valid (can even run) and does not run arbitrary code.
However 2.) is still a problem. Read DOM Building and HTML insertion.
I have a pdf document embedded inside a webpage in ASP.net and want to get a specific field inside the pdf document using Javascript...plain Javascript...
JavaScript in a PDF can call JS in a web page and visa versa, if BOTH are set up for it. You can see Acrobat's documentation here.
Check out the HostContainer specification, starting on page 486. In the PDF you'd need script something like:
var document = this; // hurray for closures.
this.hostContainer.messageHandler = { onDisclose: function() {return true;},
onMessage: function(msgArrayIgnored) {
// build a JSON string of field/value pairs
var outgoingMessage = "{ ";
for (var i = 0; i < this.numFields; ++i) {
var fldName = document.getNthFieldName(i);
var fld = document.getField(fld);
var val = fld.value;
// you'll probably need to escape 'val' to be legal JSON
outgoingMessage += fldName + ": \"" + val + "\";
// stick in a comma unless this is the last field
if (i != this.numFields-1) {
outgoingMessage += ", ";
}
}
outgoingMessage += "};";
this.hostContainer.postMessage( [outgoingMessage] );
};
In the HTML, you need to set up something similar. Lets assume your pdf is embedded in an object tag, and that element's id is "pdfElem". Your HTML script might look something like:
var pdf = document.getElementById("pdfElem");
pdf.messageHandler = function(message) {
var fldValPairs = eval(message);
doStuffWithFieldInfo(fldValPairs);
};
Later, any time you want to inspect the PDF's field info you post a message, and the PDF will call back to pdf.messageHandler with its JSON string wrapped in an array:
pdf.postMessage(["this string is ignored"]);
There's probably a bug or two lurking in there somewhere, but this will put you on the right track.
Webpage JavaScript will not be able to interact with the PDF form fields. You can however make a PDF form post to a web page form processor and then obtain the values in the form fields.