Array element assignment in Google (Apps) Script - javascript

I'm associating a Google (Apps) Script with a Google Spreadsheet.
The entire script works except for the following line:
headers[0] = headers[0] + ":";
Removing this line allows the script to run. Adding it makes it fail.
The array is initialized beforehand as follows.
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
What's wrong with my element assignment, and how do I fix it?
Thanks.

The very simple test function:
function whenOpen() {
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
Logger.log('Array of headers: ' + headers);
Logger.log('First header: ' + headers[0]);
headers[0] = headers[0] + ":";
Logger.log('Modified header: ' + headers[0]);
}
Runs perfectly for me: http://prntscr.com/58a6fx
I don't get any errors, so I suspect the issue is more complex then this one line, as it does not appear to be the culprit. If you try it yourself in a fresh script (Bound to a spreadsheet, with some values in the headers, ofc), it should run with issue.

Related

Trying to email a PDF of a single Google Sheet [duplicate]

For almost a year we have been using the below code to export a Google Sheets sheet (held in theSheetName) to a PDF named as specified in InboundID.
This last week, one at a time various users can no longer produce the PDF. I get a failure at the line containing "var newFile = DriveApp.createFile(blob);" with the error being:
"Conversion from text/html to application/pdf failed."
And sure enough, the UrlFetchApp.fetch is returning HTML instead of a PDF. Again, only for some users. Does anyone have any thoughts as to why my users might be seeing this?
function sendPDFToDrive(theSheetName, InboundID)
{
var theSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var theSpreadsheetId = theSpreadSheet.getId();
var thisSheetId = theSpreadSheet.getSheetByName(theSheetName).getSheetId();
var url_base = theSpreadSheet.getUrl().replace(/edit$/,'');
var theOutFileName = "GASFILE_M_" + (Math.floor(Math.random() * 8997) + 1000) + '.pdf'
//export as pdf
var url_ext = 'export?exportFormat=pdf&format=pdf'
+ (thisSheetId ? ('&gid=' + thisSheetId) : ('&id=' + theSpreadsheetId))
// following parameters are optional...
+ '&size=A4' // paper size
+ '&scale=2' // 1= Normal 100% / 2= Fit to width / 3= Fit to height / 4= Fit to Page
+ '&portrait=true' // orientation, false for landscape
+ '&horizontal_alignment=CENTER' //LEFT/CENTER/RIGHT
+ '&fitw=true' // fit to width, false for actual size
+ '&sheetnames=false&printtitle=false&pagenumbers=false' //hide optional headers and footers
+ '&gridlines=true' // hide gridlines
+ '&printnotes=false' // don't show notes
+ '&fzr=true'; // repeat row headers (frozen rows) on each page
// Setup options
var options =
{
headers:
{
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
}
}
// Build the file
var response = UrlFetchApp.fetch(url_base + url_ext, options);
var blob = response.getBlob().setName(theOutFileName);
var folder = DriveApp.getFolderById("ABC123FooBarID");
var newFile = DriveApp.createFile(blob); //Create a new file from the blob
newFile.setName(InboundID + ".pdf"); //Set the file name of the new file
newFile.makeCopy(folder);
}
I was having this exact problem. After some debugging I saw that my URL was being created incorrectly.
My code was nearly identical to yours. Where I found the culprit was the following line:
var url_base = theSpreadSheet.getUrl().replace(/edit$/,'');
This was not actually clearing out the 'edit' to the end of the line like it had for years. I cannot say why this is, but the proof was in the logs. So, instead I crafted the url by hand:
var url = 'https://docs.google.com/spreadsheets/d/'+SpreadsheetApp.getActiveSpreadsheet().getId()+'/';
This seemed to solve the problem. This is not a perfect futureproof resolution, because if Google changes how the URLs are crafted, this will fail. But it works for now.
I hope this helps. You can send the url your code is creating to logs and check them to see if you have the same issue I did.
To expand on Jesse's accepted answer - the culprit is definitely in this line:
var url_base = theSpreadSheet.getUrl().replace(/edit$/,'');
The reason why the replace(/edit$/,'') call no longer clears out edit like before is because the URL returned by theSpreadSheet.getUrl() used to end with edit, but now returns a URL with additional parameters on the end - ouid=1111111111111111111111&urlBuilderDomain=yourdomain.com.
While rebuilding the URL entirely should also work, you can also patch the script with some small changes to the regular expression. Instead of looking for edit$ (meaning edit as the final characters in the string), you can look for edit + any additional characters like so:
var url_base = theSpreadSheet.getUrl().replace(/edit.*$/,'');
better also avoid using comma for the last property of the header pointing below:
-- 'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(), --

