Get all Google Script Triggers and remove them - google-apps-script

Is there a way to get (and change/remove) all Triggers from all documents in Google Script, as if I opened Script Editor -> Edit -> All your triggers ?
Update:
I added a few test triggers and tried to loop all the spreadsheet files as it is said by Pierre-Marie Richard:
function getAllSpreadsheetTriggers()
{
var files = DriveApp.getFilesByType('application/vnd.google-apps.spreadsheet'),
spreadsheets = [],
triggers = [];
while(files.hasNext())
spreadsheets.push( SpreadsheetApp.openById(files.next().getId()) );
for (var i = 0; i < spreadsheets.length; i++)
{
triggers = ScriptApp.getUserTriggers( spreadsheets[i] );
Logger.log(triggers);
}
}
But .getUserTriggers() always return an empty array. I read this issue, the last answer is "We decided not to take action on this issue. Triggers always belong to a particular script and are not accessible to other scripts. The documentation has been clarified to make this clear."
It turns out that can't it be done?

You can get the trigger from your docs/forms/spreadsheets with the getUserTriggers(document), getUserTriggers(forms) and getUserTriggers(spreadsheet) methods, but it will return only the trigger for the specify file. So you'll need to loop on all the files if you want to modify the triggers from all your Drive's file.
Also, you can't modify trigger by code, but you can delete a trigger (deleteTrigger(Trigger) method) and create a new one (see TriggerBuilder class).
Edit:
As FLighter point it, you can't get the triggers from another script that the one you're running. I should have read the documentation with more attention:
Gets all installable triggers owned by this user in the given
document, for this script or add-on only. This method cannot be used
to see the triggers attached to other scripts.
So, to anwser the original question, no, you can't. You can made some code for each script you've got, but it will require to be trigger manually.

Just so you are aware, in addition to Pierre-Marie Richard's response, you can only delete the triggers you created on a document, you won't be able to delete the triggers created by other users. Any user with edit access can create a trigger on a document but that trigger can only be manipulated by that user.

Related

Getting an error when creating a simple Apps Script trigger

I have a new Forms response spreadsheet that I'm trying to trigger off. I don't make changes (yet) to the default myFunction() method and try to add a trigger. The first field tries to auto-populate forever, spinning and spinning, while I get this error message:
You cannot create a trigger without a target function, please add functions to the attached script.
I've done some online searching, and there are very few similar issues out there, and zero solutions for me.
Before creating a trigger either manually or programmatically you should save the Google Apps Script project.
Tip: Replace the default project name by something descriptive otherwise you might eventually end with a lot of "Untitled project".
One advantage of doing this programmatically from the script editor is that when clicking on the Run button if the script was not save at least one time it will prompt for the project name and save the project.
Resources
https://developers.google.com/apps-script/overview#your_first_script
ScriptApp.newTrigger("must have a function name here not a function declaration")
function imanoob(e) {
Logger.log(JSON.stringify(e));
e.source.toast('I am a noob');
}
Copy both functions into script editor and save them.
Run the second one first and then edit any cell on any tab or sheet.
function createImANoobTrigger() {
if(ScriptApp.getProjectTriggers().filter(t => t.getHandlerFunction() == 'imanoob').length == 0) {
ScriptApp.newTrigger('imanoob').forSpreadsheet(SpreadsheetApp.getActive()).onEdit().create();
}
}

'Exception: Action not allowed' when attempting to programmatically add an Installable Trigger

I have a template google sheet that our company duplicates for every project.
The final result I want is to have an onEdit trigger that does a POST request. I actually already have this working. The issue stems from this: This trigger cannot be a simple trigger, it must be an installable trigger because according to Google's restrictions, simple triggers cannot make external requests, but installable triggers can. Again, all of that works, I just have to set up the installable trigger manually.
As I mentioned, this is a template document, so creating a new installable trigger manually every time it is duplicated is a real pain. I want to improve my UX by having it done automatically. Now the API documentation DOES detail how you can do this programmatically right here. So it definitely should be possible if I'm reading this correctly.
In order to have this trigger automatically created, I, of course, must use another trigger. In this case, it MUST be a simple trigger or we're back with the same issue.
So I added this onOpen() simple trigger function to my code: (convertAlias is the name of the function to run when the onEdit trigger activates)
function onOpen() {
if (ScriptApp.getProjectTriggers().length == 0) {
ScriptApp.newTrigger('convertAlias')
.forSpreadsheet(SpreadsheetApp.getActive().getSheetId())
.onEdit()
.create()
}
}
When I open the document though, I get no results. The stack logging shows the error as Exception: Action not allowed. The error specifically originates from the create() call.
I thought that maybe there was some issue with creating an installable trigger from a simple trigger so I went for the next best thing, a button. I added a button to my spreadsheet that was linked to the same code as a "generateTrigger()" function. Pushing that actually DID bring up the Authorization screen, which is what is expected. But then after authorizing my account, it then goes on to report the same Exception: Action not allowed. After that initial authorization, it does not ask me again and automatically goes to that error. I get the same results from running the function manually in the editor.
Is there any way I can make this installable trigger happen with any sort of automation? Is this an issue with my code, a permissions issue, or something else?
Thanks
It appears I should have just been passing the sheet and not the ID? Doesn't seem right but getting rid of getSheetId() made it work!

