I am attempting to create a script that outputs a cell in the same row to discord based on a checkbox. I've written up so far the following, although I'm really not very good with javascript/Google Script. I cannot get past the auth requirements and do not see the mistake I am making.
const sheet = SpreadsheetApp.getActiveSpreadsheet()
function onEdit(e) {
var discordUrl = "Webhook";
var userName = 3
var channelMsg = userName
let checkboxColumnNo = 5
let range = e.range;
let value = range.getValue().toString();
let column = range.getColumn();
let row = range.getRow();
let sheetName = range.getSheet().getName()
if (column == checkboxColumnNo && value === "true") {userName;
}
var payload = JSON.stringify({content: "Whitelist add " + channelMsg });
var params = {headers: {'Content-Type': 'application/json','Accept': 'application/json'}, method: "POST",payload: payload,muteHttpExceptions: true};
var response = UrlFetchApp.fetch(discordUrl, params);
Logger.log(response.getContentText());
Logger.log(payload);
Logger.log(channelMsg);;
}
Just showing what my sheet layout looks like.
Comparing your code with something very similar that I've done I can only spot 1 difference which is the following:
Your code:
var params = {headers: {'Content-Type': 'application/json','Accept': 'application/json'}, method: "POST",payload: payload,muteHttpExceptions: true};
My code:
var params = {
headers: {
'Content-Type': 'application/json'
},
method: "POST",
payload: payload,
muteHttpExceptions: true
};
Difference:
In your header you have this which I don't, try removing it to see if it works.
'Accept': 'application/json'
Little bonus, here's a tool I use to make nice embedded messages for Discord:
https://leovoel.github.io/embed-visualizer/
Related
I was trying to fetch data from Clearbit API and I get this message : " Exception: The parameters (String,(class),(class)) don't match the method signature for UrlFetchApp.fetch."
Before writing this post I tried to search online but couldn't find the answer.
I share with you my code :
function linkedInUrl(domain) {
let url = `https://company.clearbit.com/v2/companies/find?domain=${domain}`
const api_keys = ""
const header = {
method: 'GET',
headers: {'Authorization':'Bearer ' + api_keys}
}
options = {muteHttpExceptions: true};
var response = UrlFetchApp.fetch(url,header,options)
var data = JSON.parse(response.getContentText())
return "https://www.linkedin.com/"+data.linkedin.handle
}
function techUsed(domain) {
let url = `https://company.clearbit.com/v2/companies/find?domain=${domain}`
const api_keys = ""
const header = {
method: 'GET',
headers: {'Authorization':'Bearer ' + api_keys}
}
options = {muteHttpExceptions: true};
var response = UrlFetchApp.fetch(url,header,options)
var data = JSON.parse(response.getContentText())
tech = ""
for(let i = 0; i < data.tech.length; i++) {
tech += data.tech[i] +","
}
return tech
}
Does anyone have a clue ?
Thank you for your help.
The arguments of fetch(url, params) are url and params. I think that this is the reason for your current issue. So, please modify your script as follows.
From:
let url = `https://company.clearbit.com/v2/companies/find?domain=${domain}`
const api_keys = ""
const header = {
method: 'GET',
headers: {'Authorization':'Bearer ' + api_keys}
}
options = {muteHttpExceptions: true};
var response = UrlFetchApp.fetch(url,header,options)
To:
let url = `https://company.clearbit.com/v2/companies/find?domain=${domain}`;
const api_keys = "###"; // Please set your access token.
options = {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + api_keys },
muteHttpExceptions: true
};
var response = UrlFetchApp.fetch(url, options);
Note:
In this case, your api_keys is valid value for using the API. Please be careful about this.
Unfortunately, I cannot know the response value from the API you want to use. So, if your script below var response = UrlFetchApp.fetch(url, options); occurs an error, please provide the sample value. By this, I would like to confirm your script.
Reference:
fetch(url, params)
You can try this :
function linkedInUrl(domain) {
let url = `https://company.clearbit.com/v2/companies/find?domain=${domain}`
const api_keys = ""
const header = {
method: 'GET',
headers: {'Authorization':'Bearer ' + api_keys}
}
options = {muteHttpExceptions: true};
var res
fetch(url,header,options) //api for the get request
.then(response => response.json())
.then(data => console.log('response',data))
}
My function is showing this error for a few days, before it worked normally. I really don't know how to insert a fix for this problem. Thank you very much in advance.
Service invoked too many times in a short time: urlfetch. Try Utilities.sleep(1000) between calls.
myTrivia # TRIVIA.gs:14
This is my code:
function myTrivia() {
var f = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('TRIVIA');
var data = new Date();
data = Utilities.formatDate(data, "GMT-03:00", "yyyy/MM/dd");
f.getRange('F1').setValue(data);
var url = 'https://triviapw.com.br/cotacao/api/item/';
var [h, ...v] = f.getDataRange().getValues();
var reqs = v.map(([a]) => ({
url,
method: "post",
payload: {id: a, date: data, server: h[6]},
muteHttpExceptions: true
}));
var res = UrlFetchApp.fetchAll(reqs);
var values = res.map(r => {
var str = r.getContentText();
if (r.getResponseCode() == 200 && str != "Requisição inválida") {
var obj = JSON.parse(str);
return [obj.nome, obj.venda, obj.compra];
}
return Array(3).fill("");
});
f.getRange(2, 2, values.length, values[0].length).setValues(values);
}
After using the code suggested below (by #Tanaike), the system reports the following "Invalid request" and after "Exceeded maximum execution time"
I tested an alternative for just one line and it worked normally (this was the old code)
Here's the code:
function myTrivia() {
var f = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('TRIVIA');
var formData = {
'id': f.getRange('A2').getValue(), //A2 IDitem
'date': f.getRange('F1').getValue(), //F1 Date
'server': f.getRange('G1').getValue(), //G1 ServerName
};
var options = {
'method': 'post',
'payload': formData
};
var result = UrlFetchApp.fetch('https://triviapw.com.br/cotacao/api/item/', options);
var response = JSON.parse(result.getContentText());
var res_code = result.getResponseCode();
if (res_code == 200) {
f.getRange('B2').setValue(response.nome); //name item
f.getRange('C2').setValue((response.venda + response.compra) / 2); //midle price for test
}
}
From So my spreadsheet has 116 rows and I usually update it once or twice a day at most., I thought that in this case, your error message of Service invoked too many times in a short time: urlfetch. might not occur. So, I'm worried about other reasons.
But, if you want to use UrlFetchApp.fetch instead of UrlFetchApp.fetchAll, how about the following modified script?
Modified script:
function myTrivia() {
var f = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('TRIVIA');
var data = new Date();
data = Utilities.formatDate(data, "GMT-03:00", "yyyy/MM/dd");
f.getRange('F1').setValue(data);
var url = 'https://triviapw.com.br/cotacao/api/item/';
var [h, ...v] = f.getDataRange().getValues();
var values = v.map(([a]) => {
var r = UrlFetchApp.fetch(url, { method: "post", payload: { id: a, date: data, server: h[6] }, muteHttpExceptions: true });
var str = r.getContentText();
var res;
if (r.getResponseCode() == 200 && str != "Requisição inválida") {
var obj = JSON.parse(str);
res = [obj.nome, obj.venda, obj.compra];
} else {
console.log(str); // If an error occurs, you can see the error message at the log.
res = Array(3).fill("");
}
Utilities.sleep(2000);
return res;
});
f.getRange(2, 2, values.length, values[0].length).setValues(values);
}
In this modified script, each request is run with the synchronous process. And, each request is run by Utilities.sleep(2000). Please adjust the value of 2000 of Utilities.sleep(2000) for your actual situation.
Reference:
sleep(milliseconds)
Added:
When you want to use the script for retrieving one value from one row as a custom function, how about the following sample script? In this sample script, please put a custom function like =myTrivia(A2) to a cell. By this, the script is run for one row.
function myTrivia(id) {
var max = 2; // Number of retry request.
var [date, server] = SpreadsheetApp.getActiveSheet().getRange("F1:G1").getDisplayValues()[0];
var retry = 0;
do {
var url = 'https://triviapw.com.br/cotacao/api/item/';
var r = UrlFetchApp.fetch(url, { method: "post", payload: { id, date, server }, muteHttpExceptions: true });
var str = r.getContentText();
if (r.getResponseCode() == 200 && str != "Requisição inválida") {
var obj = JSON.parse(str);
return [[obj.nome, obj.venda, obj.compra]];
}
retry++;
Utilities.sleep(2000);
} while (retry < max);
return [Array(3).fill("")];
}
In this sample script, when 1st request occurs an error, the request is retried. Even when 2 requests are done, when an error occurs, the empty value is returned. You can adjust the number of retry with max.
With great SO help at previous step, I have writes to sheet almost working with URLFetchApp under service account credentials in a webapp. The code (below) only works with the "put" method; "post" generates an error. My understanding is that updates and inserts can both be done with "put" method. But the code is generating an error when the range is for a new row--that is, the last row in the sheet is not blank.
"range exceeds grid limits when inserting new row"
If it is necessary to have empty rows (e.g., add 1000 rows), does this become a manual maintenance job to monitor and periodically add new blank rows? I expected the "put" to simply add a new row. Is there another method with URLFetchApp to first add rows to the "grid" before inserting data? Thank you for any guidance!
function postData(ssID,updateRange,data) {
if (clientToken) {
var url= `https://sheets.googleapis.com/v4/spreadsheets/${ssID}/values/${updateRange}?valueInputOption=RAW`
var options = {
muteHttpExceptions: true,
contentType: 'application/json',
method:'put',
payload: JSON.stringify(data),
headers: { Authorization: 'Bearer ' + clientToken }
};
var response= UrlFetchApp.fetch(url,options);
var responseCode = response.getResponseCode();
var responseBody = response.getContentText();
if (responseCode === 200) {
var responseJson = JSON.parse(responseBody)
return responseJson;
} else {
Logger.log(Utilities.formatString("Request failed. Expected 200, got %d: %s", responseCode, responseBody))
return responseCode;
}
} else {//handle failed authorization }
} //end postData
Unfortunately, there is no method in the Sheets API V4 that can automatically add rows when the given range exceeds the sheet range.
What you can do is to get the rowCount of a specific sheet by using Method: spreadsheets.get then compare it with the range you will use to update values. If rowCount is less than the update range, use Method: spreadsheets.batchUpdate to update the sheet dimension.
Demo:
Example Sheet:
Code:
function request(ssID="spreadsheet id here",updateRange = "A1499:A1500",data) {
if (clientToken) {
var ssGetUrl= `https://sheets.googleapis.com/v4/spreadsheets/${ssID}`
var options = {
muteHttpExceptions: true,
contentType: 'application/json',
method:'get',
headers: { Authorization: 'Bearer ' + clientToken }
};
var ssGetresponse= JSON.parse(UrlFetchApp.fetch(ssGetUrl,options));
var sheets = ssGetresponse.sheets;
var rowCount = 0;
var sheetId = 0;
sheets.forEach(sheet => {
if(sheet.properties.sheetId == sheetId){
rowCount = sheet.properties.gridProperties.rowCount
}
})
var num = parseInt(updateRange.split(":")[1].replace(/[^0-9]/g,'')); //remove letters in updateRange and convert it to string
if(rowCount < num){
var diff = num - rowCount;
var resource = {
"requests": [
{
"appendDimension": {
"length": diff,
"dimension": "ROWS",
"sheetId": 0
}
}
]
};
var ssBatchUpdateUrl= `https://sheets.googleapis.com/v4/spreadsheets/${ssID}:batchUpdate`
var options = {
muteHttpExceptions: true,
contentType: 'application/json',
method:'post',
payload: JSON.stringify(resource),
headers: { Authorization: 'Bearer ' + clientToken }
};
var response= JSON.parse(UrlFetchApp.fetch(ssBatchUpdateUrl,options));
}
//insert code for updating range values
}
}
After executing code:
Note: The demo above is for increasing the number of rows when the update range is beyond the sheet's actual rows. For instance, if you have a range that the column is beyond the sheet's actual column, you can update the script to also read the columnCount, modify the parser to also get column part of A1 Notation and add another entry on appendDimension with COLUMN as dimension.
Try this:
function postData(ssID, updateRange, data) {
const ss = SpreadsheetApp.openById(ssID);
const sh = ss.getRange(updateRange).getSheet();//I assumed range is in A1 notation
const lr = sh.getLastRow();
if (lr == sh.getMaxRows()) {
sh.insertRowsAfter(lr, data.length);
}
if (clientToken) {
var url = `https://sheets.googleapis.com/v4/spreadsheets/${ssID}/values/${updateRange}?valueInputOption=RAW`
var options = {
muteHttpExceptions: true,
contentType: 'application/json',
method: 'put',
payload: JSON.stringify(data),
headers: { Authorization: 'Bearer ' + clientToken }
};
var response = UrlFetchApp.fetch(url, options);
var responseCode = response.getResponseCode();
var responseBody = response.getContentText();
if (responseCode === 200) {
var responseJson = JSON.parse(responseBody)
return responseJson;
} else {
Logger.log(Utilities.formatString("Request failed. Expected 200, got %d: %s", responseCode, responseBody))
return responseCode;
}
} else {//handle failed authorization }
} //end postData
I have a script that will post available stock adjust to Shopify but I don't know how to extend that and get the payload from cells in the sheet and ideally loop the payload so I can update more than one item at a time.
REF: https://shopify.dev/docs/admin-api/rest/reference/inventory/inventorylevel#adjust-2021-01
I want to have cells in the sheet for "location_id", "inventory_item_id", "available_adjustment" and loop these so I could have below for example.
"location_id"
"inventory_item_id"
"available_adjustment"
11594563
34516664746035
1
11595526
34516664746851
-1
11215528
34516664567861
5
11595574
34516664745685
6
This is the current script that is working but I need to manually change the payload and run one at a time where I want to be able to adjust a lot more in one hit.
var url = "https://**********.myshopify.com/admin/api/2021-01/inventory_levels/adjust.json";
var payloaddata = {
"location_id": "11594563",
"inventory_item_id": "34516664746035",
"available_adjustment": "-1"
};
var payload = JSON.stringify(payloaddata);
var username = "*********";
var password = "*********";
var response = UrlFetchApp.fetch(url, {
method: "POST",
payload: payload,
contentType: "application/json",
headers: { "Authorization": "Basic " + Utilities.base64Encode(username + ":" + password) }
});
Logger.log(response.getContentText());
var json = response.getContentText();
var data = JSON.parse(json);
Logger.log(data);
} ```
Assuming that your code is working then try this:
I also assume that you spreadsheet looks like your table with same headers and same order of columns
function shopifyPost() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet Name');
const [hA, ...rows] = sh.getDataRange().getValues();
const url = "https://**********.myshopify.com/admin/api/2021-01/inventory_levels/adjust.json";
rows.forEach((r, i) => {
let pld = {};
pld[hA[0]] = r[0];
pld[hA[1]] = r[1];
pld[hA[2]] = r[2];
let payload = JSON.stringify(pld);
let username = "*********";
let password = "*********";
let response = UrlFetchApp.fetch(url, {
method: "POST",
payload: payload,
contentType: "application/json",
headers: { "Authorization": "Basic " + Utilities.base64Encode(username + ":" + password) }
});
});
Logger.log(response.getContentText());
var json = response.getContentText();
var data = JSON.parse(json);
Logger.log(data);
}
The first line looked like this: (after stringifying it)
{"location_id":11594563,"inventory_item_id":34516664746035,"available_adjustment":1}
This is what my data sheet looked like:
location_id
inventory_item_id
available_adjustment
11594563
34516664746035
1
11595526
34516664746851
-1
11215528
34516664567861
5
11595574
34516664745685
6
I've been searching how to do this, but i didn't find anything. After a while, i came up with the script i'll post as an answer.
I'm posting this for myself and anyone who might find it useful.
You'll need to get a dropbox access token, that can be obtained after creating a dropbox app.
function send2dropbox(file) {
var dropboxTOKEN = 'XXXxxx';
var path = '/somePath/' + file.getName();
var dropboxurl = 'https://api.dropboxapi.com/2/files/save_url';
var fileurl = 'https://drive.google.com/uc?export=download&id=' + file.getId();
var headers = {
'Authorization': 'Bearer ' + dropboxTOKEN,
'Content-Type': 'application/json'
};
var payload = {
"path": path,
"url": fileurl
}
var options = {
method: 'POST',
headers: headers,
payload: JSON.stringify(payload)
};
var response = UrlFetchApp.fetch(dropboxurl, options);
return response;
}
You can find an example HERE