Cannot update contactusgin People api using Google Apps Script - google-apps-script

I´m trying to update existing contact using People service from Google apps gs. I have a contact like this:
let contactInfo = {
"name" : "Jhon",
"lastName": "Doe",
"phone": "+1999999",
"rn": "people/c8289118840931811524",
"etag": "%EgkBAj0JPgs/Ny4aBAECBQciDDV1TzVFdXY0ckhnPQ=="
}
I created the folowing function in order to update contact more easily:
function updateContact(contactInfo){
//var updatePersonFields = "updatePersonFields=names,phoneNumbers,emailAddresses";
var bodyRequest = {
"resourceName": contactInfo.rn,
"etag": contactInfo.etag,
"names": [{
"givenName": contactInfo.name,
"familyName": contactInfo.lastName,
}],
"phoneNumbers": [{
'value': contactInfo.phone
}],
"emailAddresses": [{
'value': contactInfo.email
}]
};
People.People.updateContact(bodyRequest, contactInfo.rn);
}
However, the document guide for updateContact needs 3 parameters: Path parameters, Query Parameters and request body:
https://developers.google.com/people/api/rest/v1/people/updateContact
In order to update contact, I have to pass updatePersonfields, but it is a Query Parameter and the updateContact just only receive 2 parameters.
I know that etag and updatePersonfields is needed, as the link explain it:
https://developers.google.com/people/v1/contacts?hl=en#update_an_existing_contact
How can I add the Query Parameter updatePersonFields (in comments)?
If updatePersonField is not send it, I have the following error:
GoogleJsonResponseException: API call to people.people.updateContact failed with error:
updatePersonFields mask is required. Please specify one or more valid paths.
Valid paths are documented at
https://developers.google.com/people/api/rest/v1/people/updateContact.
Thanks you in advanced.

In your situation, please include updatePersonFields to 3rd argument of People.People.updateContact as an object.
In this case, when you use People API of Advanced Google services with the script editor of Google Apps Script, you can see the document of updateContact(resource: Peopleapi_v1.Peopleapi.V1.Schema.Person, resourceName: string, optionalArgs: Object) by the auto-completion of script editor.
So, when your script is modified, it becomes as follows.
From:
People.People.updateContact(bodyRequest, contactInfo.rn);
To:
People.People.updateContact(bodyRequest, contactInfo.rn, {updatePersonFields: "emailAddresses,names,phoneNumbers"});
Note:
When your bodyRequest is invalid value, an error occurs. Please be careful this.
Reference:
Method: people.updateContact

Related

GoogleJsonResponseException: Field name is required

I'm working with the Google Analytics API for the first time and I'm trying to create a new property. I wrote a JS function in Google App Script:
function insertProperty() {
var resource =
{
// "accountId": "177832616",
"resource":{
"name": "Test Property 7",
// "dataRetentionResetOnNewActivity": false,
"websiteUrl": "https://www.test.com"
}
}
var accountID = '177832616';
var request = Analytics.Management.Webproperties.insert(resource, accountID);
// request.execute(function (response) { console.log(property.id) });
}
This is the error the API throws:
GoogleJsonResponseException: API call to analytics.management.webproperties.insert failed with error: Field name is required. (line 56, file "Code")
The insert() method seems to take two parameters: insert(Webproperty resource, string accountId);
Since it's not recognizing the name key/value I added to resource, my guess is I haven't declared the variable as a Webproperty type and I'm not sure how to do this. I assumed Webproperty was a { } variable type, but at this point I'm not sure what to try next. Doing research online, I'm not able to find anything regarding the API's Webproperty so any context/info is helpful.
From your question, I could understand that Google Analytics API is used with Advanced Google services of Google Apps Script. In this case, resource of Analytics.Management.Webproperties.insert(resource, accountId) can directly use the request body of the method of "Web Properties: insert". I think that the reason of your error is due to this. So please modify as follows and test it again.
From:
var resource =
{
// "accountId": "177832616",
"resource":{
"name": "Test Property 7",
// "dataRetentionResetOnNewActivity": false,
"websiteUrl": "https://www.test.com"
}
}
To:
var resource = {
"name": "Test Property 7",
"websiteUrl": "https://www.test.com"
}
Note:
When accountId is not correct, an error occurs. Please be careful this.
From iansedano's comment, in this case, request of var request = Analytics.Management.Webproperties.insert(resource, accountID); directly returns the values. So you can see the value like console.log(request) and console.log(request.toString()).
Reference:
Web Properties: insert

