问题
I'm trying to have a function run with a time-driven (clock) trigger. My issue is, the function needs variables sent to it as parameters. Normally if I'm not using a trigger I'll just send it directly like this.
<script>
function runFunction(){
google.script.run.myFunction(x,y,z);
}
</script>
And on the server side, I'll call them easily.
function myFunction(x,y,z){
var a = x;
var b = y;
var c = z;
Logger.log(a+b+c);
}
But when I'm using a time-driven (clock) trigger to run the function how can I get x,y,z
into the function.
I searched around and saw one method of creating scriptProperties
out of the parameters in the trigger function like this.
EDITED This is the actual code.
Client side.
<script>
function sendCall() {
var testNumber = document.getElementById('numberCall').value;
var testGroup = document.getElementById('groupsCall').value;
var testtime = document.getElementById('scheduleCall').value;
var now = document.getElementsByName('sendTimeCall')[0].checked;
var number;
if(testNumber == ''){
number = null;
}else{
number = testNumber;
}
var group;
if(testGroup == ""){
group = null;
}else{
group = testGroup;
}
var time;
if(testtime == ''){
time = null;
}else{
time = testtime;
}
var file = document.getElementsByName('audio')[0].files[0];
var name = file.name;
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
google.script.run.withSuccessHandler(success2).triggerCall(group, number, content, time, now, name);
return false;
}
reader.readAsDataURL(file);
}
</script>
Server side - Trigger Function.
function triggerCall(group, number, content, time, now, name){
var scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperties({
'GROUP_CALL': group,
'AUDIO': content,
'NUMBER_CALL': number,
'FILE_NAME': name
});
var status;
if(now){
status = 'Call Sent';
}else{
status = 'Call Scheduled';
}
if(now){
return makeCall(status);
}else{
// Set here the date you want to schedule the one-time trigger
var rawdate = time;
var today_D = new Date(new Date().toLocaleString("en-US", {timeZone: "America/New_York"}));
var scheduled_D = new Date(rawdate);
var time_af = Math.abs(scheduled_D - today_D) / 36e5;
ScriptApp.newTrigger("makeCall")
.timeBased()
.after(time_af * 60 *60 * 1000)
.create();
}
return status;
}
Server side - Here is The function that actually does the work.
function makeCall(status) {
var scriptProperties = PropertiesService.getScriptProperties();
var blob = scriptProperties.getProperty('AUDIO');
var number = scriptProperties.getProperty('NUMBER_CALL');
var group = scriptProperties.getProperty('GROUP_CALL');
var name = scriptProperties.getProperty('FILE_NAME');
var fullNumber;
if(group){
var ss = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxx');
var sheet = ss.getSheetByName(group)
var length = sheet.getLastRow();
var values = sheet.getRange(1, 1, length).getValues();
fullNumber = values.flat();
}else{
var num = number;
var prefix = '+1';
var removeDashes = num.replace(/-/g,"");
var format = prefix + removeDashes;
var comma = format.replace(/ /g, ' +1');
fullNumber = comma.split(' ')
}
//upload file to drive
var folder = DriveApp.getFolderById('xxxxxxxxxxxxxxxxxxxxxx');
var blob = blob.split(",");
var blob = Utilities.newBlob(Utilities.base64Decode(blob[1]), 'audio/mpeg', name);
var file = folder.createFile(blob);
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
var id = file.getId();
for (var i = 0; i < fullNumber.length; i++){
//the url with HTTP request to create a call and parameters
var callsUrl = "https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxxxxxxxxxx/Calls.json";
var payload = {
"To": fullNumber[i],
"From" : "+177777777",
"Twiml" : "<Response><Play>https://docs.google.com/uc?export=play&id=" + id + "</Play></Response>",
};
var options = {
"method" : "post",
"payload" : payload
};
options.headers = {
"Authorization" : "Basic " + Utilities.base64Encode("xxxxxxxxxxx:xxxxxxxx")
};
UrlFetchApp.fetch(callsUrl, options);
}
scriptProperties.deleteProperty('AUDIO');
scriptProperties.deleteProperty('NUMBER_CALL');
scriptProperties.deleteProperty('GROUP_CALL');
scriptProperties.deleteProperty('FILE_NAME');
return status;
}
The problem is when I run the above code without the file input it works, But when I run it as above the function doesn't work. I did some trouble shooting and I think it has to do with transferring the file as a Data URL via the properties method. Is there a limit to how long of a string the VALUE can be?
in a nut shell these are the 2 points of my question.
- Any other ideas how to send parameters to a triggered function
- How I could do it using
PropertiesService
.
回答1:
I would like to propose the following modification.
Modification points:
- I think that the reason of your issue might be due to the maximum data size for PropertiesService. In the current stage, it seems that "Properties total storage" is "500kB / property store". I thought that in this case, when you upload a file, the file size might be over than it.
- In order to remove your issue, how about creating
content
as a temporal file and put the file ID to the PropertiesService?
When above points are reflected to your script, it becomes as follows.
Pattern 1:
In this pattern, content
is saved as a temporal file and that is used in the function of makeCall()
.
triggerCall()
function triggerCall(group, number, content, time, now, name){
var scriptProperties = PropertiesService.getScriptProperties();
var tempFile = DriveApp.createFile("tempFile.txt", content, MimeType.PLAIN_TEXT); // Added
scriptProperties.setProperties({'GROUP_CALL': group,'AUDIO': tempFile.getId(),'NUMBER_CALL': number,'FILE_NAME': name}); // Modified
var status;
if(now){
status = 'Call Sent';
}else{
status = 'Call Scheduled';
}
if(now){
return makeCall(status);
}else{
var rawdate = time;
var today_D = new Date(new Date().toLocaleString("en-US", {timeZone: "America/New_York"}));
var scheduled_D = new Date(rawdate);
var time_af = Math.abs(scheduled_D - today_D) / 36e5;
ScriptApp.newTrigger("makeCall").timeBased().after(time_af * 60 *60 * 1000).create();
}
return status;
}
makeCall()
function makeCall(status) {
var scriptProperties = PropertiesService.getScriptProperties();
var tempfileId = scriptProperties.getProperty('AUDIO'); // Modified
var number = scriptProperties.getProperty('NUMBER_CALL');
var group = scriptProperties.getProperty('GROUP_CALL');
var name = scriptProperties.getProperty('FILE_NAME');
var fullNumber;
if(group){
var ss = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxx');
var sheet = ss.getSheetByName(group)
var length = sheet.getLastRow();
var values = sheet.getRange(1, 1, length).getValues();
fullNumber = values.flat();
}else{
var num = number;
var prefix = '+1';
var removeDashes = num.replace(/-/g,"");
var format = prefix + removeDashes;
var comma = format.replace(/ /g, ' +1');
fullNumber = comma.split(' ')
}
var folder = DriveApp.getFolderById('xxxxxxxxxxxxxxxxxxxxxx');
var tempFile = DriveApp.getFileById(tempfileId); // Added
var text = tempFile.getBlob().getDataAsString(); // Added
tempFile.setTrashed(true); // Added
var blob = text.split(","); // Modified
var blob = Utilities.newBlob(Utilities.base64Decode(blob[1]), 'audio/mpeg', name);
var file = folder.createFile(blob);
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
var id = file.getId();
for (var i = 0; i < fullNumber.length; i++){
var callsUrl = "https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxxxxxxxxxx/Calls.json";
var payload = {"To": fullNumber[i],"From" : "+177777777","Twiml" : "<Response><Play>https://docs.google.com/uc?export=play&id=" + id + "</Play></Response>"};
var options = {"method" : "post","payload" : payload};
options.headers = {"Authorization" : "Basic " + Utilities.base64Encode("xxxxxxxxxxx:xxxxxxxx")};
UrlFetchApp.fetch(callsUrl, options);
}
scriptProperties.deleteProperty('AUDIO');
scriptProperties.deleteProperty('NUMBER_CALL');
scriptProperties.deleteProperty('GROUP_CALL');
scriptProperties.deleteProperty('FILE_NAME');
return status;
}
Pattern 2:
In this pattern, content
is saved to a file as the decoded data and that is used in the function of makeCall()
.
triggerCall()
function triggerCall(group, number, content, time, now, name){
var scriptProperties = PropertiesService.getScriptProperties();
var folder = DriveApp.getFolderById('xxxxxxxxxxxxxxxxxxxxxx'); // Added
var blob = content.split(","); // Added
var blob = Utilities.newBlob(Utilities.base64Decode(blob[1]), 'audio/mpeg', name); // Added
var file = folder.createFile(blob); // Added
scriptProperties.setProperties({'GROUP_CALL': group,'AUDIO': file.getId(),'NUMBER_CALL': number,'FILE_NAME': name}); // Modified
var status;
if(now){
status = 'Call Sent';
}else{
status = 'Call Scheduled';
}
if(now){
return makeCall(status);
}else{
var rawdate = time;
var today_D = new Date(new Date().toLocaleString("en-US", {timeZone: "America/New_York"}));
var scheduled_D = new Date(rawdate);
var time_af = Math.abs(scheduled_D - today_D) / 36e5;
ScriptApp.newTrigger("makeCall").timeBased().after(time_af * 60 *60 * 1000).create();
}
return status;
}
makeCall()
function makeCall(status) {
var scriptProperties = PropertiesService.getScriptProperties();
var fileId = scriptProperties.getProperty('AUDIO'); // Modified
var number = scriptProperties.getProperty('NUMBER_CALL');
var group = scriptProperties.getProperty('GROUP_CALL');
var name = scriptProperties.getProperty('FILE_NAME');
var fullNumber;
if(group){
var ss = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxx');
var sheet = ss.getSheetByName(group)
var length = sheet.getLastRow();
var values = sheet.getRange(1, 1, length).getValues();
fullNumber = values.flat();
}else{
var num = number;
var prefix = '+1';
var removeDashes = num.replace(/-/g,"");
var format = prefix + removeDashes;
var comma = format.replace(/ /g, ' +1');
fullNumber = comma.split(' ')
}
var file = DriveApp.getFileById(fileId); // Modified
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
var id = file.getId();
for (var i = 0; i < fullNumber.length; i++){
var callsUrl = "https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxxxxxxxxxx/Calls.json";
var payload = {"To": fullNumber[i],"From" : "+177777777","Twiml" : "<Response><Play>https://docs.google.com/uc?export=play&id=" + id + "</Play></Response>"};
var options = {"method" : "post","payload" : payload};
options.headers = {"Authorization" : "Basic " + Utilities.base64Encode("xxxxxxxxxxx:xxxxxxxx")};
UrlFetchApp.fetch(callsUrl, options);
}
scriptProperties.deleteProperty('AUDIO');
scriptProperties.deleteProperty('NUMBER_CALL');
scriptProperties.deleteProperty('GROUP_CALL');
scriptProperties.deleteProperty('FILE_NAME');
return status;
}
Note:
- In this modified script, when a file is uploaded,
content
is saved as a temporal file and the file ID is put to the PropertiesService. WhenmakeCall
is run,content
is retrieved by the file ID and convert to the blob and saved it as a file. And the temporal file is removed. By this, the limitation of PropertiesService can be cleared. - But, in the current stage, the maximum blob size of Google Apps Script is 50 MB (52,428,800 bytes). So when the uploaded file size is over 50 MB, an error occurs. In this case, the file is converted to the base64 data. So, the maximum size is the size of base64 data. Please be careful this.
Reference:
- Current limitations
来源:https://stackoverflow.com/questions/63221917/how-to-set-a-time-driven-clock-trigger-for-a-function-that-needs-parameters-se