Contents persistence in google script "blob" - javascript

I'm putting togheter some lines of code in Google scripts. The important piece is (consider true the fact that I have a good mySpreadsheet with contents, also source and folder are set):
[...]
var mySpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(source.getId()).makeCopy("test", folder))
[...]
var sheet = mySpreadsheet.getSheets()[0];
sheet.clear();
//email, obj, msg are string set before
sendPdf(mySpreadsheet, pdfName, email, obj, msg);
}
function sendPdf(sheet, pdfName, email, object, message) {
//save to pdf
var pdfFile = sheet.getBlob().getAs('application/pdf').setName(pdfName);
// Send the freshly constructed email
MailApp.sendEmail(email, object message, {attachments:[pdfFile]});
}
The script works, it means that the script creates the pdf and attach it to the email.
I expected, after cleaning the (only) sheet of the file, to receive an empty pdf.
mySpreadsheet is empty, but the pdf attached contains all the contents copied from source. Where these data came from? Where are they "stored" when the sheet is being cleared? Thank you in advance.

In your situation, you want to receive the Spreadsheet using sheet.clear() for the 1st sheet as an attachment file of an email.
If my understanding is correct, how about this modification?
Modification point:
Although I'm not sure about your whole script, after sheet.clear() is run, it seems that the Spreadsheet is not saved. I thought that this is the reason of your issue.
By saving the Spreadsheet after using sheet.clear(), the blob can be retrieved from the updated Spreadsheet.
Modified script:
Please modify as follows and test it again.
From:
sheet.clear();
To:
sheet.clear();
SpreadsheetApp.flush(); // Added
Reference:
flush()
If I misunderstood your question and this was not the result you want, I apologize.

Related

XmlService using Apps Script is finding an error with the '&' symbol

