"Insufficient Permissions" Error with Google Appscripts - gmail-api

I get following error when I try to create draft using google appscripts
{
"error": {
"errors": [
{
"domain": "global",
"reason": "insufficientPermissions",
"message": "Insufficient Permission"
}
],
"code": 403,
"message": "Insufficient Permission"
}
}
I enabled GMAIL api service in resource --> Advanced google services. I am using the following end point to create the draft.
https://www.googleapis.com/gmail/v1/users/me/drafts
I am not sure if I need to enable any other api to make this work. Would appreciate any help to debug this issue
I am making the api as shown below:
function createDraft(tid,Subject,Body,fromEmail,toEmail,ccEmail) {
var boundary = "ABDADASFDSBCCCADSAD" + (new Date()).getTime().toString();
SendSubject = "Subject:" + Subject
raw = SendSubject + "\r\n" +
"From: " + fromEmail + "\r\n" +
"To: " + toEmail + "\r\n" +
"Cc: " + ccEmail + "\r\n" +
"Content-Type: multipart/alternative; boundary=" + boundary + "\r\n" + "\r\n" +
"--" + boundary + "\r\n" +
"Content-Type: text/html; charset=UTF-8" + "\r\n" +
"Content-Transfer-Encoding: quoted-printable" + "\r\n" + "\r\n" +
Body + "\r\n" + "\r\n" +
"--" + boundary + "--"
//var draftBody = Utilities.base64Encode(raw, Utilities.Charset.US_ASCII).replace(/\//g,'_').replace(/\+/g,'-')
var draftBody = Utilities.base64EncodeWebSafe(raw, Utilities.Charset.UTF_8)
var params = {method:"post",
contentType: "application/json",
headers: {"Authorization": "Bearer " + ScriptApp.getOAuthToken(), "Reply-To": "naveen#skedool.it"},
muteHttpExceptions:true,
payload:JSON.stringify({
"message": {
"raw": draftBody,
"threadId" : tid
}
})
};
var resp = UrlFetchApp.fetch("https://www.googleapis.com/gmail/v1/users/me/drafts", params);
//Logger.log(resp);
return resp
}

you need to give permission to your app to get the access,
you just need to add valued in SCOPES array
private static final String[] SCOPES = { GmailScopes.GMAIL_LABELS, GmailScopes.GMAIL_COMPOSE, GmailScopes.GMAIL_INSERT, GmailScopes.GMAIL_MODIFY, GmailScopes.MAIL_GOOGLE_COM};
mCredential = GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff())
.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));

The error you are getting is related to the credentials. although you are sending a token, that token does not have access to Gmail.
In Apps script go to the menu "Resources > Advances Google Services"
There look for the Gmail service and enable it.
Then click on the link of the text "These services must also be enabled in the Google Developers Console."
It will open the Developer Console, and also there you have to enable the Gmail API.
After doing that, run your code again and it will ask for permission to access Gmail.
Now the token will have access to Gmail API.
Let me know if it didn't work for you.

Related

Google Drive API multipart upload file appears to be corrupted

public with sharing class uploadFileToGdrive {
public static void fileUploadHandler(List<ContentVersion> cvFileList) {
for (ContentVersion cvFile : cvFileList) {
system.debug('Loop');
// Get the content of the document
ContentVersion contentVersion = [SELECT Title, VersionData, FileType FROM ContentVersion WHERE ContentDocumentId = :cvFile.contentDocumentId ORDER BY CreatedDate DESC LIMIT 1];
Blob fileBody = contentVersion.VersionData;
String fileName = contentVersion.Title;
String fileType = contentVersion.FileType;
String boundary = '-------'+contentVersion.Id;
String header = 'Content-Type: multipart/related; boundary="' + boundary + '"\n' +
'Authorization: Bearer ' + [SELECT Access_Token__c FROM gDriveTokens__c][0].Access_Token__c + '\n' +
'Content-Length: ' + String.valueOf(fileBody.size()) + '\n' +
'\n';
String body = '--' + boundary + '\n' +
'Content-Type: application/json; charset=UTF-8\n' +
'\n' +
'{"name": "' + fileName + '"}\n' +
'--' + boundary + '\n' +
'Content-Type: '+MIMEHelper.getMIMEType(fileType)+'\n' +
'\n';
String requestBody = header + body + EncodingUtil.base64Encode(fileBody) + '\n--' + boundary + '--';
uploadFileToGdrive.uploadFileCallout(requestBody, boundary);
}
}
#future(callout=true)
public static void uploadFileCallout(String requestBody, String boundary) {
system.debug('Callout');
HttpRequest req = new HttpRequest();
req.setMethod('POST');
req.setEndpoint('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart');
req.setHeader('Content-Type', 'multipart/related; boundary="' + boundary + '"');
req.setheader('Authorization','Bearer '+[SELECT Access_Token__c FROM gDriveTokens__c][0].Access_Token__c);
req.setBody(requestBody);
// Send the request
Http http = new Http();
HttpResponse res = http.send(req);
system.debug(res.getBody());
}
}
I was trying to upload a file from my salesforce system to my google drive using google drive api. The files are uploading. But when I download or try to open them, it shows this message.
Drive File Error