Using Google Apps Script, how can I download each presentation slide as a pdf?

I'm a bit new to this, so I apologize in advance for any newb related annoyances.
What I'm trying to do is create a google presentation with various images, and then download each slide as a separate pdf. I'm trouble with the downloading as a pdf part. The presentation is being constructed correctly. I've tried a couple different things, but haven't found a working solution yet. The simplest one I tried was:
var newFolder=rootFolder.createFolder(sourceSpreadsheet.getName() + ' - Functionals').setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
var deck = SlidesApp.create(NAME); // name determined separately
var presentationID = deck.getId();
...
var blob = DriveApp.getFileById(presentationID).getBlob();
newFolder.createFile(blob);
This did create a pdf, but it looks like it was just one blank page. I'm unsure if maybe it needs to run on each slide individually rather than the presentation as a whole. I couldn't find anything to indicate that to be the case though.
The second thing I tried was based on a similar solution I found for a spreadsheet. I don't really understand how changing the URL downloads it as a pdf, and maybe that's related to the issue with it, which is this is resulting in a 404.
var presentation = SlidesApp.openById(presentationID);
var url = presentation.getUrl();
url = url.replace(/edit$/,'');
var url_ext = 'export?exportFormat=pdf&format=pdf' + '&muteHttpExceptions=true' //export as pdf
var response = UrlFetchApp.fetch(url + url_ext, {
headers: {
'Authorization': 'Bearer ' + token
}
});
I've used the second method to create pdfs of Google Sheets.
The following function could be adapted to create pdfs of your slides. This uses the REST API so that's why you need to construct the URL with parameters according to how you want to format the pdf.
Your formated url will need to look something like this: https://docs.google.com/presentation/d/****presentationId****/export?exportFormat=pdf&format=pdf
You can find other optional parameters for formating the pdf in this function.
function exportPDF(fileId) {
var ss = SpreadsheetApp.openById(fileId);
// Base URL
var url = "https://docs.google.com/spreadsheets/d/SS_ID/export?".replace("SS_ID", ss.getId());
/* Specify PDF export parameters
From: https://code.google.com/p/google-apps-script-issues/issues/detail?id=3579
https://stackoverflow.com/questions/46088042/margins-parameters-for-spreadsheet-export
*/
var url_ext = 'exportFormat=pdf&format=pdf' // export as pdf / csv / xls / xlsx
+ '&size=letter' // paper size legal / letter / A4
+ '&portrait=true' // orientation, false for landscape
+ '&fitw=true&source=labnol' // fit to page width, false for actual size
+ '&top_margin=0.25' //All four margins must be set!
+'&bottom_margin=0.25' //All four margins must be set!
+'&left_margin=0.25' //All four margins must be set!
+'&right_margin=0.25' //All four margins must be set!
+ '&sheetnames=false&printtitle=false' // hide optional headers and footers
+ '&pagenumbers=false&gridlines=false' // hide page numbers and gridlines
+ '&fzr=true' // do not repeat row headers (frozen rows) on each page
+ '&gid='; // the sheet's Id
var token = ScriptApp.getOAuthToken();
var sheet = ss.getSheets()[0]; //get first sheet
// Converts to PDF
var response = UrlFetchApp.fetch(url + url_ext + sheet.getSheetId(), {
headers: {
'Authorization': 'Bearer ' + token
}
});
//convert the response to a blob and store in our array
var blob = response.getBlob().setName(sheet.getName() + '.pdf');
var folderId = '**********your folder id here*******************';
var folder = DriveApp.getFolderById(folderId);
return folder.createFile(blob).getId();
}
Converting all of the slides in a presentation to individual pdfs
function convertingSlideImagesToPDF() {
var fldr=DriveApp.getFolderById("FolderID");
var ss=SlidesApp.openById("PresentationID");
var slds=ss.getSlides();
var n=0;
for(var i=0;i<slds.length;i++) {
var sldImgA=slds[i].getImages();
if(sldImgA) {
for(var j=0;j<sldImgA.length;j++) {
var imgName=sldImgA[j].getTitle();
var base64=Utilities.base64Encode(sldImgA[j].getBlob().getBytes());
var html='<img src="data:image/jpg;base64,'+base64+'">';
var blob=null;
blob=Utilities.newBlob(html, MimeType.HTML).setName('Image' + n++ + ".pdf");
blob=blob.getAs(MimeType.PDF);
var file=fldr.createFile(blob);
}
}
}
}
Helpful Reference