I have the below function trying to convert a webpage to xml, so I can start extracting out some data from tables etc.
function getWebpageContent() {
var url = "https://training.gov.au/Training/Details/BSBCRT501";
var xml = UrlFetchApp.fetch(url).getContentText();
var document = XmlService.parse(xml);
Logger.log(document);
}
I'm recieving this error:
Exception: Error on line 170: The entity name must immediately follow the '&' in the entity reference.
getWebpageContent # Code.gs:6
When I search that webpage for the "&" symbol, (assuming that XmlService is confusing the 'and' symbol for some sort of html code and throwing an error) I can only find one hidden one. And am not sure how to circumvent it.
Any way to dodge that error and get the webpage info as Xml in Apps Script?
From your following replying,
The output I want from this page (https://training.gov.au/Training/Details/BSBCRT501) is each in the 'Elements and Performance Criteria' table. I want to save it as an array to then reformat into my spreadsheet. I might just use IMPORTXML in a spreadsheet formula instead.
In this case, how about the following formula?
Sample formula:
=IMPORTXML("https://training.gov.au/Training/Details/BSBCRT501","//table[2]//tr")
Result:
Reference:
IMPORTXML
Added:
From your following replying,
That's a great answer thanks and the method I think I'll use. It doesn't link break at each point (2.1, 2.2 etc) unfortunately but it's still good. I don't think I can accept it as the answer though as it doesn't solve the specific Apps Script problem, but thanks a lot for this.
I added a sample script for using Google Apps Script. Could you please confirm it?
Sample script:
Before you use this script, please enable Sheets API at Advanced Google services. When you run this script, the table is put to the active sheet.
function myFunction() {
const url = "https://training.gov.au/Training/Details/BSBCRT501";
const res = UrlFetchApp.fetch(url, {muteHttpExceptions: true});
if (res.getResponseCode() != 200) throw new Error(res.getContentText());
const table = [...res.getContentText().matchAll(/<TABLE[\s\S\w]+?<\/TABLE>/g)];
if (table && table[1][0]) {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheet = spreadsheet.getActiveSheet();
const resource = {requests: [{pasteData: {html: true, data: table[1][0], coordinate: {sheetId: sheet.getSheetId()}}}]};
Sheets.Spreadsheets.batchUpdate(resource, spreadsheet.getId());
}
}
References:
Class UrlFetchApp
Method: spreadsheets.batchUpdate
This guy here explains the underlying cause, and also gives the solution:
The entity name must immediately follow the '&' in the entity reference

Self Populating Cell in Google Sheets after a ZAPIER ZAP is run

I live oversees (military) and get emails when I have a package that arrives at my Post Office and is ready for pickup. I have a Zapier PARSER email account and associated ZAP setup that pulls the data from the email and updates a Google Sheets document with its shelf location, tracking number, and a few other important things from the email so the clerks can get my stuff quickly. It works great. In that same workbook, I have another sheet that I update using an app on my phone to scan tracking barcodes to when I physically pick up the package. On the first sheet I have a basic VLOOKUP function that looks for the tracking number in the scanned list to mark it off as PICKED UP (I get a lot of packages )
I have to manually go in and drag the function down when the ZAP creates a new row. it's not difficult, but i want to have it all automatic. that's what computers are for! I created a google script from the SCRIPT editor on my sheet to do it (I think)
function onEdit(e)
{
var row = e.range.getRow(); //Determine the Row # Just added
var sheet = e.range.getSheet(); //Determine the Sheet, probably not needed
var row_string = row.toString(); //Convert the Row Number to a string.
var start_string = "=VLOOKUP(B"; //this is a fixed part of the function I need in the E column of this row.
var end_string = ", 'Scanned Packages Fixed'!A:B, 2, FALSE)"; //This is the fixed part of the function at the end of the row.
var set_lookup_cell = start_string.concat(row_string, end_string); //Smash the strings together to build a full function
sheet.getRange(row,5).setValue(set_lookup_cell); //Put the full function of the string into the proper cell (E)
}
I am not 100% up on how this would get called automatically or if I am missing a way to link it to the sheet itself. When I hit "run" on the code I got this:
TypeError: Cannot read property 'range' of undefined (line 3, file "Code")
I went into my sheet and just added something in the first column of a new row to see what happened, nothing did.
Any help would be super appreciated!
EDIT: Basically, I need Column E of the row to say this
=VLOOKUP(B63, 'Scanned Packages Fixed'!A:B, 2, FALSE) [Where 63 is the row#]
Turns out, the code above does work. I am just not patient and didn't let the sheet update and script run automatically after an update to a row.
Turns out, this isn't triggered when the zap populates the sheet... Only if I do.

Resolve a 301 redirect and store the url for future use javascript

So I have a script that organises an un-formatted csv file and presents an output.
One of the pieces of data I receive in this data that we must return is a link to an image stored on Google Drive. The problem with this is Google Drive doesn't like to present you with a direct link to a file.
You can get the ID of a file (e.g. abc123DEFz) and view it online at https://drive.google.com/open?id=abc123DEFz. We need a direct link for another service to be able to process the file, not a redirect or some fancy website.
After poking around I discovered that https://drive.google.com/uc?export=view&id=abc123DEFz would redirect you directly to the file, and was what I somehow had to obtain inside the script.
The url it gave me though didn't really seem to have any relation to the ID and I couldn't just go ahead and swap the ID, for each file I would have to resolve this uc?export link into this link that would send me directly to the file. (Where the redirect sent me: http://doc-0c-2s-docs.googleusercontent.com/docs/securesc/32-char-long-alphanumeric-thing/another-32-char-long-alphanumeric-thing/1234567891234/12345678901234567890/12345678901234567890/abc123DEFz?e=view&authuser=0&nonce=abcdefgh12345&user=12345678901234567890&hash=32-char-long-alphanumeric-hash)
No authentication is required to access the file, it is public.
My script works like this:
const csv = require('csv-parser'),
fs = require('fs'),
request = require('request');
let final = [],
spuSet = [];
fs.createReadStream('data.csv')
.pipe(csv())
.on('data', (row) => {
>> data processing stuff, very boring so you don't care
console.log(`
I'm now going to save this information and tell you about the row I'm processing
so you can see why something went wrong`);
final.push(`[{"yes":"there is something here"},{"anditinvolves":${thatDataIJustGot}]`);
spuSet.push(`[{"morethings":123}]`);
})
.on('end', () => {
console.log('CSV file successfully processed');
console.log(`
COMPLETED! Check the output below and verify:
[${String(final).replace(/\r?\n|\r/g, " ")}]
COMPLETED! Check the output below and verify:
[${String(spuSet).replace(/\r?\n|\r/g, " ")}]`);
>> some more boring stuff where I upload the data somewhere and create a file containing said data
});
I tried using requests but it's a function with a callback so using the data outside of the function would be difficult, and wrapping everything inside the function would remove my ability to push to the array.
The url I get from the redirect would be included in the data I am pushing to the array for me to use later on.
I'm pretty bad at explaining crap, if you have any questions please ask.
Thanks in advance for any help you can give.
Try using the webContentLink parameter of the Get API call:
var webLink = drive.files.get({
fileId: 'fileid',
fields: 'webContentLink'
});
This will return the object:
{
"webContentLink": "https://drive.google.com/a/google.com/uc?id=fileId&export=download"
}
Then you can use split() to remove &export=download from the link, as we don't want to download it.
As fileId, you can get the Ids of your files by using the List API Call, and then you can loop through the list array calling the files.get from the first step.
My apologies if I misunderstood your issue.
In case you need help with the authentication to the Google Services, you can take a look at the Quickstart

HTML Function displaying as plain text

I have been working on this for quite some time, and have basically been teaching myself HTML, so I apologize if the code is sloppy or if this is a simple fix. Here is what I am attempting to do, and the problem I am running into:
Take Google Form responses, generate an email based on those responses and dynamically email a certain person in my organization based on the location response(this part is done and working, just adding for context). Then create a survey response that sends info back to the original responder, sent from the administrator that the form was sent to. This is the js that I have running, that is working when it is ran in the google project:
function getid() {
var spreadsheet = SpreadsheetApp.openByUrl('https://docs.google.com/a/raytownschools.org/spreadsheets/d/1YWHu_yKn5bqq63x1A4e4-vBUtZANj-xjeF07IBpHP64/edit?usp=sharing');
SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
var sheet = spreadsheet.getActiveSheet();
var lastRow = sheet.getLastRow();
}
When I attempt to run that in my HTML code, and insert it into the element, it is simply inserting that code as raw text. HTML isn't running the function, or returning the data that it should be (and does return when ran outside the HTML code as a js app).
I can post the full HTML code if that would be helpful. Hopefully someone on here can help me out.
What you have there is a Javascript function. There aren't functions in HTML, HTML is a markup language.
You must add that function inside Javascript tags like this:
<script type="text/javascript">
function getid() {
var spreadsheet = SpreadsheetApp.openByUrl('https://docs.google.com/a/raytownschools.org/spreadsheets/d/1YWHu_yKn5bqq63x1A4e4-vBUtZANj-xjeF07IBpHP64/edit?usp=sharing');
SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
var sheet = spreadsheet.getActiveSheet();
var lastRow = sheet.getLastRow();
}
alert( getid() );
</script>
Take a look at here, on how to use javascript.
Edit
Seems like that code you're trying to execute is for Google Apps Script. I think you must execute it inside the Google script editor, because they don't make this API available for regular websites. Here is a running example with your code.

Accessing headers of a google spreadsheet using HTTP GET and Google App Script

I'm trying to return the header row of a Google spreadsheet using doGet() in a Google App Script that's running as a WebApp. I'm using a HTML form to send the GET request to the WebApp and it's all working except I don't know how to return the headers to my javascript. I'll post my code:
HTML:
<form id="getForm" method="get" action="My URL for WebApp">
<label for="sheetGetID">SheetID</label>
<input type="text" name="sheetGetID" id="sheetGetID" value="">
<button class="ui-btn" onclick='submitGET()'>Submit</button>
</form>
Javascript:
function submitGET() {
var headers = $("getForm").submit();
alert(headers);
}
Google App Script:
function doGet(e) {
//Trying To: Get headers from sheetID and then return to app, then have correct labels for the inputs, then use POST to post.
var ss = SpreadsheetApp.openById(ScriptProperties.getProperty('active'));
var sheet = ss.getSheetByName(e.parameter["sheetGetID"]);
//Return the first 3 cells, A1:C1,
var headers = sheet.getRange(1,1,1,sheet.getLastColumn()).getValues()[0];
return ContentService.createTextOutput(JSON.stringify(headers))
.setMimeType(ContentService.MimeType.JSON);
}
I'm getting a JSON object returned but it's just a text output. My question is how would/could I get the JSON returned and stored as the headers variable?
The return of doGet method must be an HTML.
Build another html page and use the call HtmlService.createTemplateFromFile('newPag.html').evaluate()
Inside your page use the tags and put your server side code manipulating the json object. This way you will create a good look and feel and a good maintanable code.
I got this to work a while ago, I forgot to post the answer just in case anyone else needed it.
You need to output it as a JSON object like the API demo. You also need to append "?prefix=?" to the url when you're doing a $.getJSON() call. The prefix part is to tell the JQuery that it is a JSON object you're receiving.
If anyone has troubles with this just comment and this and I'll post all the code I used.
So on your client end, I'm using JQuery Mobile, I'm not sure how to do it without it, you would do something like:
sheetID = $("#sheetGetID").val();
$.getJSON("https://script.google.com/macros/s/YOUR_KEY_GOES_HERE/exec?prefix=?",
{ sheetGetID: sheetID},
function(results) {
var fields = results.split(",");
//Do something with fields
}
);
}
Where #sheetGetID is the textbox where the user can enter the sheet id for headers.
Note the ?prefix=? appended to the URL, that part is for JQuery to know it's receiving JSON. That part is necessary. The URL is your deployed WebApp.
On the Google App Script side, ie Server side, you'd have something like:
function doGet(request) {
var ss = SpreadsheetApp.openById(ScriptProperties.getProperty('active'));
var sheet = ss.getSheetByName(request.parameter["sheetGetID"]);
//Return the first 3 cells, A1:C1,
var headers = sheet.getRange(1,1,1,sheet.getLastColumn()).getValues()[0];
var result = headers.join();
var content = request.parameters.prefix + '(' +JSON.stringify(result) + ')';
return ContentService.createTextOutput(content)
.setMimeType(ContentService.MimeType.JSON);
}
If you have any questions on how the spreadsheet part works theres plenty of documentation on Google's API's. doGet() is called when you use the $.getJSON(), the return from the G.A.S. needs to be JSON. Most of this is covered in the documentation Google has, some of it I found watching Google Developers Live on youtube. If you are trying to do more stuff I highly recommend checking those sources out.
If you have any more questions about what's being called or parameters you can find it easily enough on Google.

Categories