suitescript: POST an image form the cabinet multipart/form-data

I am trying to post an image form the cabinet to an API
the API is rejected call with Content-Type": "multipart/form-data:
{
httpCode: "405",
httpMessage: "Method Not Allowed",
message: "PUT, POST require an input body.",
errorClass: "Exception"
}
the API is rejected call without Content-Type": "multipart/form-data:
{
httpCode: "400",
httpMessage: "Bad Request",
message: "JSON Input was invalid. Error Message: Syntax error",
errorClass: "InvalidArgumentException"
}
the current code is:
function ItemImageCreation(){
var itemId = 4;
var payload;
var StringUrl = "https://someURL";
var boundary = '--' + uuidv4();
var files = file.load(1056); // getting the file
var fileContents = files.getContents(); // getting the content
var decodedStr = fromBaseUTF(fileContents); // conversion to Base64
var form_data = "{\"description\": \"Test Image\",\n\"ordering\": 1\n}";
// add the data field
payload = "\n" + boundary + "\n"
+ 'Content-Disposition: form-data; name=\"data\"\n\n'
+ form_data + "\n"
+ boundary + "\n"
+ 'Content-Disposition: form-data; name=\"image\"\n'
+ 'Content-Type: image/jpeg\n\n'
+ decodedStr + "\n"
+ boundary + "--\n\n";
log.debug("payload", payload);
var Header = {"Authorization": "Bearer " + token,
"Content-Type": "multipart/form-data; boundary=" + boundary
};
try {
var response = https.post({
url: StringUrl,
body: payload,
headers: Header
});
var newSFID = JSON.parse(response.body);
log.debug("Item Image creation", newSFID);
} catch (e) {
log.error({ title: 'Failed to submit file', details: (e.message || e.toString()) + (e.getStackTrace ? (' \n \n' + e.getStackTrace().join(' \n')) : '') });
log.error('ERROR Item Image Creation', JSON.stringify(e));
}
}
using postman, the image is correctly sent:
I am using a scheduled script, do you see what is wrong or is there a way to know what is send by netsuite?
There is an answer here that covers this: In NetSuite with SuiteScript 2.0 unable to send a file with HTTP POST request with a content-type multipart/form-data
what you missing is the Content-Transfer-Encoding header and you should be getting the content as Base64 so you shouldn't need to convert from UTF16 ( I could be wrong on that but I've never needed to)

Forbidden 403 response from Google Calendar API while calling from Salesforce Using Server-to-Server

