There is a way to do that?. I'm using Drive REST API from client browser, even I´ve tryed to convert a csv file into application/vnd.google-apps.spreadsheet but using v2 the request throws a 403 error saying "Method not supported for appdata contents" and using v3 creates the spreadsheet but in root directory instead of appDataFolder.
And if it isn't possible, can I hide a Google Sheet from the user Drive root?
Here my code to upload (using v3)
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
var metadata = {
'title': 'my title ',
'mimeType': 'application/vnd.google-apps.spreadsheet',
'parents': [{'id': 'appDataFolder'}]
};
var multipartRequestBody =
delimiter +
'Content-Type: application/json; charset=UTF-8\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: text/csv\r\n' +
'\r\n' +
'21/2/2017;prod1;22;33' +
close_delim;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://content.googleapis.com/upload/drive/v3/files?uploadType=multipart&convert=true');
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
xhr.setRequestHeader('Content-Type', 'multipart/mixed; boundary="' + boundary + '"');
xhr.onerror=function(a,b,c){console.log('error',a,b,c)};
xhr.onload = function(a,b,c){console.log('success',a,b,c)};
xhr.onreadystatechange = function () {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200){
console.log(xhr.response);
}
};
xhr.send(multipartRequestBody);
Related
I'm trying to call the Amazon SP-API from Google Apps Script.
I was able to retrieve the access-token. However when trying call the
I attempted to follow the advice on this post: Google Apps Script: Getting Orders from Amazon Selling Partner API (Signing Requests)
There seems to be something wrong with the way the signature is being calculated.
(I am able to make this call in Postman.)
However in Goolge Apps Script I'm getting an InvalidSignature response.
This is my code:
function getAsins() {
const hex = bytes => bytes.map(byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
const digestToHex = data => hex(Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, data));
const toBytes = data => Utilities.newBlob(data).getBytes();
//Credential variables
var access_token = AccessToken();
const ACCESS_ID = 'AKIEXAMPLEEXAMPLEW5';
const ACCESS_KEY = 'bh8EXAMPLEEXAMPLEWw5SA/EXAMPLE+5EXAMPLEP';
const marketplaceId = 'ATVPDKIKX0DER';
//Time variables
var currentDate = new Date();
var isoDate = currentDate.toISOString();
var isoString = isoDate.replace(/-/g, "").replace(/:/g, "").replace(/(\.\d{3})/, "");
var yearMonthDay = Utilities.formatDate(currentDate, 'GTM-4', 'yyyyMMdd');
//API variables
var end_point = 'https://sellingpartnerapi-na.amazon.com';
var aws_region = "us-east-1";
var service = "execute-api";
var termination_string = "aws4_request";
//CanonicalRequest components:
var asin = 'B07X6C9RMF';
var httpRequestMethod = 'GET';
var canonicalURI = '/catalog/2022-04-01/items/' + asin;
var canonicalQueryString = '?marketplaceIds=' + marketplaceId;
var canonicalheaders = 'host:' + "sellingpartnerapi-na.amazon.com" + '\n' + 'x-amz-access-token:' + access_token + '\n' + 'x-amz-date:' + isoDate;
var signedheaders = 'host;x-amz-access-token;x-amz-date'; //;user-agent
var requestPayloadHashed = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, "");//NEW
requestPayloadHashed = requestPayloadHashed.map(function (e) { return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2) }).join("");//NEW
//Building the canonical request
var canonical_string = httpRequestMethod + '\n' + canonicalURI + '\n' + "MarketplaceIds=" + marketplaceId + '\n' + canonicalheaders + '\n\n' + signedheaders + '\n' + requestPayloadHashed;//UPDATED
var canonical_signature = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, canonical_string);
canonical_request = canonical_signature.map(function (e) { return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2) }).join("");
var credential_scope = yearMonthDay + '/' + aws_region + '/' + service + '/' + termination_string;
var string_to_sign = "AWS4-HMAC-SHA256" + '\n' + isoString + '\n' + credential_scope + '\n' + canonical_request;
var kSecret = ACCESS_KEY;
var kDate = Utilities.computeHmacSha256Signature(yearMonthDay, "AWS4" + kSecret);
var kRegion = Utilities.computeHmacSha256Signature(toBytes(aws_region), kDate);
var kService = Utilities.computeHmacSha256Signature(toBytes(service), kRegion);
var kSigning = Utilities.computeHmacSha256Signature(toBytes(termination_string), kService);
var signature = hex(Utilities.computeHmacSha256Signature(toBytes(string_to_sign), kSigning));
Logger.log('signature: ' + signature)
var options = {
'method': 'GET',
'headers': {
'x-amz-access-token': access_token,
'x-amz-date': isoDate,
'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
},
'muteHttpExceptions': true
}
var asinData = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
Logger.log(asinData);
}
This is the response I'm getting:
{
"errors": [
{
"message": "The request signature we calculated does not match the signature you provided.
....
....
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20220701T185142Z
20220701/us-east-1/execute-api/aws4_request
9a5fa583759a5ff04d7ce67d01fcf7157e9f8a58c4fbbdd69f91cb7a816f5650'
",
"code": "InvalidSignature"
}
]
}
Any help sorting this out would be greatly appreciated!
I'm only starting on this but I think the Canonical Query String does not include the question mark.
I am trying to automise sending of the Emails from my account using Gmail API in Google Apps Script.
Here is my code:
function email_checker() {
var yourEmailAddress = "####gmail.com";
var myEmailAddress = "support####.com";
var subject = "testing mail";
var forScope = GmailApp.getInboxUnreadCount();
var htmlBody = '<html><body>' + '<h1>HI</h1>' + '</body></html>';
var message = 'From: Me <' + myEmailAddress + '>\r\n' +
'To: Me <' + myEmailAddress + '>\r\n' +
'Subject: ' + subject + '\r\n' +
'Content-Type: text/html; charset=utf-8\r\n' +
'Content-Transfer-Encoding: quoted-printable\r\n\r\n' +
htmlBody;
var draftBody = Utilities.base64Encode(message);
draftBody = draftBody.replace(/\//g, '_').replace(/\+/g, '-');
var params = {
method: "post",
contentType: "application/json",
headers: {
"Authorization": "Bearer " + ScriptApp.getOAuthToken()
},
muteHttpExceptions: true,
payload: JSON.stringify({
"message": {
"raw": draftBody
}
})
};
var resp = UrlFetchApp.fetch("https://gmail.googleapis.com/upload/gmail/v1/users/me/messages/send", params);
Logger.log(resp.getContentText());
}
I am getting the following error: Media type 'application/json' is not supported.
Can anyone please advise on what I am doing wrong?
Thank you.
I believe your goal and your current situation as follows.
You want to send an email using Gmail API with UrlFetchApp.
You have already done the settings for sending the email.
Gmail API is enabled.
The scopes for sending emails can be included.
Modification points:
From your endtpoint, it is found that the media upload request is used.
In this case,
the request body is required to create with multipart/alternative.
It is not required to use the base64 encode with the web safe.
The content type is required to use message/rfc822.
The created request body can be directly used for payload.
When above points are reflected to your script, it becomes as follows.
Modified script:
function email_checker() {
var yourEmailAddress = "####gmail.com";
var myEmailAddress = "support####.com";
var subject = "testing mail";
var forScope = GmailApp.getInboxUnreadCount();
var htmlBody = '<html><body>' + '<h1>HI</h1>' + '</body></html>';
var message = 'MIME-Version: 1.0\r\n' +
'From: Me <' + myEmailAddress + '>\r\n' +
'To: Me <' + myEmailAddress + '>\r\n' +
'Subject: ' + subject + '\r\n' +
'Content-type: multipart/alternative; boundary=boundaryboundary\r\n\r\n' +
'--boundaryboundary\r\n' +
'Content-type: text/html; charset=UTF-8\r\n' +
'Content-Transfer-Encoding: quoted-printable\r\n\r\n' +
htmlBody + "\r\n\r\n" +
'--boundaryboundary--';
var params = {
method: "post",
contentType: "message/rfc822",
headers: {
"Authorization": "Bearer " + ScriptApp.getOAuthToken()
},
muteHttpExceptions: true,
payload: message
};
var resp = UrlFetchApp.fetch("https://gmail.googleapis.com/upload/gmail/v1/users/me/messages/send", params);
Logger.log(resp.getContentText());
}
Note:
If you want to use the endpoint of POST https://gmail.googleapis.com/gmail/v1/users/{userId}/messages/send, please modify your script as follows.
From
var params = {
method: "post",
contentType: "application/json",
headers: {
"Authorization": "Bearer " + ScriptApp.getOAuthToken()
},
muteHttpExceptions: true,
payload: JSON.stringify({
"message": {
"raw": draftBody
}
})
};
var resp = UrlFetchApp.fetch("https://gmail.googleapis.com/upload/gmail/v1/users/me/messages/send", params);
Logger.log(resp.getContentText());
To
var params = {
method: "post",
contentType: "application/json",
headers: {
"Authorization": "Bearer " + ScriptApp.getOAuthToken()
},
muteHttpExceptions: true,
payload: JSON.stringify({"raw": draftBody})
};
var resp = UrlFetchApp.fetch("https://gmail.googleapis.com/gmail/v1/users/me/messages/send", params);
Logger.log(resp.getContentText());
In this case, var draftBody = Utilities.base64Encode(message); draftBody = draftBody.replace(/\//g, '_').replace(/\+/g, '-'); can be also modified to var draftBody = Utilities.base64EncodeWebSafe(message);.
Reference:
Method: users.messages.send
So I wrote a bot with GAS for Slack and everything works fine. Now I made a copy of the bot and it starts giving out weird error "We're sorry, a server error occurred. Please wait a bit and try again." when I try to access a folder in Google drive. Since the code is exactly the same, I have no idea what the problem is.
//Create Pdf
function exportCurrentSheetAsPDF_() {
var ss = SpreadsheetApp.openById(MAIN_SPREADSHEET_ID);
var currentSheet = ss.getSheetByName(ASAKAWA_HOLIDAY_SHEET);
var blob = getAsBlob(ss.getUrl(), currentSheet);
var date = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'YYYYMMddhhmmss');
var pdfName = mergePdfName("休日", date, "浅川Only", "H");
//Export pdf to google drive 008.2 Entertainment folder
exportPdfToDrive(blob, pdfName);
return pdfName;
}
function exportPdfToDrive(blob, fileName) {
blob = blob.setName(fileName);
var folder = DriveApp.getFolderById(GOOGLE_DRIVE_FOLDER_ID); <--- This gives error
var pdfFile = folder.createFile(blob);
}
//Get spreadsheet as blob
function getAsBlob(url, sheet, range) {
var exportUrl = url.replace(/\/edit.*$/, '')
+ "/export?exportFormat=pdf"
+ "&format=pdf"
+ "&size=A4"
+ "&portrait=true"
+ "&fitw=true"
+ "&sheetnames=false"
+ "&printtitle=false"
+ "&pagenum=false"
+ "&gridlines=false"
+ "&fzr=FALSE"
+ "&gid=" + sheet.getSheetId();
var response = UrlFetchApp.fetch(exportUrl, {
headers: {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
},
})
return response.getBlob();
}
I try to automatically attach a file from my Google Drive (so ideally with the file id) in my Gmail draft created with Google Apps Script and GMail API. I use the syntax below. Can I do that easily? Creating the draft works great by the way.
Thanks! Chris
function createDraft() {
var forScope = GmailApp.getInboxUnreadCount(); // needed for auth scope
var htmlBody = 'Howzit';
var raw =
'Subject: Howzit\n' +
'To: aa#bb.cc\n' +
'Content-Type: text/html; charset=UTF-8\r\n' +
'\r\n' + htmlBody;
var draftBody = Utilities.base64Encode(raw, Utilities.Charset.UTF_8).replace(/\//g,'_').replace(/\+/g,'-');
var params = {method:"post",
contentType: "application/json",
headers: {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions:true,
payload:JSON.stringify({
"message": {
"raw": draftBody
}
})
};
var resp = UrlFetchApp.fetch("https://www.googleapis.com/gmail/v1/users/me/drafts", params);
}
How about following sample script? This is a very simple script for attaching a file to a draft. So please modify this to your environment.
In order to use this script, please enable Gmail API at API console. And please import file ID to fileId in the script.
Sample script :
function createDraft() {
var fileId = "### file id ###";
var file = DriveApp.getFileById(fileId);
var forScope = GmailApp.getInboxUnreadCount();
var htmlBody = 'Howzit';
var raw =
'Subject: Howzit\r\n' +
'To: aa#bb.cc\r\n' +
'Content-Type: multipart/mixed; boundary=##########\r\n\r\n' +
'--##########\r\n' +
'Content-Type: text/html; charset=UTF-8\r\n\r\n' + htmlBody + '\r\n' +
'--##########\r\n' +
'Content-Type: ' + file.getMimeType() + '; charset=UTF-8; name="' + file.getName() + '"\r\n' +
'Content-Disposition: attachment; filename="' + file.getName() + '"\r\n' +
'Content-Transfer-Encoding: base64\r\n\r\n' + Utilities.base64Encode(file.getBlob().getBytes()) +
'\r\n--##########\r\n';
var draftBody = Utilities.base64EncodeWebSafe(raw, Utilities.Charset.UTF_8);
var params = {
method:"post",
contentType: "application/json",
headers: {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions: true,
payload: JSON.stringify({"message": {"raw": draftBody}})
};
var resp = UrlFetchApp.fetch("https://www.googleapis.com/gmail/v1/users/me/drafts", params);
Logger.log(resp)
}
Result :
{
"id": "#####",
"message": {
"id": "#####",
"threadId": "#####",
"labelIds": [
"DRAFT"
]
}
}
Image :
I try to use google apps script to create ticket with attachments via freshdesk API.
Freshdesk have google app script sample code here: https://github.com/freshdesk/fresh-samples/tree/master/google_script , but without attachment demo.
I tried the following code, but it seems always return error by /helpdesk/tickets.json api.
how to post a attachment in google app script with UrlFetchApp right?
function createFreshdeskTicketWithAttachments() {
var API_KEY = PropertiesService.getScriptProperties().getProperty('FreshDeskApiKey')
if (!API_KEY) throw new Error('FreshDeskApiKey not found in script properties.')
var ENDPOINT = Utilities.formatString('https://%s.freshdesk.com', 'zixia')
var headers = {
'Authorization': 'Basic ' + Utilities.base64Encode(API_KEY + ':X')
, 'Content-type': 'application/json'
//'Content-type': 'multipart/form-data'
};
var response = UrlFetchApp.fetch("https://circleci.com/gh/AKAMobi/ucapp/tree/master.svg?style=svg")
var fileBlob = response.getBlob()
Logger.log("%s:%s"
, response.getResponseCode()
, fileBlob.getContentType()
)
var payload = {
helpdesk_ticket: {
description: 'TEST 4'
, subject: "TEST 4"
, email: "test#test.com"
, priority: 1
, status: 2
, attachments: { '': [ { resource: fileBlob } ] }
}
}
//Adds the extensions that are needed to post a new ticket to the end of the url
var url = ENDPOINT + '/helpdesk/tickets.json';
var options = {
'method': 'post',
'headers': headers,
'payload': JSON.stringify(payload),
// 'payload': payload,
muteHttpExceptions: true
};
var response = UrlFetchApp.fetch(url, options);
Logger.log('resp: %s, %s'
, response.getResponseCode()
, response.getContentText()
)
}
after use debug with nc:
nc -l 211.99.222.55 3333
I found payload array should write like this:
var payload = {
'helpdesk_ticket[description]': 'test jjjj'
, 'helpdesk_ticket[subject]': 'test jj'
, 'helpdesk_ticket[email]': 'test#test.com'
, 'helpdesk_ticket[attachments][][resource]': fileBlob1
, 'helpdesk_ticket[attachments][][resource]': fileBlob2
}
but fileBlob2 will not post to server, because the key of array is duplicated. I tried to change 'helpdesk_ticket[attachments][][resource]' to 'helpdesk_ticket[attachments][1][resource]' but it did not work.
so here's a workable version, which only support single attachment:
function createTicket() {
var API_KEY = PropertiesService.getScriptProperties().getProperty('FreshDeskApiKey')
if (!API_KEY) throw new Error('FreshDeskApiKey not found in script properties.')
var ENDPOINT = Utilities.formatString('https://%s.freshdesk.com', 'zixia')
var headers = {
'Authorization': 'Basic ' + Utilities.base64Encode(API_KEY + ':X')
}
var response = UrlFetchApp.fetch("https://circleci.com/gh/AKAMobi/ucapp/tree/master.svg?style=svg")
var fileBlob1 = response.getBlob()
var fileBlob2 = UrlFetchApp
.fetch("http://imgcache.qq.com/open_proj/proj_qcloud_v2/qcloud_2015/css/img/global/internet-plus.png")
.getBlob()
var payload = {
'helpdesk_ticket[description]': 'test jjjj'
, 'helpdesk_ticket[subject]': 'test jj'
, 'helpdesk_ticket[email]': 'test#test.com'
, 'helpdesk_ticket[attachments][][resource]': fileBlob1
, 'helpdesk_ticket[attachments][][resource]': fileBlob2
}
//
// for (var i=0; i<attachments.length; i++) {
// payload['helpdesk_ticket[attachments][][resource]'] = attachments[i]
// }
//
// for (var k in payload) {
// Logger.log('%s = %s', k, payload[k])
// }
var options = {
'method': 'post'
, 'headers': headers
, 'payload': payload
, muteHttpExceptions: true
}
var url = ENDPOINT + '/helpdesk/tickets.json'
// url = 'http://211.99.222.55:3333'
var response = UrlFetchApp.fetch(url, options)
Logger.log('resp: %s, %s'
, response.getResponseCode()
, response.getContentText()
)
}
UPDATE Jan 20th, 2016
I wrote a library named GasFreshdesk for freshdesk v2 api in gas, which is very easy to use(with attachments support):
var MyFreshdesk = new GasFreshdesk('https://domain.freshdesk.com', 'TOKEN')
var ticket = new MyFreshdesk.Ticket({
description:'A description'
, subject: 'A subject'
, email: 'you#example.com'
, attachments: [
Utilities.newBlob('TEST DATA').setName('test-data.dat')
, Utilities.newBlob('TEST DATA2').setName('test-data2.dat')
]
})
ticket.assign(9000658396)
ticket.note({
body: 'Hi tom, Still Angry'
, private: true
, attachments: [
Utilities.newBlob('TEST DATA').setName('test-data.dat')
, Utilities.newBlob('TEST DATA2').setName('test-data2.dat')
]
})
ticket.reply({
body: 'Hi tom, Still Angry'
, cc_emails: ['you#example.com']
, attachments: [
Utilities.newBlob('TEST DATA').setName('test-data.dat')
, Utilities.newBlob('TEST DATA2').setName('test-data2.dat')
]
})
ticket.setPriority(2)
ticket.setStatus(2)
ticket.del()
ticket.restore()
Logger.log('ticket #' + ticket.getId() + ' was set!')
GasFreshdesk Github: https://github.com/zixia/gas-freshdesk
OLD POST:
finnaly, google apps script could attach multi attachments to new ticket on freshdesk by UrlFetchApp.fetch, with a hand made 'multipart' param generator helper function by myself.
put attachments in another array payload:
var payload = [
['helpdesk_ticket[description]', 'test jjjj']
, ['helpdesk_ticket[subject]', 'test jj']
, ['helpdesk_ticket[email]', 'test#test.com']
, ['helpdesk_ticket[attachments][][resource]', fileBlob2]
, ['helpdesk_ticket[attachments][][resource]', fileBlob1]
]
use makeMultipartBody function to generate a requestBody:
var multipartBody = makeMultipartBody(payload)
full code here:
function createTicket2() {
var API_KEY = PropertiesService.getScriptProperties().getProperty('FreshDeskApiKey')
if (!API_KEY) throw new Error('FreshDeskApiKey not found in script properties.')
var ENDPOINT = Utilities.formatString('https://%s.freshdesk.com', 'zixia')
var headers = {
'Authorization': 'Basic ' + Utilities.base64Encode(API_KEY + ':X')
}
var response = UrlFetchApp.fetch("https://circleci.com/gh/AKAMobi/ucapp/tree/master.svg?style=svg")
var fileBlob1 = response.getBlob()
var fileBlob2 = UrlFetchApp
.fetch("http://imgcache.qq.com/open_proj/proj_qcloud_v2/qcloud_2015/css/img/global/internet-plus.png")
.getBlob()
var payload = [
['helpdesk_ticket[description]', 'test jjjj']
, ['helpdesk_ticket[subject]', 'test jj']
, ['helpdesk_ticket[email]', 'test#test.com']
, ['helpdesk_ticket[attachments][][resource]', fileBlob2]
, ['helpdesk_ticket[attachments][][resource]', fileBlob1]
]
var boundary = '-----CUTHEREelH7faHNSXWNi72OTh08zH29D28Zhr3Rif3oupOaDrj'
payload = makeMultipartBody(payload, boundary)
//Logger.log('payload: %s', payload)
//return
var options = {
'method': 'post'
, contentType: "multipart/form-data; boundary=" + boundary
, 'headers': headers
, 'payload': payload
, muteHttpExceptions: true
}
var url = ENDPOINT + '/helpdesk/tickets.json'
// url = 'http://211.99.222.55:3333'
var response = UrlFetchApp.fetch(url, options)
Logger.log('resp: %s, %s'
, response.getResponseCode()
, response.getContentText()
)
}
function makeMultipartBody(payload, boundary) {
var body = Utilities.newBlob('').getBytes()
Logger.log(payload)
for (var i in payload) {
var [k, v] = payload[i]
Logger.log('############ %s = %s', k, v)
if (v.toString() == 'Blob') {
// attachment
body = body.concat(
Utilities.newBlob(
'--' + boundary + '\r\n'
+ 'Content-Disposition: form-data; name="' + k + '"; filename="' + v.getName() + '"\r\n'
+ 'Content-Type: ' + v.getContentType() + '\r\n\r\n'
).getBytes())
body = body
.concat(v.getBytes())
.concat(Utilities.newBlob('\r\n').getBytes())
} else {
// string
body = body.concat(
Utilities.newBlob(
'--'+boundary+'\r\n'
+ 'Content-Disposition: form-data; name="' + k + '"\r\n\r\n'
+ v + '\r\n'
).getBytes()
)
}
}
body = body.concat(Utilities.newBlob("\r\n--" + boundary + "--\r\n").getBytes())
return body
}