Include Parent Folder Name in Spreadsheet onOpen

I would like a spreadsheet to automatically include the name of its parent folder in cell A1 of the active sheet onOpen. I have a script that successfully achieves this if I run it manually, yet I am not able to accomplish this onOpen. As recommended below, I have tried using an installable onOpen trigger but that is not a solution as I want to make copies of the spreadsheet and have the folder name included onOpen. The trigger will not copy with the spreadsheet so I am back to square one. The issue is with permissions, I believe? Any workaround?
You can use something like this to create an installable onOpen trigger if one is not already in the project.
function createOpenTrigger(funcname) {
if(funcname) {
if(!isTrigger(funcname)) {
ScriptApp.newTrigger(functionName).forSpreadsheet(SpreadsheetApp.getActive()).onOpen().create();
}
}
}
function isTrigger(funcName){
var r=false;
if(funcName){
var allTriggers=ScriptApp.getProjectTriggers();
for(var i=0;i<allTriggers.length;i++){
if(funcName==allTriggers[i].getHandlerFunction()){
r=true;
break;
}
}
}
return r;
}
Of course, the user will have to approve it first.
As recommended below, I have tried using an installable onOpen trigger but that is not a solution as I want to make copies of the spreadsheet and have the folder name included onOpen. The trigger will not copy with the spreadsheet so I am back to square one. The issue is with permissions, I believe? Any workaround?
No, the issue isn't with permissions, the issue is related to other concepts. I'll try to make a summary including the minimal of them that I think are required for this question to help you learn the basic terms so you could scan this site and others to find the stuff you will need or that will help you to make more specific questions:
There are two kinds of script projects, bounded and standalone.
Scripts that will make certain actions should be authorized before they execute. Please keep reading.
There are two kinds of triggers, simple an installable
Installable triggers could be created manually or by a script. Creating a a trigger by a script requires authorization.
Installable triggers only could execute functions that the user that is creating the trigger either manually or through a script had been authorized. If you create an installable trigger but later makes changes to the script, perhaps this will make that your script should be authorized again.
Installable triggers could be created for spreadsheets by using bounded and standalone project scripts. This kind of triggers require authorization to access non public spreadsheets
To get the parent folder of a spreadsheet your script should use the Drive Service or the Drive Advanced Service. This requires authorization.

Copy cell background to other spreadsheets

I am new to Google Apps Script and I don't know how to do some codes. I have two spreadsheets, 1 for the admin and 1 for the client. Every time the admin will update the cells the client side must be updated also. However, only the data in the cells are copied but not the backgrounds in it. Here are the screenshots for better understanding:
Copy value and background from Admin to Client
This requires an installable onEdit(e) trigger. You will also need the id of the client spreadsheet. Note you cannot run this from the Script Editor unless you do it from another function that supplies the event object. See this example.
function updateClient(e) {
var ss=SpreadsheetApp.openById('ClientSideSpreadsheetId');//You need to provide id here. You cannot pass other parameters to this function because it a trigger.
var sh=ss.getSheetByName(e.range.getSheet().getName());
var rg=sh.getRange(e.range.rowStart,e.range.columnStart);
rg.setValue(e.value);
rg.setBackground(e.range.getBackground());
}
I tested this on my account and it works. I suspect that you'll have trouble getting it to run so read the answer in the link I provided thoroughly before telling me that it doesn't work.
This is what the event object looks like:
{"authMode":{},"range":{"columnStart":3,"rowStart":18,"rowEnd":18,"columnEnd":3},"source":{},"user":{"nickname":"nickname","email":"email#email.com"},"triggerUid":"123456","value":"3"}
Event Objects

How to Stop Orphaned Triggers

Interesting use case:
1. Script 1 with ScriptApp trigger management associated as an image link in a Google Site
2. Created a new instance of the script under a new account and update the image link
3. Deleted the container script 1 within the Google Site
4. A user visited the Google Site to invoke the script, but the page was cached pointing to the previous script 1.
5. The on-error trap emails are being emailed to me every time the "deleted" script runs.
How do I delete or stop these triggers?
If you know the user that installed the trigger you could ask them to do to the "All my triggers" menu item in the script editor, find the trigger and delete it.
In the on-error email, there is a link to manage triggers. Make sure that the triggers are really gone. I had this issue with a set of shared spreadsheets, where I thought I had removed all the triggers, but my partner still had some enabled.
In the Script Editor, You can also check for a project's triggers programmatically, then work with that trigger and it's source:
// Get triggers
var triggers = ScriptApp.getProjectTriggers();
// Loop through each trigger
triggers.forEach(function(trigger) {
// Get the id
var id = trigger.getTriggerSourceId();
// You can then use that id to get the related form or a sheet. E.g. :
var ss = SpreadSheetApp.openById(id);
// You can also work with the trigger (i.e. delete it)
ScriptApp.deleteTrigger(trigger);
});
See https://developers.google.com/apps-script/reference/script/script-app for more