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

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.

Related

Cannot update contactusgin People api using 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

How to pass a json object as a query in a get request

I am trying to pass parameters to a url get request that requires one of the parameters be a json object. I am using Google apps script. I get an invalid argument exception. The searchConditions parameter requires the json. I also need to pass some additional parameters after the query to specify the fields to return.
The example in the documentation looks like this:
https://theurl/search?searchConditions=[{ "Param1": "value", "Param2": "value"}]&fields=[ "Field1", "Field2", "etc"]
My code is as follows:
var url = "https:/theurl/search?searchConditions=";
var conditions = {
"Param1":"value",
"Param2":"value"
};
var fields = "&fields=[\'Field1\',\'Field2\',\'etc\']";
var options = {
"method":"Get",
"Accept": "application/json",
"Content-Type": "application/json",
"muteHttpExceptions" : true
};
options.headers = {"Authorization": "Basic xxxxxxxxxxxxx="};
var jsondata = UrlFetchApp.fetch(url + conditions + fields, options);
var data = JSON.parse(jsondata.getContentText())
Update: From Documentation:
Search Incidents
URI
https://trackerbeyond.phaseware.com:443/pro9/api/incident/search
HTTP Verb
GET
Request Parameters
There are two request parameters to pass in as part of the URI; searchConditions and fields.
searchConditions Parameter
This is an array of search conditions. Note that when multiple conditions are defined, all conditions must be met for the Incident to be returned.
This table shows the fields to set within each search condition.
Fieldname Description
ConditionType Possible values: Exact, BeginsWith, Contains, DateRange, IsBlank, IsNotBlank, ArchiveStatus, OpenCloseStatus.
FieldName The name of the field to search against. To get the full list of fields use the Incident Schema API call.
TableName The name of the table that the field exists on. Possible values are z_Incident, UserIncident, z_FullTextMain, Customer, UserCustomer, Contacts ,UserContacts ,CustomerContacts ,UserCustomerContacts ,CustomerProducts, CustomerSupportPackages ,IncidentParts ,IncidentParties ,DepartmentGroupingMembers (for searching on a DepartmentGrouping). If blank then z_Incident will be used.
Note: For the CreateDate and Description fields use z_FullTextMain for the TableName.
Lookup An object that contains two fields; LookupTableName and LookupFieldName.
SearchValue The value to search on.
EndingSearchValue Used when specifying ConditionType of DateRange to supply the ending date.
OpenActive Possible values: All, OpenOrActive, ClosedOrArchived. Please note that this parameter only applies when adding a search condition with ConditionType of OpenCloseStatus.
Example
In this example, the first search condition is for searching on DepartmentID equal to 1. The second condition is for searching on Priority description of "Priority 3". This is an example of using the Lookup field to search on a description for a lookup instead of the id. The third condition is for including both open and closed incidents. By default only open incidents are returned.
[
{
"ConditionType": "Exact",
"FieldName": "DepartmentID",
"TableName": "",
"Lookup": "",
"SearchValue": "1",
"EndingSearchValue": "",
"OpenActive": "OpenOrActive"
},
{
"ConditionType": "Exact",
"FieldName": "PriorityID",
"TableName": "",
"Lookup": {
"LookupTableName": "LU_Priority",
"LookupFieldName": "Description"
},
"SearchValue": "Priority 3",
"EndingSearchValue": "",
"OpenActive": "OpenOrActive"
},
{
"ConditionType": "OpenCloseStatus",
"FieldName": "",
"TableName": "",
"Lookup": "",
"SearchValue": "1",
"EndingSearchValue": "",
"OpenActive": "All"
}
]
fields Parameter
This is an array of fields to return in the result. If this parameter is left blank then a default set of fields will be returned.
Successful call made from the Test this API interface: https://trackerbeyond.phaseware.com:443/pro9/api/incident/search?searchConditions=[ { "ConditionType": "Exact", "FieldName": "StatusID", "SearchValue": "12", "OpenActive": "OpenOrActive" } ]&fields=[ "CustomerName", "CreateDate", "AgentFullName", "ClosedDateTime", "StatusID", "IncidentID", "Description" ]
Modification points:
At GET method, contentType is not required to be used.
When you want to use Accept, please include it in the request header.
Although I'm not sure about the detail of the specification of the API you want to use, from The example in the documentation looks like this: https://theurl/search?searchConditions=[{ "Param1": "value", "Param2": "value"}]&fields=[ "Field1", "Field2", "etc"] in your question, I think that in this case, how about URL encoding the values of query parameter?
When above points are reflected to your script, it becomes as follows.
Sample script:
var url = "https:/theurl/search";
var conditions = [{ "Param1": "value", "Param2": "value" }];
var fields = ["Field1", "Field2", "etc"];
var options = {
"method": "get",
"headers": {
"Authorization": "Basic xxxxxxxxxxxxx=",
"Accept": "application/json",
},
"muteHttpExceptions": true
};
var jsondata = UrlFetchApp.fetch(`${url}?searchConditions=${encodeURIComponent(JSON.stringify(conditions))}&fields=${encodeURIComponent(JSON.stringify(fields))}`, options);
var data = JSON.parse(jsondata.getContentText())
Note:
In this answer, it supposes that the URL of https:/theurl/search and the token of "Basic xxxxxxxxxxxxx=" can be used for the API you want to use. Please be careful this.
If above modification didn't resolve your issue, can you provide the official document of the API you want to use? By this, I would like to confirm it.
References:
encodeURIComponent()
fetch(url, params)