How to prevent Google Drive API v3 from sending a notification email when giving writer permissions?

I'm able to give writer permissions using the Google Drive API (v3). This is the endpoint:
POST https://www.googleapis.com/drive/v3/files/FILE_ID/permissions"
The API reference says that I should use sendNotificationEmail: false (note, this is a boolean not a string), which is what I'm doing (in v2 this was called sendNotificationEmails).
However, after the call I still get the email from Google saying I've been invited to edit a file. 🤔
sendNotificationEmail: false works as intended, there is one small detail:
It is a request parameter that goes outside of the resource body.
I am not sure which language your are using, if e.g. Javascript, the request would be:
gapi.client.drive.permissions.create({
"fileId": "XXX",
"sendNotificationEmail": false,
"resource": {
"role": "writer",
"type": "user",
"emailAddress": "test#gmail.com"
}
})

Zapier Catch (Raw) Hook JSON parsing issue

I would like to configure sync between two different CRMs (Clevertap and Intercom) using Zapier and Webhooks. In general Clevertap sends the following JSON to webhook:
{
"targetId": 1548328164,
"profiles": [
{
"event_properties": {
"MSG-sms": true,
"MSG-push": true,
"businessRole": "EMPLOYEE",
"Mobile Number": "123123123123",
"Name": "Artem Hovtvianisa",
"Title": "Mr",
"Last Name": "Hovtvianisa",
"Gender": "M",
"Customer type": "Business Account Holder",
"MSG-email": true,
"First Name": "Artem",
"Last seen IP": "111.177.74.50",
"tz": "GMT+0200",
"International customer": "yes",
"isBusiness": true,
"Email": "xxxyyy#gmail.com",
"Identity": 15675
},
"objectId": "e32e4de3c1e84b2d9bab3707c92cd092",
"all_identities": [
"15675",
"xxxyyy#gmail.com"
],
"email": "xxxyyy#gmail.com",
"identity": "15675"
}
]
}
Zapier provides two types of catch webhook: regular and Raw.
Catch Raw Hook
When I use this type, JSON raw data will be handled OK and on the next step (Zapier JS code app) I am able to pass proper JSON data like in example above.
However when I use simple JS code to parse JSON object and get profiles[0] array value I get the following error "TypeError: Cannot read property '0' of undefined"
JS Code from Code step:
var result = JSON.parse(JSON.stringify(inputData));
console.log(result.profiles[0]);
return result;
Catch Hook
In case I use regular Catch Hook, hook parse data in some odd way, like this:
JSON.parse cannot recognize this structure.
Please advise how can I handle Webhook Zapier step in a proper way in order to get profiles[0] array item values?
Thanks in advance!
David here, from the Zapier Platform team. You're on the right track!
Catch Raw Hook is the way to go here. Your issue is that the data is coming in as a string and you're re-stringifying it before parsing it, which gets you back to where you came from. A simpler version:
JSON.stringify("asdf") // => "\"asdf\"", quotes in the string
JSON.parse("\"asdf\"") // => "asdf", the original string
"asdf".profiles // => undefined
undefined[0] // => error, cannot read property "0" of undefined
Instead, just parse it and you're good to go!
// all your variables are already in "inputData", so yours,
// also named inputData, must be referenced explicitly.
const result = JSON.parse(inputData.inputData);
return {result: result, firstProfile: result.profiles[0]};

googleapis "appProperties" field not being returned for files in node