Display thumbnailPhoto from Active Directory using Javascript only - Base64 encoding issue

Here's what I'm trying to do:
From an html page using only Javascript I'm trying to query the Active Directory and retrieve some user's attributes.
Which I succeded to do (thanks to some helpful code found around that I just cleaned up a bit).
I can for example display on my html page the "displayName" of the user I provided the "samAccountName" in my code, which is great.
But I also wanted to display the "thumbnailPhoto" and here I'm getting some issues...
I know that the AD provide the "thumbnailPhoto" as a byte array and that I should be able to display it in a tag as follow:
<img src="data:image/jpeg;base64," />
including base64 encoded byte array at the end of the src attribute.
But I cannot manage to encode it at all.
I tried to use the following library for base64 encoding:
https://github.com/beatgammit/base64-js
But was unsuccesful, it's acting like nothing is returned for that AD attribute, but the photo is really there I can see it over Outlook or Lync.
Also when I directly put that returned value in the console I can see some weird charaters so I guess there's something but not sure how it should be handled.
Tried a typeof to find out what the variable type is but it's returning "undefined".
I'm adding here the code I use:
var ADConnection = new ActiveXObject( "ADODB.connection" );
var ADCommand = new ActiveXObject( "ADODB.Command" );
ADConnection.Open( "Data Source=Active Directory Provider;Provider=ADsDSOObject" );
ADCommand.ActiveConnection = ADConnection;
var ou = "DC=XX,DC=XXXX,DC=XXX";
var where = "objectCategory = 'user' AND objectClass='user' AND samaccountname='XXXXXXXX'";
var orderby = "samaccountname ASC";
var fields = "displayName,thumbnailPhoto";
var queryType = fields.match( /,(memberof|member),/ig ) ? "LDAP" : "GC";
var path = queryType + "://" + ou;
ADCommand.CommandText = "select '" + fields + "' from '" + path + "' WHERE " + where + " ORDER BY " + orderby;
var recordSet = ADCommand.Execute;
fields = fields.split( "," );
var data = [];
while(!recordSet.EOF)
{
var rowResult = { "length" : fields.length };
var i = fields.length;
while(i--)
{
var fieldName = fields[i];
if(fieldName == "directReports" && recordSet.Fields(fieldName).value != null)
{
rowResult[fieldName] = true;
}
else
{
rowResult[fieldName] = recordSet.Fields(fieldName).value;
}
}
data.push(rowResult);
recordSet.MoveNext;
}
recordSet.Close();
console.log(rowResult["displayName"]);
console.log(rowResult["thumbnailPhoto"]);
(I replaced db information by Xs)
(There's only one entry returned that's why I'm using the rowResult in the console instead of data)
And here's what the console returns:
LOG: Lastname, Firstname
LOG: 񏳿က䙊䙉Āā怀怀
(same here Lastname & Firstname returned are the correct value expected)
This is all running on IE9 and unfortunetly have to make this compatible with IE9 :/
Summary:
I need to find a solution in Javascript only
I know it should be returning a byte array and I need to base64 encode it, but all my attempts failed and I'm a bit clueless on the reason why
I'm not sure if the picture is getting returned at all here, the thing in the console seems pretty small... or if I'm nothing doing the encoding correctly
If someone could help me out with this it would be awesome, I'm struggling with this for so long now :/
Thanks!

Google sheets, scripts stop working after making a copy.

I have a spreadsheet that I have built to be used as a template. This spreadsheet has a few scripts in it, the problem I am having is when you make a copy of the spreadsheet, all of my scripts stop working. I have to go into each script and manually authorize them again.
We would be making a copy of the Master spreadsheet for every single job that comes through my department. Roughly 20-30 copies of the master would be made each day, by multiple people.
Is there anyway to avoid this?
Please see sample code and spreadsheet below.
Thanks,
Tyler
https://docs.google.com/a/costco.com/spreadsheets/d/1vcmjVtS2mKwCGfboVFK14yNoksTJ7pq4vDcKIOpG2oU/edit?usp=sharing
function customDocEmail(){
var sheet = SpreadsheetApp.getActiveSheet();
if (sheet.getName() == "Version 1 ") {;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var triggerCell = sheet.getRange("C17").getValue().toString();
var email = sheet.getRange("A17").getValue().toString();
var EMAIL_SENT = new Date() ;
var recipients = "Youremail#gmail.com";
var cellA1 = ss.getSheetByName("Version 1 ").getRange("A1").getValue().toString();
var cellB2 = ss.getSheetByName("Version 1 ").getRange("B2").getValue().toString();
var cellD1 = ss.getSheetByName("Version 1 ").getRange("D1").getValue().toString();
}
var subject = 'New customDoc ' + cellA1+ '-' +cellB2;
var body = ' Hi Stephanie,' + '\n' + '\n' + 'This job ' + cellA1 + '-'+ cellB2+ ', is being created as a CustomDoc.. Please view the specs for this job. ' + '\n' + ss.getUrl() +' '+ '\n' + '\n' +'Thank you,' + '\n' + cellD1 +' ' ;
if (triggerCell =="YES")
{MailApp.sendEmail(recipients, subject, body);
sheet.getRange("C17").setValue("SENT");
}
}
function templateMagix() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Version 1 ");
var trigger = sheet.getRange("B3").getValue().toString();
var formNumber = sheet.getRange("A23").getValue().toString();
var boom = sheet.getRange("C23").getValue().toString();
if (boom =="BOOM")
sheet.getRange("B3").setValue(formNumber);
}
The reason why you have to authorize your scripts time and again is because each copy that you create is treated as a New Document and so are the scripts attached to that document. And for any new document to be able to run scripts, it is necessary for the user to provide that document permission to run scripts. Being able to make copies and run scripts without having authorized it manually will be somewhat similar to providing a script unauthorized access to run. Which, if it were possible, could be seen as a serious security thread. Therefore, unfortunately so, it is not possible to run scripts without providing them permission to run.
Although, depending on how many scripts you have, your use case and what function(s) they are performing etc., I would suggest that if it is possible combine these functions into one script and call them where necessary. This way, you will have to only provide manual permission to the script once instead of having to do it n number of times (assuming you have n scripts) for each script to be granted permission to run.
I was able to figure out a work around for this and it works flawlessly for my application.
I put all onEdit scripts in the same "Project", then I made a button and assigned my timeStamp Function to it. This prompted the authorization for all of my scripts that required the Auth.
Next I ran into all of the "installed onEdits" not staying installed upon making a copy of the spreadsheet, so the script's still were not functional. A little more digging and research brought me to writing a simple but effective script, that I assigned to my newly created button. Which in turn install's all of my onEdit triggers as well as prompting the authorization and all script's now work as they were intended.
I hope someone dealing with the same issues can find some use in this.
function authoRize(e) {
Browser.msgBox("Great! Let's be friends!");
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("customDocEmail")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("templateMagix")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("GetData")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("GetPJData")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("hideSeek")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("hideSeekOP")
.forSpreadsheet(sheet)
.onEdit()
.create();
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("hideSeekPJ")
.forSpreadsheet(sheet)
.onEdit()
.create();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("HOME");
var newDate = new Date() ;
sheet.getRange("A5").setValue(newDate);
goToSheet('Version 1 ');
}