Google Drive API v3 - Import CSV in Sheet - Is it possible to disable smart conversion?

Thanks to the API, we can create an empty Sheet file and then fill it with CSV data.
In my CSV data, strings are surrounded by double quotes (").
In these data, there are barcodes like "0212345678901".
In the Sheet file, the string 0212345678901 is converted in number, so the first 0 disapear … That is not correct.
In a CSV file, if a string is surrounded by double quotes, it shoul'd remain a string …
My data are imported in 2 steps :
I create a new empty Sheet file with API. The API return the created file id.
POST => https://www.googleapis.com/drive/v3/files
body :
{
'name': 'aFilename',
'mimeType': 'application/vnd.google-apps.spreadsheet',
'parents': [idFolder]
}
I update the file (with a PATCH REST call) with the previous returned id. The content is my CSV data.
PATCH => https://www.googleapis.com/upload/drive/v3/files/${file['id']}?uploadType=media
Headers : Authorization + 'Content-Type' : 'text/csv'
So, I have two questions :
1 : Is it possible to disable the smart conversion?
2 : Or, is there a way to specify that a string must remain a string (like in Excel if we start a formula with a simple quote ')?
Sample :
"21/12/2018 17:02:06","3614950268815",1
"21/12/2018 17:04:28","0212345005507",1
"21/12/2018 17:32:10","3614950268891",1
"21/12/2018 17:32:52","3614950268099",1
"21/12/2018 17:34:36","3614950268105",1
How about these modifications? There are 3 patterns in your situation. I think that there are several answers. So please think of this as one of them.
1. Add an apostrophe
In this pattern, by adding an apostrophe to the CSV data, it can be used as a string value. Please add an apostrophe to the CSV data and update the Spreadsheet using the modified CSV file. I think that this is most simple in these 3 patterns.
"21/12/2018 17:04:28","'0212345005507",1
or
"21/12/2018 17:04:28",'0212345005507,1
2. Use a method of spreadsheets.values.update in Sheets API
In this pattern, a method of spreadsheets.values.update in Sheets API is used to the created Spreadsheet.
Endpoint:
PUT https://sheets.googleapis.com/v4/spreadsheets/### spreadsheetId ###/values/### sheetName ###?valueInputOption=RAW
Request body:
{
"values": [
[
"21/12/2018 17:02:06",
"0212345005507",
"1"
]
]
}
3. Use a method of spreadsheets.create in Sheets API
In this pattern, a method of spreadsheets.create in Sheets API is used. In this case, both creating spreadsheet and putting values can be done by one API call.
Endpoint:
POST https://sheets.googleapis.com/v4/spreadsheets
Request body:
{
"sheets": [
{
"data": [
{
"rowData": [
{
"values": [
{
"userEnteredValue": {
"stringValue": "21/12/2018 17:02:06"
}
},
{
"userEnteredValue": {
"stringValue": "0212345005507"
}
},
{
"userEnteredValue": {
"numberValue": 1
}
}
]
}
]
}
]
}
],
"properties": {
"title": "### filename of spreadsheet ###"
}
}
Note:
In the case of patterns 2 and 3, Sheets API puts the value of 0212345005507 by automatically adding an apostrophe. When you see the cell, it's '0212345005507.
References:
spreadsheets.values.update
spreadsheets.create
If these were not the result you want, I'm sorry.

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.

Google Apps Script and Big Query - tabledate.insertAll

Have been struggling with this..... Google Apps Script and the Big Query API are working well however when I try to use BigQuery.Tabledata.insertAll I keep getting an error saying 'no such field'.
When I try to run the same thing through the Google API explorer it works fine. The documentation says the command is :
BigQuery.TableData.insertAll(TableDataInsertAllRequest resource, String projectId, String datasetId, String tableId)
I have constructed the TableDataInsertAllRequest resource as per the documentation https://developers.google.com/bigquery/docs/reference/v2/tabledata/insertAll and it looks like this :
{
"kind": "bigquery#tableDataInsertAllRequest",
"rows":
[
{
"json":
{
"domain": "test",
"kind": "another test"
}
}
]
}
This matches my table schema.
When I run the command the error returned is :
{
"insertErrors": [
{
"index": 0,
"errors": [
{
"message": "no such field",
"reason": "invalid"
}
]
}
],
"kind": "bigquery#tableDataInsertAllResponse"
}
As I say the same TableDataInsertAllRequest resource works fine in the API explorer (clicking Try It on the documentation page above) it just does not work through Apps Script.
Any help gratefully received.
I've run into this too, and had somewhat better luck with this variation.
var rowObjects = [];
// Generally you'd do this next bit in a loop
var rowData = {};
rowData.domain = 'test';
rowData.kind = 'another test';
rowObjects.push(rowData);
// And at this point you'd have an array rowObjects with a bunch of objects
var response = BigQuery.Tabledata.insertAll({'rows': rowObjects}, projectId, datasetId, tableId);
Some things to note:
I don't indicate a kind -- it is implied by the call to insertAll()
I use dot notation (is that the right term?) rather than strings to stuff attributes into my "row objects"
I'm not sure which of these is the Secret Sauce. Anyways, in the end, the structure of the call looks about like this:
BigQuery.Tabledata.insertAll({'rows' : [
{
'domain' : 'test',
'kind' : 'another test'
}
]
},
projectId,
datasetId,
tableId);