I'm trying to get the appProperties field to be returned with my files on gdrive, but currently unable to get it working.
"googleapis": "^29.0.0"
Here's my scopes and fields:
scopes: [
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/drive.metadata.readonly"
]
fields = ["id", "name", "mimeType", "parents", "description", "modifiedTime", "appProperties"]
All of the other properties come back using drive.files.list without issue, but it won't return the appProperties field.
getFilesByQuery: function( queryString , extraFields ){
var fields = ["id", "name", "mimeType", "parents", "description", "modifiedTime", "appProperties"];
if( extraFields && extraFields.length )
fields = fields.concat( extraFields );
return drive.files.list({
'pageSize': 200,
'fields': `nextPageToken, files(${ fields.join(', ') })`,
'q': queryString
});
}
When I query directly through files/get on dev.google API, this is what I get back for that file:
{
"name": "US",
"appProperties": {
"order": "1"
}
}
Any ideas?
Thanks!
In my environment, I confirmed that appProperties can be retrieved using files.list and files.get of googleapis with v29.0.0. And I thought about the possibility of the reason for your situation. So can you confirm the following point?
When I read the document of Custom File Properties, it says as follows.
Properties are accessed using the properties (visible to all apps) and appProperties (restricted to single apps) fields on files
I investigated about this. As a sample, it supposes that {"key1": "value1"} was written to appProperties and properties by client_id_A.
For appProperties, when the appProperties is read, only the client ID which is the same with the client ID used when appProperties was written can read it.
Namely, when the access token retrieved from client_id_B is used, it cannot read appProperties written by client_id_A.
For properties, when the properties is read, it can be read by various client IDs.
Namely, even if the access token retrieved from client_id_B is used, it can read properties written by client_id_A.
From these results, appProperties and properties can be used as "Private" and "Public", respectively.
Using this, can you confirm your situation again? If you will write appProperties using node.js, you can use the following script. By this, you can confirm that you can write and read appProperties using the same client ID.
drive.files.update({
fileId: "### file ID ###",
resource: {"appProperties": {"key": "value"}},
fields: 'id,appProperties',
});
If this was not useful for your situation, I'm sorry.

Less-than sign in folder name in Google Drive API V2/V3

I have a folder with name b<bb in my Google Drive root folder. When I try to list folders where title/name contains b<bb, the Google Drive API doesn't return it, however it works when I try b<b.
Trying to send a request with query 'root' in parents and name contains 'b<bb':
https://content.googleapis.com/drive/v3/files?q=%27root%27%20in%20parents%20and%20name%20contains%20%27b%3Cbb%27
The response is:
{
"kind": "drive#fileList",
"incompleteSearch": false,
"files": []
}
Trying to send a request with query 'root' in parents and name contains 'b<b':
https://content.googleapis.com/drive/v3/files?q=%27root%27%20in%20parents%20and%20name%20contains%20%27b%3Cb%27
The response is:
{
"kind": "drive#fileList",
"incompleteSearch": false,
"files": [
{
"kind": "drive#file",
"id": "0B8nHPp6YUJPJOU80TWFqSVpkNWM",
"name": "b\u003cbb",
"mimeType": "application/vnd.google-apps.folder"
}
]
}
The same issue is also when I use Google Drive API V2. Any suggestions?
I confirmed that when Drive API v2 is used for your situation, I got the same result. But at Drive API v3, the file information can be retrieved using the query of name="b<bb". On the other hand, it couldn't be done using name contains "b<bb"
About = and contains, there is a following comment from Google.
The drive UI search for the title isn't the same thing as using the query "name = '[filename]'". If you are looking for the same behavior as the drive web UI, they should do the query: fullText contains [filename] or, if you want prefix matching, you need to use "name" s.t... name contains [filename] Additionally, "name = [filename]" is case sensitive. If you use the operator "contains" instead of "=", then it's not case sensitive.
The comment can be seen at here.
The sample script using Drive API v3 is as follows.
Sample script :
var url = 'https://www.googleapis.com/drive/v3/files?fields=files(id,name)&q=name=' + encodeURIComponent('"b<bb"')
var params = {
method: "GET",
headers: {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions: true
}
var res = UrlFetchApp.fetch(url, params).getContentText();
Logger.log(res)
Logger.log(JSON.parse(res).files[0].name)
Result :
Logger.log(res)
{
"files": [
{
"id": "### file ID ###",
"name": "b\u003cbb"
}
]
}
Logger.log(JSON.parse(res).files[0].name)
b<bb
If this information is useful for you, I'm glad.