jQuery - parsing JSON data - Having trouble with variable name

My first delve into working with JSON data. I have a bit of experience using jQuery though.
I'm posting to this URL (tumblr api): jyoseph.com/api/read/json
What I'm trying to do is output the json that gets returned. What I have so far:
$(document).ready(function(){
$.getJSON("http://jyoseph.com/api/read/json?callback=?",
function(data) {
//console.log(data);
console.log(data.posts);
$.each(data.posts, function(i,posts){
var id = this.id;
var type = this.type;
var date = this.date;
var url = this.url;
var photo500 = this.photo-url-500;
$('ul').append('<li> ' +id+ ' - ' +type+ ' - ' +date+ ' - ' +url+ ' - ' +photo500+ ' - ' + ' </li>');
});
});
});
See my jsbin post for the entire script: http://jsbin.com/utaju/edit
Some of the keys from tumblr have "-" hyphens in them, and that seem to be causing a problem. As you can see "photo-url-500" or another "photo-caption" is causing the script to break, it's outputting NaN.
Is there a problem with having hyphens in the key names? Or am I going about this all wrong?
If there are dashes in the names you'll need to access them differently. Change var photo500 = this.photo-url-500; to read var photo500 = this["photo-url-500"];.
Please note it is best not to append inside each iteration. Better to append to a string or push to an array then append once after the iterator has finished. Appending to the dom is expensive.
Use the bracket notation to access the members:
var photo500 = this['photo-url-500'];

Categories

Resources