Trigger webhook from Google Sheets when button in cell pressed - google-apps-script

We have our sprint capacity planning in Google Sheets, as JIRA wasn't able to efficiently break out tasks up into sprints as per number of story points per task.
We're bringing in a list of all tasks in JIRA, and their associated story points, and with some spreadsheet magic are building the sprints according to the number of available story points.
The spreadsheet updates via Zapier every time there's an edit in JIRA in the specific board, but at times when lots of things are changing it fires a lot of events, as there's so many steps in the Zapier Zap.
I was wondering if it's possible to have a button in a Google Sheets cell that can fire a webhook, perhaps with something as trivial as the date/time that can trigger the Zap to update the spreadsheet?
This means it's less 'expensive' on tasks in Zapier and it's only updating when a user clicks the button in the spreadsheet.

Hello tectomics I believe I have worked out a solution that should work for you.
The solution at a high level is as follows:
Create a script, located in your Google Sheet, that is triggered by a button press. The script makes an HTTP POST request to a Zapier webhook which is listening for any incoming traffic. Once the webhook is caught on Zapier's end it triggers all of your downstream steps located in the zap. Note that for this to work you will require a premium subscription to Zapier as Zapier's webhook app is premium only access.
And now for the details:
The google script is as follows:
function fireZap() {
var endpoint = "ZAPIER_WEBHOOK_URL";
var payload = {
"uuid" : Utilities.getUuid()
};
var options = {
"method" : "post",
"payload" : payload
};
UrlFetchApp.fetch(endpoint, options)
}
NOTE: The endpoint variable is just holding an example, you will have to update that value with the endpoint URL provided by Zapier when you first create your webhook trigger.
The google script makes use of the UrlFetchApp class. Zapier's webhook endpoint only seems to trigger on unique payload data (at least in testing mode, could be different for a live zap) so we generate a unique UUID for the payload.
Once the script is written you must link it to a button located in your workbook. There are many tutorials such as this one that describe the straight forward process of doing this and so I will save myself the trouble.
Once we have all of this in place we head over to Zapier and create a new zap with the Webhooks zap for a trigger. For the trigger event select 'Catch Hook'. Proceed to the 'Customize Hook' section. Here Zapier will provide you with a unique URL endpoint, place this in the endpoint variable back in the google script.
With this complete setup whatever downstream zaps you would like and it will trigger whenever you hit the button located on your sheet.
Hope this helps,
Any questions please let me know.

Related

How to transfer data from webapp to addon

