So I am trying to send message to LINE Notify from Google Spreadsheets via google form responses, I already testing the API with Postman and it works, I got the Notification, however it doesn't works on the Apps Script Code. here's the error log:
function autoFillPendataanKontak(e) {
var nama = e.values[1];
var nim = e.values[2];
var bidang = e.values[3];
var file = DriveApp.getFileById('------');
var doc = DocumentApp.openById(file.getId());
var body = doc.getBody();
function sendLineNotify(messageNama, messageBidang) {
var token = ["------"];
var options = {
"method": "post",
"payload": messageNama + " telah mendaftar di Bidang " + messageBidang,
"headers": {
"Authorization": "Bearer " + token
}
};
UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}
function appendTable(variabel1, variabel2){
var rangePSDI = null;
var searchElement = body.findElement(DocumentApp.ElementType.TABLE, rangePSDI);
element = searchElement.getElement();
table = element.asTable();
if (bidang == 'PSDI') {
body.replaceText('{{a}}', variabel1);
body.replaceText('{{b}}', variabel2);
var tr = table.appendTableRow();
var ukur = table.getNumRows();
ukur -= 3;
tr.appendTableCell(ukur+1);
tr.appendTableCell("{{a}}");
tr.appendTableCell("{{b}}");
} else if (bidang == 'PSDM') {
body.replaceText('{{c}}', variabel1);
body.replaceText('{{d}}', variabel2);
var tr = table.appendTableRow();
var ukur = table.getNumRows();
ukur -= 3;
tr.appendTableCell(ukur + 1);
tr.appendTableCell("{{c}}");
tr.appendTableCell("{{d}}");
}
}
appendTable(nama, nim);
sendLineNotify(nama, bidang);
doc.saveAndClose();
}
Solved the problem, I just forgot the "message=" on payload
"payload": "message=" + messageNama + " telah mendaftar di Bidang " + messageBidang,
I've been at this all day trying to figure out how to do an XMLHTTP request after authorization but just can't for the life of me figure it out.
So far I've got the code below which authorizes the user.
var OAUTHURL = 'https://accounts.google.com/o/oauth2/auth?';
var VALIDURL = 'https://www.googleapis.com/oauth2/v1/tokeninfo?
access_token=';
var SCOPE = 'https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/userinfo.email';
var CLIENTID = 'NOT SHOWING FOR SECURITY REASONS';
var REDIRECT = 'NOT SHOWING FOR SECURITY REASONS'
var LOGOUT = 'http://accounts.google.com/Logout';
var TYPE = 'token';
var _url = OAUTHURL + 'scope=' + SCOPE + '&client_id=' + CLIENTID + '&redirect_uri=' + REDIRECT + '&response_type=' + TYPE;
var acToken;
var tokenType;
var expiresIn;
var user;
var loggedIn = false;
function login() {
var win = window.open(_url, "windowname1", 'width=800, height=600');
var pollTimer = window.setInterval(function() {
try {
console.log(win.document.URL);
if (win.document.URL.indexOf(REDIRECT) != -1) {
window.clearInterval(pollTimer);
var url = win.document.URL;
acToken = gup(url, 'access_token');
tokenType = gup(url, 'token_type');
expiresIn = gup(url, 'expires_in');
win.close();
validateToken(acToken);
}
} catch(e) {
}
}, 500);
}
function validateToken(token) {
$.ajax({
url: VALIDURL + token,
data: null,
success: function(responseText){
getUserInfo();
loggedIn = true;
$('#loginText').hide();
$('#logoutText').show();
},
dataType: "jsonp"
});
}
function getUserInfo() {
$.ajax({
url: 'https://www.googleapis.com/oauth2/v1/userinfo?access_token=' + acToken,
data: null,
success: function(resp) {
user = resp;
console.log(user);
$('#uName').text('Welcome ' + user.name);
$('#imgHolder').attr('src', user.picture);
},
dataType: "jsonp"
});
}
//credits: http://www.netlobo.com/url_query_string_javascript.html
function gup(url, name) {
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\#&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( url );
if( results == null )
return "";
else
return results[1];
}
function startLogoutPolling() {
$('#loginText').show();
$('#logoutText').hide();
loggedIn = false;
$('#uName').text('Welcome ');
$('#imgHolder').attr('src', 'none.jpg');
}
The code works fine as far as the login goes. It's after logging in that I don't know what to do. I've tried multiple ideas and have gotten nowhere. Any ideas on how I can call tags from tag manager in "readonly" mode after this login?
Hi I just decided to try using the JavaScript web app method and was able to get this working. If you run into the same issue using the ajax version here is the documentation! Make sure to select the JavaScript tab or you can try the oAuth2.
https://developers.google.com/identity/protocols/OAuth2UserAgent
I have successfully figured out node.js/Express code for making a single http.request to my server. However, the next step is to make multiple requests which use the same res.render statement at the end.
Here is my successful working code:
module.exports = function (app) {
// MODULES - INCLUDES
var xml2js = require('xml2js');
var parser = new xml2js.Parser();
// FORM - SUBMIT - CUCMMAPPER
app.post('/cucmmapper/submit', function (req, res) {
// FORM - DATA COLLECTION
var cucmpub = req.body.cucmpub;
var cucmversion = req.body.cucmversion;
var username = req.body.username;
var password = req.body.password;
// JS - VARIABLE DEFINITION
var authentication = username + ":" + password;
var soapreplyx = '';
var cssx = '';
var spacer = '-----';
var rmline1 = '';
var rmline2 = '';
var rmline3 = '';
var rmline4 = '';
var rmbottomup1 = '';
var rmbottomup2 = '';
var rmbottomup3 = '';
// HTTP.REQUEST - BUILD CALL
var https = require("https");
var headers = {
'SoapAction': 'CUCM:DB ver=' + cucmversion + ' listCss',
'Authorization': 'Basic ' + new Buffer(authentication).toString('base64'),
'Content-Type': 'text/xml; charset=utf-8'
};
// SOAP - AXL CALL
var soapBody = new Buffer('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/11.5">' +
'<soapenv:Header/>' +
'<soapenv:Body>' +
'<ns:listCss sequence="?">' +
'<searchCriteria>' +
'<name>%</name>' +
'</searchCriteria>' +
'<returnedTags uuid="?">' +
'<name>?</name>' +
'<description>?</description>' +
'<clause>?</clause>' +
'</returnedTags>' +
'</ns:listCss>' +
'</soapenv:Body>' +
'</soapenv:Envelope>');
// HTTP.REQUEST - OPTIONS
var options = {
host: cucmpub, // IP ADDRESS OF CUCM PUBLISHER
port: 8443, // DEFAULT CISCO SSL PORT
path: '/axl/', // AXL URL
method: 'POST', // AXL REQUIREMENT OF POST
headers: headers, // HEADER VAR
rejectUnauthorized: false // REQUIRED TO ACCEPT SELF-SIGNED CERTS
};
// HTTP.REQUEST - Doesn't seem to need this line, but it might be useful anyway for pooling?
options.agent = new https.Agent(options);
// HTTP.REQUEST - OPEN SESSION
let soapRequest = https.request(options, soapResponse => {
soapResponse.setEncoding('utf8');
soapResponse.on('data', chunk => {
soapreplyx += chunk
});
// HTTP.REQUEST - RESULTS + RENDER
soapResponse.on('end', () => {
// EDIT - SCRUB XML OUTPUT
var rmline1 = soapreplyx.replace(/<\?xml\sversion='1\.0'\sencoding='utf-8'\?>/g, '');
var rmline2 = rmline1.replace(/<soapenv:Envelope\sxmlns:soapenv="http:\/\/schemas.xmlsoap.org\/soap\/envelope\/">/g, '');
var rmline3 = rmline2.replace(/<soapenv:Body>/g, '');
var rmline4 = rmline3.replace(/<ns:listCssResponse\sxmlns:ns="http:\/\/www\.cisco\.com\/AXL\/API\/[0-9]*\.[0-9]">/g, '');
var rmbottomup1 = rmline4.replace(/<\/soapenv:Envelope>/g, '');
var rmbottomup2 = rmbottomup1.replace(/<\/soapenv:Body>/g, '');
var xmlscrubbed = rmbottomup2.replace(/<\/ns:listCssResponse>/g, '');
// console.log(xmlscrubbed);
// console.log(spacer);
// XML2JS - TESTING
parser.parseString(xmlscrubbed, function (err, result) {
var cssx = result['return']['css'];
// console.log(cssx);
// console.log(spacer);
res.render('cucmmapper-results.html', {
title: 'CUCM Toolbox',
cucmpub: cucmpub,
cssx: cssx,
soapreply: soapreplyx,
xmlscrubbed: xmlscrubbed
});
});
});
});
// SOAP - SEND AXL CALL
soapRequest.write(soapBody);
soapRequest.end();
});
}
My guess is that I have to setup several things to make this work:
Another "var soapBody" with my new request (I can do this).
Another "let soapRequest" (I'm good with this too).
Another "soapRequest.write" statement (Again, easy enough).
Split the "res.render" statement out of the specific "let soapRequest" statement and gather all the variable (this is where I'm stuck).
My guess is that I need to use async. However, I can't for the life of me wrap my head around how to get that "res.render" to work with async.
Here is the closest I can come to an answer. However, the "cssx" and "partitionsx" variable are not translated over to the "function complete". They both still show up as null.
module.exports = function (app) {
// MODULES - INCLUDES
var xml2js = require('xml2js');
var parser = new xml2js.Parser();
// FORM - SUBMIT - CUCMMAPPER
app.post('/cucmmapper/submit', function (req, res) {
// FORM - DATA COLLECTION
var cucmpub = req.body.cucmpub;
var cucmversion = req.body.cucmversion;
var username = req.body.username;
var password = req.body.password;
// JS - VARIABLE DEFINITION - GLOBAL
var authentication = username + ":" + password;
var soapreplyx = '';
var cssx = null;
var spacer = '-----';
var rmline1 = '';
var rmline2 = '';
var rmline3 = '';
var rmline4 = '';
var rmbottomup1 = '';
var rmbottomup2 = '';
var rmbottomup3 = '';
var soapreplyp = '';
var partitionsx = null;
var rmline1p = '';
var rmline2p = '';
var rmline3p = '';
var rmline4p = '';
var rmbottomup1p = '';
var rmbottomup2p = '';
var rmbottomup3p = '';
// HTTP.REQUEST - BUILD CALL - GLOBAL
var https = require("https");
var headers = {
'SoapAction': 'CUCM:DB ver=' + cucmversion + ' listCss',
'Authorization': 'Basic ' + new Buffer(authentication).toString('base64'),
'Content-Type': 'text/xml; charset=utf-8'
};
// SOAP - AXL CALL - CSS
var soapBody = new Buffer('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/11.5">' +
'<soapenv:Header/>' +
'<soapenv:Body>' +
'<ns:listCss sequence="?">' +
'<searchCriteria>' +
'<name>%</name>' +
'</searchCriteria>' +
'<returnedTags uuid="?">' +
'<name>?</name>' +
'<description>?</description>' +
'<clause>?</clause>' +
'</returnedTags>' +
'</ns:listCss>' +
'</soapenv:Body>' +
'</soapenv:Envelope>');
// SOAP - AXL CALL - PARTITIONS
var soapBody2 = new Buffer('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/11.5">' +
'<soapenv:Header/>' +
'<soapenv:Body>' +
'<ns:listRpite{artotopm} sequence="?">' +
'<searchCriteria>' +
'<name>%</name>' +
'</searchCriteria>' +
'<returnedTags uuid="?">' +
'<name>?</name>' +
'</returnedTags>' +
'</ns:listRoutePartition>' +
'</soapenv:Body>' +
'</soapenv:Envelope>');
// HTTP.REQUEST - OPTIONS - GLOBAL
var options = {
host: cucmpub, // IP ADDRESS OF CUCM PUBLISHER
port: 8443, // DEFAULT CISCO SSL PORT
path: '/axl/', // AXL URL
method: 'POST', // AXL REQUIREMENT OF POST
headers: headers, // HEADER VAR
rejectUnauthorized: false // REQUIRED TO ACCEPT SELF-SIGNED CERTS
};
// HTTP.REQUEST - GLOBAL (Doesn't seem to need this line, but it might be useful anyway for pooling?)
options.agent = new https.Agent(options);
// HTTP.REQUEST - OPEN SESSION - CSS
var soapRequest = https.request(options, soapResponse => {
soapResponse.setEncoding('utf8');
soapResponse.on('data', chunk => {
soapreplyx += chunk
});
// HTTP.REQUEST - RESULTS + RENDER
soapResponse.on('end', () => {
// EDIT - SCRUB XML OUTPUT
var rmline1 = soapreplyx.replace(/<\?xml\sversion='1\.0'\sencoding='utf-8'\?>/g, '');
var rmline2 = rmline1.replace(/<soapenv:Envelope\sxmlns:soapenv="http:\/\/schemas.xmlsoap.org\/soap\/envelope\/">/g, '');
var rmline3 = rmline2.replace(/<soapenv:Body>/g, '');
var rmline4 = rmline3.replace(/<ns:listCssResponse\sxmlns:ns="http:\/\/www\.cisco\.com\/AXL\/API\/[0-9]*\.[0-9]">/g, '');
var rmbottomup1 = rmline4.replace(/<\/soapenv:Envelope>/g, '');
var rmbottomup2 = rmbottomup1.replace(/<\/soapenv:Body>/g, '');
var xmlscrubbed = rmbottomup2.replace(/<\/ns:listCssResponse>/g, '');
// console.log(xmlscrubbed);
// console.log(spacer);
// XML2JS - TESTING
parser.parseString(xmlscrubbed, function (err, result) {
var cssx = result['return']['css'];
// console.log(cssx);
// console.log(spacer);
complete();
});
});
});
// SOAP - SEND AXL CALL - CSS
soapRequest.write(soapBody);
soapRequest.end();
// SOAP - SEND AXL CALL - PARTITIONS
var soapRequest2 = https.request(options, soapResponse2 => {
soapResponse2.setEncoding('utf8');
soapResponse2.on('data', chunk => {
soapreplyp += chunk
});
// HTTP.REQUEST - RESULTS + RENDER
soapResponse2.on('end', () => {
// EDIT - SCRUB XML OUTPUT
var rmline1p = soapreplyy.replace(/<\?xml\sversion='1\.0'\sencoding='utf-8'\?>/g, '');
var rmline2p = rmline1.replace(/<soapenv:Envelope\sxmlns:soapenv="http:\/\/schemas.xmlsoap.org\/soap\/envelope\/">/g, '');
var rmline3p = rmline2.replace(/<soapenv:Body>/g, '');
var rmline4p = rmline3.replace(/<ns:listCssResponse\sxmlns:ns="http:\/\/www\.cisco\.com\/AXL\/API\/[0-9]*\.[0-9]">/g, '');
var rmbottomup1p = rmline4.replace(/<\/soapenv:Envelope>/g, '');
var rmbottomup2p = rmbottomup1.replace(/<\/soapenv:Body>/g, '');
var xmlscrubbedp = rmbottomup2.replace(/<\/ns:listCssResponse>/g, '');
console.log(xmlscrubbedp);
console.log(spacer);
// XML2JS - TESTING
parser.parseString(xmlscrubbedp, function (err, result) {
var partitionsx = result['return']['css'];
// console.log(partitionsx);
// console.log(spacer);
complete();
});
});
});
// SOAP - SEND AXL CALL - PARTITIONS
soapRequest2.write(soapBody2);
soapRequest2.end();
// PAGE - RENDER
function complete() {
if (cssx !== null && partitionsx !== null) {
res.render('cucmmapper-results.html', {
title: 'CUCM Toolbox',
cucmpub: cucmpub,
cssx: cssx,
partitionsx: partitionsx,
})
} else {
res.render('cucmerror.html', {
title: 'CUCM Toolbox',
})
}
};
});
}
Any help or suggestions would be greatly appreciated.
OK, so the thing to remember is that there is always one request mapped to one response in HTTP. So you can't send multiple requests and expect to get just one response from that.
Instead, you need to have the server keep track of what's been posted (perhaps in a database on a production app), and respond to each request in turn. One way might be to respond with partial documents, or respond with other codes that indicate the submission was accepted but that you need to send another request to push more info, that sort of thing.
But again, you can't strictly accept multiple requests without responding and then respond only after all requests are given.
I'm having a few problems with this, so I'll try to keep it simple. What's happening in the first script is a new Google doc file gets made from a copy of a "master" doc I've defined, which gets its data populated from Form submissions, and that new copy is ultimately moved to a Folder on my Drive. The second script is supposed to send that copied file to the Google Cloud Print. The first script works perfect; I have it triggered on a form submit. The second script works by itself, but only when I explicitly define the master doc ID in the "content" section. Because with each Form submission a new doc gets made, I was having trouble integrating the new doc's ID with the second script. Right now, I tried pulling from the var file, but that's not working. I might have a syntax issue.
My other problem is I need to merge my second script with the first, in a way that gets triggered on the same Form Submit and probably execute after the PDF creation and Email send, but before it gets moved to the folder.
Any help or advice would be greatly appreciated.
And I've removed some of my IDs and sensitive information where you only see double quotes.
// Work Order
// Get template from Google Docs and name it
var docTemplate = ""; // *** replace with your template ID ***
var docName = "Work Order";
function addDates() {
var date = new Date(); // your form date
var holiday = ["09/04/2017", "10/09/2017", "11/23/2017", "12/24/2017", "12/25/2017", "01/01/2018"]; //Define holiday dates in MM/dd/yyyy
var days = 5; //No of days you want to add
date.setDate(date.getDate());
var counter = 0;
if (days > 0) {
while (counter < days) {
date.setDate(date.getDate() + 1);
var check = date.getDay();
var holidayCheck = holiday.indexOf(Utilities.formatDate(date, "EDT", "MM/dd/yyyy"));
if (check != 0 && check != 6 && holidayCheck == -1) {
counter++;
}
}
}
Logger.log(date) //for this example will give 08/16/2017
return date;
}
// When Form Gets submitted
function onFormSubmit(e) {
//Get information from form and set as variables
var email_address = "";
var job_name = e.values[1];
var ship_to = e.values[11];
var address = e.values[12];
var order_count = e.values[7];
var program = e.values[2];
var workspace = e.values[3];
var offer = e.values[4];
var sort_1 = e.values[5];
var sort_2 = e.values[6];
var image_services = e.values[9];
var print_services = e.values[10];
var priority = e.values[13];
var notes = e.values[14];
var formattedDate = Utilities.formatDate(new Date(), "EDT", "MM/dd/yyyy");
var expirationDate = Utilities.formatDate(addDates(), "EDT", "MM/dd/yyyy");
// Get document template, copy it as a new temp doc, and save the Doc's id
var copyId = DriveApp.getFileById(docTemplate)
.makeCopy(docName + ' for ' + job_name)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document's body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys,in our google doc template
copyBody.replaceText('keyJobName', job_name);
copyBody.replaceText('keyShipTo', ship_to);
copyBody.replaceText('keyAddress', address);
copyBody.replaceText('keyOrderCount', order_count);
copyBody.replaceText('keyProgram', program);
copyBody.replaceText('keyWorkspace', workspace);
copyBody.replaceText('keyOffer', offer);
copyBody.replaceText('keySort1', sort_1);
copyBody.replaceText('keySort2', sort_2);
copyBody.replaceText('keyImageServices', image_services);
copyBody.replaceText('keyPrintServices', print_services);
copyBody.replaceText('keyPriority', priority);
copyBody.replaceText('keyNotes', notes);
copyBody.replaceText('keyDate', formattedDate);
copyBody.replaceText('keyDue', expirationDate);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
// Attach PDF and send the email
var subject = "New Job Submission";
var body = "Here is the work order for " + job_name + "";
MailApp.sendEmail(email_address, subject, body, {
htmlBody: body,
attachments: pdf
});
// Move file to folder
var file = DriveApp.getFileById(copyId);
DriveApp.getFolderById("").addFile(file);
file.getParents().next().removeFile(file);
}
function printGoogleDocument(file, docName) {
// For notes on ticket options see https://developers.google.com/cloud-print/docs/cdd?hl=en
var ticket = {
version: "1.0",
print: {
color: {
type: "STANDARD_COLOR"
},
duplex: {
type: "NO_DUPLEX"
},
}
};
var payload = {
"printerid": "",
"content": file,
"title": docName,
"contentType": "google.kix", // allows you to print google docs
"ticket": JSON.stringify(ticket),
};
var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/submit', {
method: "POST",
payload: payload,
headers: {
Authorization: 'Bearer ' + GoogleCloudPrint.getCloudPrintService().getAccessToken()
},
"muteHttpExceptions": true
});
// If successful, should show a job here: https://www.google.com/cloudprint/#jobs
response = JSON.parse(response);
if (response.success) {
Logger.log("%s", response.message);
} else {
Logger.log("Error Code: %s %s", response.errorCode, response.message);
}
return response;
}
**
Update 8/14 with Sandy Good's suggestion:
**
I've attempted to do what you suggested, but now it's not creating the doc or sending to the cloud print. Any thoughts?
// Work Order
// Get template from Google Docs and name it
var docTemplate = ""; // *** replace with your template ID ***
var docName = "Work Order";
function addDates() {
var date = new Date(); // your form date
var holiday = ["09/04/2017", "10/09/2017", "11/23/2017", "12/24/2017", "12/25/2017", "01/01/2018"]; //Define holiday dates in MM/dd/yyyy
var days = 5; //No of days you want to add
date.setDate(date.getDate());
var counter = 0;
if (days > 0) {
while (counter < days) {
date.setDate(date.getDate() + 1);
var check = date.getDay();
var holidayCheck = holiday.indexOf(Utilities.formatDate(date, "EDT", "MM/dd/yyyy"));
if (check != 0 && check != 6 && holidayCheck == -1) {
counter++;
}
}
}
Logger.log(date) //for this example will give 08/16/2017
return date;
}
function createNewDoc(values) {
var email_address = "";
var job_name = e.values[1];
var ship_to = e.values[11];
var address = e.values[12];
var order_count = e.values[7];
var program = e.values[2];
var workspace = e.values[3];
var offer = e.values[4];
var sort_1 = e.values[5];
var sort_2 = e.values[6];
var image_services = e.values[9];
var print_services = e.values[10];
var priority = e.values[13];
var notes = e.values[14];
var formattedDate = Utilities.formatDate(new Date(), "EDT", "MM/dd/yyyy");
var expirationDate = Utilities.formatDate(addDates(), "EDT", "MM/dd/yyyy");
// Get document template, copy it as a new temp doc, and save the Doc's id
var copyId = DriveApp.getFileById(docTemplate)
.makeCopy(docName + ' for ' + job_name)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document's body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys,in our google doc template
copyBody.replaceText('keyJobName', job_name);
copyBody.replaceText('keyShipTo', ship_to);
copyBody.replaceText('keyAddress', address);
copyBody.replaceText('keyOrderCount', order_count);
copyBody.replaceText('keyProgram', program);
copyBody.replaceText('keyWorkspace', workspace);
copyBody.replaceText('keyOffer', offer);
copyBody.replaceText('keySort1', sort_1);
copyBody.replaceText('keySort2', sort_2);
copyBody.replaceText('keyImageServices', image_services);
copyBody.replaceText('keyPrintServices', print_services);
copyBody.replaceText('keyPriority', priority);
copyBody.replaceText('keyNotes', notes);
copyBody.replaceText('keyDate', formattedDate);
copyBody.replaceText('keyDue', expirationDate);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
// Attach PDF and send the email
var subject = "New Job Submission";
var body = "Here is the work order for " + job_name + "";
MailApp.sendEmail(email_address, subject, body, {
htmlBody: body,
attachments: pdf
});
// Move file to folder
var file = DriveApp.getFileById(copyId);
DriveApp.getFolderById("").addFile(file);
file.getParents().next().removeFile(file);
}
function printGoogleDocument(file, docName) {
// For notes on ticket options see https://developers.google.com/cloud-print/docs/cdd?hl=en
var ticket = {
version: "1.0",
print: {
color: {
type: "STANDARD_COLOR"
},
duplex: {
type: "NO_DUPLEX"
},
}
};
var payload = {
"printerid": "",
"content": file,
"title": docName,
"contentType": "google.kix", // allows you to print google docs
"ticket": JSON.stringify(ticket),
};
var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/submit', {
method: "POST",
payload: payload,
headers: {
Authorization: 'Bearer ' + GoogleCloudPrint.getCloudPrintService().getAccessToken()
},
"muteHttpExceptions": true
});
// If successful, should show a job here: https://www.google.com/cloudprint/#jobs
response = JSON.parse(response);
if (response.success) {
Logger.log("%s", response.message);
} else {
Logger.log("Error Code: %s %s", response.errorCode, response.message);
}
return response;
}
// When Form Gets submitted
function onFormSubmit(e) {
//Get information from form and set as variables
var values = e.values;
createNewDoc(values);
printGoogleDocument(file, docName);
}
Not sure if that is what you are after, but the easiest way to execute functions consecutively is to pass a callback function as an argument to your function.
Here's the list of simple functions assigned to variables.
var addFive = function(number, callback){
number += 5;
if (callback) {
return callback(number);
}
return number;
}
var multiplyByFive = function(number, callback){
number *= 5;
if (callback) {
return callback(number);
}
return number;
}
var subtractFive = function(number, callback){
number -= 5;
if (callback) {
return callback(number);
}
return number;
}
You can then just chain call them like this.
function test() {
var result = addFive(7, function(number) {
return multiplyByFive(number, function(number){
return subtractFive(number);
});
});
Logger.log(result); //logs (7 + 5) * 5 - 5 = 55
}
Of course, if your functions only perform operations like creating files and don't return values, feel free to omit the 'return' statement.
I have more questions in regards to this project, but I think this specific question has been answered, so here's the final code for future reference.
// Work Order
// Get template from Google Docs and name it
var docTemplate = ""; // *** replace with your template ID ***
var docName = "Work Order";
function addDates() {
var date = new Date(); // your form date
var holiday = ["09/04/2017", "10/09/2017", "11/23/2017", "12/24/2017", "12/25/2017", "01/01/2018"]; //Define holiday dates in MM/dd/yyyy
var days = 5; //No of days you want to add
date.setDate(date.getDate());
var counter = 0;
if (days > 0) {
while (counter < days) {
date.setDate(date.getDate() + 1);
var check = date.getDay();
var holidayCheck = holiday.indexOf(Utilities.formatDate(date, "EDT", "MM/dd/yyyy"));
if (check != 0 && check != 6 && holidayCheck == -1) {
counter++;
}
}
}
Logger.log(date) //for this example will give 08/16/2017
return date;
}
function createNewDoc(values) {
//Get information from form and set as variables
var email_address = "";
var job_name = values[1];
var ship_to = values[11];
var address = values[12];
var order_count = values[7];
var program = values[2];
var workspace = values[3];
var offer = values[4];
var sort_1 = values[5];
var sort_2 = values[6];
var image_services = values[9];
var print_services = values[10];
var priority = values[13];
var notes = values[14];
var formattedDate = Utilities.formatDate(new Date(), "EDT", "MM/dd/yyyy");
var expirationDate = Utilities.formatDate(addDates(), "EDT", "MM/dd/yyyy");
// Get document template, copy it as a new temp doc, and save the Doc's id
var copyId = DriveApp.getFileById(docTemplate)
.makeCopy(docName + ' for ' + job_name)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document's body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys,in our google doc template
copyBody.replaceText('keyJobName', job_name);
copyBody.replaceText('keyShipTo', ship_to);
copyBody.replaceText('keyAddress', address);
copyBody.replaceText('keyOrderCount', order_count);
copyBody.replaceText('keyProgram', program);
copyBody.replaceText('keyWorkspace', workspace);
copyBody.replaceText('keyOffer', offer);
copyBody.replaceText('keySort1', sort_1);
copyBody.replaceText('keySort2', sort_2);
copyBody.replaceText('keyImageServices', image_services);
copyBody.replaceText('keyPrintServices', print_services);
copyBody.replaceText('keyPriority', priority);
copyBody.replaceText('keyNotes', notes);
copyBody.replaceText('keyDate', formattedDate);
copyBody.replaceText('keyDue', expirationDate);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
// Attach PDF and send the email
var subject = "New Job Submission";
var body = "Here is the work order for " + job_name + "";
MailApp.sendEmail(email_address, subject, body, {
htmlBody: body,
attachments: pdf
});
// Move file to folder
var file = DriveApp.getFileById(copyId);
DriveApp.getFolderById("").addFile(file);
file.getParents().next().removeFile(file);
}
function printGoogleDocument(file, docName) {
// For notes on ticket options see https://developers.google.com/cloud-print/docs/cdd?hl=en
var ticket = {
version: "1.0",
print: {
color: {
type: "STANDARD_COLOR"
},
duplex: {
type: "NO_DUPLEX"
},
}
};
var payload = {
"printerid": "",
"content": file,
"title": docName,
"contentType": "google.kix", // allows you to print google docs
"ticket": JSON.stringify(ticket),
};
var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/submit', {
method: "POST",
payload: payload,
headers: {
Authorization: 'Bearer ' + GoogleCloudPrint.getCloudPrintService().getAccessToken()
},
"muteHttpExceptions": true
});
// If successful, should show a job here: https://www.google.com/cloudprint/#jobs
response = JSON.parse(response);
if (response.success) {
Logger.log("%s", response.message);
} else {
Logger.log("Error Code: %s %s", response.errorCode, response.message);
}
return response;
}
// When Form Gets submitted
function onFormSubmit(e) {
var values = e.values;
createNewDoc(values);
printGoogleDocument(file, docName);
}
This code for a Google Chrome Extension doesn't work. I am new to Javascript and I am not sure what the problem is. Any help would be greatly appreciated.
JS/jQuery
var userV = serviceName + 'Username';
var passV = serviceName + 'Password';
boolean works = true;
var User = {
passV: password,
userV: username,
works = true;
}
chrome.storage.sync.set({User : userV}, function() {
console.log('');
});
chrome.storage.sync.set({User : passV }, function() {
console.log('');
});
Script
chrome.storage.sync.get("userV", function (User) {
sUsername = User.userV;
};
chrome.storage.sync.get("passV", function (User) {
sPassword = User.passV;
};
Thank you for any help.
In your code you are storing User and Password in the same Key Name hence you will get only Last assigned value,
as well as your retrieving the value by value not by key
JS/jQuery
var userV = serviceName + 'Username';
var passV = serviceName + 'Password';
boolean works = true;
var User = {
passV: password,
userV: username,
works = true;
}
chrome.storage.sync.set({User : userV}, function() {
console.log('');
});
chrome.storage.sync.set({Pass : passV }, function() {
console.log('');
});
Script
chrome.storage.sync.get("User", function (data) {
sUsername = data.User;
};
chrome.storage.sync.get("Pass", function (data) {
sPassword = data.Pass;
};
For more simplify, you can store the whole User object into the storage. When you want to store your user data, the code is like the following:
var userV = serviceName + 'Username';
var passV = serviceName + 'Password';
boolean worksV = true;
var user = {
password: passV,
username: userV,
works: worksV
};
chrome.storage.sync.set({"user" : user}, function() {
// Do something...
});
Then, when you want to retrieve the stored data, the code is:
chrome.storage.sync.get("user", function(data) {
var user = data.user;
var passV = user.password;
var userV = user.username;
var worksV = user.works;
// Do something...
});
I think that you don't need to store each data item as each property. I recommend that it will be stored as one object.