I'm trying to insert an event on Google Calendar using REST API, I'm using JWT to get the access token as I don't want user to login into google account to get token. I'd performed below steps, but still getting the error:
I've created one service account
I'm getting a Token from google to send the request
I've shared the calendar with Service Account email address as well.
Please see below code:
public class GoogleCalendarSynchronization {
public static void addEvent (){
String accessToken = GenerateJWTBearerToken.generateTokenforGoogleCalendarServices();
system.debug(accessToken);
String createEventEndPoint = 'https://www.googleapis.com/calendar/v3/calendars/primary/events/';
String createEventBody = '{' +
'"attendees": ['+
'{'+
'"email": "abc#gmail.com"'+
'},'+
'{'+
'"email": "abc#gmail.com"'+
'}'+
'],'+
'"end": {'+
'"dateTime": "2019-12-27T03:30:00-07:00"'+
'},'+
'"start": {'+
'"dateTime": "2019-12-27T03:30:00-06:00"'+
'},'+
'"summary": "Appointment has been confirmed..!!",'+
'"location": "TEST",'+
'"sendUpdates": "all"'+
'}';
//system.debug(createEventBody);
Http http = new Http();
HttpRequest httpReq = new HttpRequest();
HttpResponse HttpRes = new HttpResponse();
httpReq.setEndpoint(createEventEndPoint);
httpReq.setMethod('POST');
httpReq.setBody(createEventBody);
httpReq.setHeader('Content-Type', 'application/json');
httpReq.setHeader('Authorization','Bearer ' + accessToken);
try{
HttpRes = http.send(httpReq);
if(HttpRes.getStatusCode() == 200){
String response = HttpRes.getBody();
system.debug(response);
Map<String, Object> responseMap = (Map<String, Object>)JSON.deserializeUntyped(response);
system.debug(responseMap.get('id'));
system.debug('calendar is saved successfully..!!');
}else{
String errorMessage = 'Unexpected Error while communicating with Google Calendar API. '
+'Status '+HttpRes.getStatus()+' and Status Code '+HttpRes.getStatuscode();
system.debug(errorMessage);
}
} catch(system.Exception e){
System.debug('#### Exception Executed : '+e.getMessage() + ' ' + e.getStackTraceString() + ' ' +e.getLineNumber());
}
}
}

Access json array from navigator.camera.getPicture Cordova response

I am getting a response after I run a function that calls a cordova navigator.camera.getPicture() function. All works well and the response is below, however I can not access individual value-pairs
({"tagone" : "optimal", "datex" : "Thursday"})
I try this: r.response['tagone'] and just returns empty.
$scope.win = function (r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
$("#camLoader").hide();
$("#resultDiv").show();
$("#finalResult").append(r.response['tagone']);
//alert(r.response);
};

get 404 error by batch file upload via google-api-javascript-client library

I'm trying to upload whole folder to google drive.
I could successfully upload one file by one request.
But I met rateLimitExceed error while upload whole files.
So, I tried to use batch request.
Creating folders with batch request are successfully done.
but when I trying to upload file by batch request, it returns 404 error. ( Not Found )
Is this google drive's bug?
If so, should I do time delay for upload many files?
var boundary = '--314159265358979323846';
var delimiter = "\r\n--" + boundary + "\r\n";
var close_delim = "\r\n--" + boundary + "--";
var contentType = 'text/plain';
var metadata = {
'title': 'test1.txt',
'mimeType': contentType
};
var base64Data = btoa('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
var request = gapi.client.request({
'path': '/upload/drive/v2/files',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
'body': multipartRequestBody});
var httpBatch = gapi.client.newHttpBatch();
httpBatch.add(request, {
callback: function(resp, rawResp){
console.log(rawResp);
}
});
httpBatch.execute(function(resp, rawResp){
console.log(rawResp)
});
error is here:
{"id":"1171148984","result":false}
{"gapiRequest":{"data":{"body":"--batch_YZmy6yr9vIk=_ABqi-xumfFQ=\r\nContent-Type: application/http\r\nContent-ID: <response-1171148984>\r\n\r\nHTTP/1.1 404 Not Found\r\nContent-Type: text/html; charset=UTF-8\r\nDate: Mon, 21 Oct 2013 07:53:20 GMT\r\nExpires: Mon, 21 Oct 2013 07:53:20 GMT\r\nCache-Control: private, max-age=0\r\nContent-Length: 9\r\n\r\nNot Found\r\n--batch_YZmy6yr9vIk=_ABqi-xumfFQ=--\r\n","headers":{"pragma":"no-cache","date":"Mon, 21 Oct 2013 07:53:20 GMT","server":"GSE","content-type":"multipart/mixed; boundary=batch_YZmy6yr9vIk=_ABqi-xumfFQ=","cache-control":"no-cache, no-store, max-age=0, must-revalidate","content-length":"349","expires":"Fri, 01 Jan 1990 00:00:00 GMT"},"status":200,"statusText":"OK"}}}
Uploading cannot be batched, please run the upload requests individually.

Resources