Project_1 is a container-bound script. A container is a readable spreadsheet (Template).
Code_1:
function doPost(e) {
return HtmlService.createHtmlOutput(JSON.stringify(e));
}
The user makes a copy of the Template, deploys the script (Project_1) as a webapp with permissions: "Execute as: Me, Who has access: Anyone". The user is the owner of Project_1.
Project_2 is a script deployed as an add-on. The user from point 1 is not the owner of Project_2.
Code_2:
function sendPost() {
var sheetURL = SpreadsheetApp.getActiveSpreadsheet().getUrl();
var webAppUrl = "https://script.google.com/macros/s/###/exec"; // 7: Part_1 - WebApp: Tester
// var auth = ScriptApp.getOAuthToken();
// var header = { 'Authorization': 'Bearer ' + auth };
var payload = { scriptName: 'updateData', sheetURL: 'sheetURL' };
var options = {
method: 'post',
// headers: header,
muteHttpExceptions: true,
payload: payload
};
var resp = UrlFetchApp.fetch(webAppUrl, options);
var respTxt = resp.getContentText();
console.log('resp: ' + respTxt);
}
function doPost(ev) {
var respWebapp = func(ev);
}
The user installs an add-on (Project_2).
The flow in the direction of addon -> webapp is fine: when sendPost() starts, it sends a request to the webapp and receives a response with the necessary data_1 in response.
The flow in the direction of "someone on the web" -> webapp also flows well: when requesting a webapp_url receives the transferred data_2.
I am trying to transfer data_2 to an addon.
I read a lot about scripts.run, but it seems that this option is not applicable in such a situation.
There is also nowhere to add an eventListener.
I would not want to deploy webapp from my account, so as not to spend my quota for simultaneous executions (<= 30).
Also I would not like to do a sidebar, etc. in the spreadsheet and try to screw eventListener to html. I assume that with this approach, the listener (if it is possible to add it there at all) will be active only when ui is active (the spreadsheet is open and the sidebar is active). Data can come at any time of the day and must be immediately transferred to the addon.
Added:
I feel like I'm stumped. Therefore I reaches out to the community in the hope that someone would suggest a workaround or a new strategy for this initial data. By initial data I mean provide the opportunity for more than 30 users to exchange messages in both directions Spreadsheet <--> External service (for example, Telegram) and at the same time not fall under the limit of 30 simultaneous script executions.
Added_2:
I'm going to assign a bounty, so I'm transferring here from the comments what is missing in the post and updating the question itself.
I rejected the option with immediate entry into the sheet, because this will cause constant calls to the spreadsheet and slow down the performance of the system as a whole.
I am aware of the existence of Google cloud functions and Google compute engine, but would like to stay within the free quotas.
QUESTION: How to transfer data from webapp to addon and execute func () or which workaround to use to achieve the goals?
Here is a list of your requirements:
Trigger add-on code to run from some external request, not using the add-on user interface or time based trigger.
Code runs from the user's account, using their quota
Run the add-on code regardless of whether the user is using the add-on or not. For example, their Google Sheet is closed, and the user may even be signed out.
I only know of one way to do that, and it's with a Sheet's add-on by triggering the "On Change" event by setting a value in a Sheet cell using the Sheets API. The Sheets API must use a special option to set the value "As the User."
The special setting is:
valueInputOption=USER_ENTERED
That option will trigger the "On Change" event even if the Sheet is closed.
Obviously the script making the request needs authorization from the user to set a value in a cell of the Sheet.
If the script sending the request is outside of the user's account then you'd need to use OAuth.
The add-on would need to install an "On Change" trigger for the Sheet and the function that the trigger is bound to would need to determine whether the change was from the special cell designated for this special functionality.
If the request to set a value in the users Sheet is from outside of that users Google account, then the user of the Sheet would need to somehow authorize the OAuth credentials for the Sheets API to make a change to the Sheet.
Depending upon the programming language being used with the Google Sheets API, there may be a Sheets API Library specifically for that language. You can also use the Sheets REST API.
There is an example here on StackOverflow of using the Sheets REST API from Apps Script, but if the external request is from some code that isn't Apps Script, it won't be exactly the same.
I understand that the solutions proposed in the comments, by others and myself, can't work in your scenario because it can't stand an average delay of 30 seconds. In that case I strongly advise you to set up a Cloud project that can be used as an instant server, as opposed to triggers/apps/etc.
In "Code_1" and "Code_2" use a shared data store. In other words, instead of directly passing the data from "Code_1" to "Code_2", make that Code_1 write to the datastore and "Code_2" read from it.
One possibility among many is to use a spreadsheet as a database. In this case you might use on change triggers to do some action when the spreadsheet is changed by one of the "Code_1" scripts and/or use time-driven triggers to do some action with certain frequency or at certain datetime.

How to make Google App script triggers to run on script executions or API requests?

I am aware that installable triggers do not execute/run on Script executions or updates via API requests. For triggers to run, the change or edit has to be done 'manually'. Is there any work-around or solution to this?
Here is my usecase:
I have designed HTML UI that accepts some data and stores that in specific spreadsheet
Since I didn't want any users to have access to backend spreadsheet (to restrict view to other's submission), I have created REST service using TIBCO Cloud Integration > Google connector that writes data to Google spreadsheet
When user submit the response, UI internally invokes above-mentioned TIBCO API and that in turn updates the spreadsheet (using my Google credentials) with response submitted by user
With this arrangement, I don't have to share my Google spreadsheet with all users and expose all submissions. I could have used Google Form, but that is too basic and my UI requirements are quite complex.
Until this point, everything works fine, but as a part of some advance features, I want some functions (written in the script of backend spreadsheet) to trigger on 'onEdit' when my API call write to the spreadsheet and that is where I am stuck. So far, I have tried:
Exposing Google Script as an REST API
Exposing Google Script as Library function
but in all cases, I have to share the spreadsheet with user that invokes the calls, and I dont want that, thanks.

How to manage form responses spreadsheet from non-Apps Script code (Node.js for example)

I'm trying to create a Google Forms add-on that manages approval workflows
Here is the idea:
User A installs the add-on and sets up the approval workflows in the add-on configuration.
User A will be the owner of the Form Responses spreadsheet.
User X is a recipient in that approval workflow
(there might be other recipients such as Y, Z, ... in the workflow,
but for simplicity, let's assume that there is only 1 recipient X)
User B is the respondent, he goes to the form URL and submits a response (this is a request that will be approved/rejected by user X)
After user B submits a request, an email will be sent to user X's Gmail
In this email, there are 1 button: Approve/Reject this request
After user X clicks this button, a new tab is opened. And in this new page, user X can click 2 buttons Approve or Reject to give his feedback on the request of user B
This page is a normal webpage that is built with non-Apps Script
code (for example Nodejs + React)
An email will be sent to both users B and X to tell them that the request is approved/rejected
Finally, in the Form Responses spreadsheet of user A (who installed and configured the add-on), the Approve/Reject status of the request will be updated accordingly
The question is: How a non-Apps Script code can modify the Form
Responses spreadsheet?
From my understanding, in this case, there are only 2 things that can modify the Form Responses spreadsheet:
The Forms add-on code
The bounded script of the Forms Responses spreadsheet (the destination spreadsheet)
But this is a Forms add-on, so there is no bounded script for the destination spreadsheet, so only option 1. The Forms add-on code is feasible
=> There must be a way so that non-Apps Script code can notify The Forms add-on code to update the spreadsheet
Here is my solution at the moment (still not good enough):
I will store the workflow data (configs, responses) on Firebase Cloud Firestore (a real-time document database, it's like the combination of MongoDB and Firebase Realtime Database)
Each time a request is approved/rejected by the recipient, my non-Apps Script code will update the data on Firestore
My Forms add-on code will listen to the changes on Firestore and will update the spreadsheet accordingly
I said that this solution is still not good enough because as you can
check my another question here
Google Apps Script - How to listen for realtime updates in Firebase Cloud Firestore?
=> At the moment, there might be no way for Apps Script to listen to realtime update on Firestore
=> The workaround is to use a time-based trigger to periodically check for new data on Firestore (but can only do once per hour at most
because of the Apps Script quotas)
=> Once per hour to see new updates in the destination spreadsheet is not a good UX for users, it should be realtime)
Any idea how to solve this problem without the once per hour limit?
The question is: How a non-Apps Script code can modify the Form Responses
spreadsheet?
(As already mentioned on a comment by TheMaster) use Google Sheets API.
=> There must be a way so that non-Apps Script code can notify The Forms add-on code to update the spreadsheet
Yes there is, actually, there are. You could:
create a web application that listed to an HTTP POST request as part of you Form Add-on for details see https://developers.google.com/apps-script/guides/web
use the Apps Script API to execute functions from your Form Add-on. For details see https://developers.google.com/apps-script/api/how-tos/execute
Related
How do I create a doPost(e) function in Apps Script project to capture HTTP POST data from web service?

Why Isn't My Spreadsheet Changing From Input Values of An Outside Source?

So I am trying to use an outside source (Zapier) to input values into my spreadsheet. These input values are then "transposed (formula wise)" into my spreadsheet to fit the cell coordinates with which they are to align.
I have the spreadsheet set to run 'onEdit' and when these incoming values arrive, it is supposed to cause the rest of the spreadsheet to change, but the function is not running.
However, if I were to edit the spreadsheet 'manually,' the onEdit function runs perfectly.
So why then would the spreadsheet not be running the function, when the outside source brings its input values?
UPDATE:
So I discovered that if I manually authorize an 'onChange' installable trigger, it will work. But if I create a copy of the same exact spreadsheet, the installable trigger will not exist in the copy. The copy needs to have the trigger without me having to do it manually. So I am trying to create a code inside of Google Script Editor that will either allow me to use the onChange function or install the onChange function in the Developer Hub. Any thoughts? Here is the code I tried but did not work:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("My
Sheet")
var ssid = "My SpreadSheet ID";
ScriptApp.newTrigger('My Sheet)
.forSpreadsheet(ss.getId())
.onChange()
.create();
myFunction()
{
If there is an alternative for the onChange function, then I'm all ears. I just need a function that can run itself in my copies.
As a part of a collaborative effort, let me clarify the Zapier part (this answer does not concern the copy part).
Part 1. Zapier setup
Assuming you have a third-party application that you pull data from (btw, since you decided to use apps script, isn't it easier to drop the middleman like Zapier and connect to the 3P app API – if it has one, ofc – directly?), you created a Catch Hook and a POST Action.
The POST Action setup contains several fields:
URL field - this is where your /exec URL goes (WebApp is deployed via Publish->Deploy as a WebApp). After you deploy your script as a WebApp, you will get a URL that users and scripts can make requests to (it is always of this format https://script.google.com/macros/s/{yourProjectId}/exec - with some slight diff. due to access permissions). To avoid permissions issue, set the Who has access to the app option to anyone or anyone, even anonymous (otherwise, you'll have to devise auth handling).
Payload Type field is irrelevant here, but I suggest using JSON.
Data field is required if you chose the POST Action and should contain key-value pairs of data you would like to transmit via Zapier (the data will be available in parameter/parameters property of the event object).
Part 2. WebApp setup
Published WebApps should have either a doGet() or doPost() function to be able to receive and process requests (or both). Each of them accepts one special argument, which is constructed each time a request to the WebApp is made – an event object.
The event object will contain all the data that you sent from Zapier. You can then use this data to conditionally trigger different functions, pass data to handlers, etc. So, instead of relying on triggers, you can create a function that is called inside the doGet / doPost that will a) populate your target sheet with new values; b) do anything else after that, thus acting as an analogue of onEdit / onChange.
Useful links
Event object structure;
Passing event objects around;
Creating triggers on other documents;

Typeform Submit Trigger in Spreadsheet Script

Our company has made a form with Typeform. Is it possible to trigger the onSubmit event when a new response is sent to the spreadsheet from the Typeform form? Or is there some other way to detect new responses in the spreadsheet?
Is it possible to trigger the onSubmit event when a new response is sent to the spreadsheet from the Typeform form?
You can't do that. Google Forms and Typeform are two different platforms with different mechanisms. The onSubmit event of a google form cannot be made to work with Typeform.
You can write a script to 'poll' the Typeform API (as others have suggested) but there is a more efficient way to achieve what you require.
You'll need to leverage Typeform's Webhook API in tandem with a webhook endpoint. You can deploy a stand-alone apps script as a web app and use it's URL as an endpoint for webhook payloads. The script can then be made to process Typeform submission data and place it into a Google Sheet.
The onSubmit() event has to do with Google Forms, but Typeform does not go through Google Forms.
Instead, you should write a Script that fires from your connected Spreadsheet. However, the onEdit() trigger will not work because the user needs to be logged in for it to work. To work around that, you can write a script that checks every, say, 15 minutes to detect any changes in your Google Sheet.
Then you can trigger some actions to run whenever new data has been added to your Google Sheet.
Typeform offers a native integration with Google Spreadsheet, you can turn it on directly from the Integrate tab. The steps are described here as well.
Every time a new answer is submitted to your typeform it will be added on your google spreadsheet.
There you can have a script to listen to changes and react to it.
As Dimu mentioned, using Typeform webhook will give you a lot more flexibility.
It turns out Typeform has a ready made integration with Zapier to post Typeform answers to Slack. This way you can just click through the process and not have to write a single line of code.
Here it is: https://zapier.com/app/editor/template/883
You can set the trigger for onChange. The sheet captures the Typeform response input as a change and any script can be triggered based on that.