How to set formatting with Google sheets API for python? - google-sheets-api

In theory this was answered in Remove only formatting on a cell range selection with google spreadsheet API but for the life of me I cannot get it to work.
I want to write a function that clears the formatting of a given Google Sheet. Here is what I think is the right way to do it based on the above:
def clear_sheet_formatting():
spreadsheetID = "1pQoBG0q6f0Ni6yMiC9BSIXVLGMmvBRc07pGXqMA2VtA"
global service_spreadsheets
open_connection()
body = {
"requests": [
{
"updateCells": {
"range": {
"sheetId": "Sheet1",
},
"fields": "userEnteredFormat"
}
}
]
}
func = lambda: service_spreadsheets.batchUpdate(spreadsheetId=spreadsheetID,
body=body).execute()
result = execute_query(func)
The sheet itself is very boring:
But I am getting the following error:
WARNING:root:Google API call failed with the following error, sleeping 20 seconds: Invalid value at 'requests[0].update_cells.range.sheet_id' (TYPE_INT32), "Sheet1"
What am I doing wrong? How do I make this work?

I perform a test regarding this, use this sample code to see if that helps.
I'm currently using this scopes:
SCOPES = ['https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/spreadsheets' ]
And the sample code I'm using is:
try:
service = build('sheets', 'v4', credentials=creds)
# Call the Sheets API and the sheet ID for "Sheet1"
# the ID is not the name of the sheet but a number.
call_sheet_with_format = service.spreadsheets().get(spreadsheetId=SPREADSHEET_ID).execute()
sheets_with_format = call_sheet_with_format.get('sheets', '')
sheet_id = sheets_with_format[0].get("properties", {}).get("sheetId", 0)
request_body = {
'requests': [
{
'updateCells': {
'range': {
'sheetId': sheet_id
},
'fields':'userEnteredFormat'
}
}
]
}
request = service.spreadsheets().batchUpdate(spreadsheetId=SPREADSHEET_ID, body=request_body)
response = request.execute()
except HttpError as err:
print(err)
Or you can get the sheetId directly in the Google Sheet:
And remove this part of the
sheets_with_format = call_sheet_with_format.get('sheets', '')
sheet_id = sheets_with_format[0].get("properties", {}).get("sheetId", 0)

Related

Merge PDF in ConvertAPI using Google Apps Script

I'm attempting to merge two PDF files from Google Drive via ConvertAPI with the following code. Both pdf1 and pdf2 are file objects.
function mergePDFs(pdf1,pdf2){
const formData = ""
formData['Files[0]'] = pdf1.getBlob();
formData['Files[1]'] = pdf2.getBlob();
Logger.log(formData['Files[0]']);
Logger.log(formData);
endpoint = "https://v2.convertapi.com/convert/pdf/to/merge?Secret=XXXXXXXXXXXXX&StoreFile=true"
var options = {
'method' : 'post',
'payload' : formData,
'muteHttpExceptions': true
};
Logger.log(UrlFetchApp.fetch(endpoint,options));
}
To which I receive the following error code:
{"Code":4000,"Message":"Parameter validation error.","InvalidParameters":{"Files":["Files array item count must be greater than 0."]}}
It should be noted both Logger.log() statement come up empty. It appears to me that assignments of pdf1 and pdf2 to formData['Files[index]'] are not
I have modified the following lines considerably as I'm not familiar with this syntax, but it was referenced on another Stack Overflow post.
formData['Files[0]'] = pdf1.getBlob();
formData['Files[1]'] = pdf2.getBlob();
I'm also finding that the declaration of formData is inconsequential regardless of whether it's declared as an array or as a string.
Lastly, the pertinent documentation from ConvertAPI says:
Files to be converted. Value can be URL or file content. If used in >query or multipart content parameter must be suffixed with index >e.g. Files[0], Files1, Files[2]...
The following lines from the main function are the pertinent ones to the function in question:
//lodgingRecieptId is set to a url
const receiptFile = DriveApp.getFileById(lodgingReceiptId);
...
const copyID = frontPage.makeCopy().getId();
const copyDoc = DocumentApp.openById(copyID)
copyDoc.setName("MPD | " + sheet.getLastRow());
const body = copyDoc.getBody();
//find and replace in template copy
body.replaceText("{{AMOUNT}}",amount)
body.replaceText("{{CURRENT_DATE}}",current_date)
body.replaceText("{{LOCATION}}",location)
body.replaceText("{{PURPOSE}}",purpose);
body.replaceText("{{DEPART_DATE}}",formatLeaveDate);
body.replaceText("{{RETURN_DATE}}",formatReturnDate);
body.replaceText("{RSB} ",rsb);
body.replaceText("{{DAYS}}",days);
body.replaceText("{{MPD_AMOUNT}}",mpdAmount);
const docBlob = copyDoc.getAs('application/pdf');
docBlob.setName(copyDoc.getName() + ".pdf");
const copyPdf = DriveApp.createFile(docBlob);
//merge lodging receipt and template copy ——> Save id
mergePDFs(copyPdf,receiptFile)
From your showing script and your showing official document, how about the following modification?
Modified script:
Please replace <YOUR SECRET HERE> with your secret.
function mergePDFs(pdf1, pdf2) {
var fileValues = [pdf1.getBlob(), pdf2.getBlob()].map((e, i) => ({
"Name": e.getName() || `sample${i + 1}`,
"Data": Utilities.base64Encode(e.getBytes())
}));
var data = { "Parameters": [{ "Name": "Files", "FileValues": fileValues }, { "Name": "StoreFile", "Value": true }] };
var endpoint = "https://v2.convertapi.com/convert/pdf/to/merge?Secret=<YOUR SECRET HERE>";
var options = {
'method': 'post',
'payload': JSON.stringify(data),
'contentType': "application/json",
'muteHttpExceptions': true
};
var res = UrlFetchApp.fetch(endpoint, options);
var outputPDFURL = JSON.parse(res.getContentText()).Files[0].Url;
var outputFile = UrlFetchApp.fetch(outputPDFURL).getBlob().setName("sampleOutput.pdf");
DriveApp.createFile(outputFile);
}
Note:
In this modification, it supposes that your secret is valid for using this API and pdf1 and pdf2 are the file object or the HTTPResponse object of the PDF data. Please be careful about this.
References:
Merge PDF API
fetch(url, params)

Business Central: custome api getById does not work

My problem is that I can't call my custom API for a specific itemId , however when I call the normal API it works as expected.
Currently I can successfully call the normal API for a specific item like so:
myBcServer:Port/bc/api/v1.0/companies(666e508d-9abb-ea11-bbac-000d3a492c82)/items(a5dc88b9-9abb-ea11-bbac-000d3a492c82)
But when I try to do the same with my custom API:
myBcServer:Port/bc/api/contoso/app1/v2.0/companies(666e508d-9abb-ea11-bbac-000d3a492c82)/items(a5dc88b9-9abb-ea11-bbac-000d3a492c82)
I get an error:
"error": {
"code": "BadRequest_NotFound",
"message": "Bad Request - Error in query syntax. CorrelationId: f7bc0b59-45ac-4293-9f94-108d6436272c."
}
I can successfully call both API versions at /items. Where I get a list of all the items.
The custom API page that I made looks like this:
page 50101 ItemsCustomApi
{
PageType = API;
Caption = 'API: Items';
APIPublisher = 'contoso';
APIGroup = 'app1';
APIVersion = 'v2.0';
EntityName = 'item';
EntitySetName = 'items';
SourceTable = Item;
DelayedInsert = true;
Editable = false;
layout
{
area(Content)
{
field(id; SystemId)
{
Caption = 'ID';
}
field("No"; "No.")
{
Caption = 'No.';
}
field("UnitPrice"; "Unit Price")
{
Caption = 'Unit Price';
}
field("VendorNo"; "Vendor No.")
{
Caption = 'Vendor No.';
}
}
}
}
I suspect I need to add a property to the page like CanGetById = true. However, I don't know.
BC version run in docker: mcr.microsoft.com/businesscentral/sandbox:dk
Docker version: V19.03.12
You need to set the page property ODataKeyFields to be able to select by id:
ODataKeyFields = SystemId;

Read Google Spreadsheets conditonal format information

I wish to read google spreadsheets conditional format information with script. I do it as below:
function readConditionalFormatInfo() {
var url = "https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId?fields=sheets(properties(title,sheetId),conditionalFormats)"
var response = UrlFetchApp.fetch(url)
Logger.log(response)
}
But error happen:
Request failed for https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId?fields=sheets(properties(title,sheetId),conditionalFormats) returned code 403. Truncated server response: { "error": { "code": 403, "message": "The request is missing a valid API key.", "status": "PERMISSION_DENIED" } } (use muteHttpExceptions option to examine full response) (line 214, file "Code")
Maybe I should not run REST API in GAS but I don't know how to do it in script!
Appreciate if anyone can help!
Something like below:
function readConditionalFormat() {
var sheet = SpreadsheetApp.getActive().getActiveSheet();
var rules = sheet.getConditionalFormatRules();
if (rules != null) {
for (var i=0;i<rules.length;i++) {
var rule = rules[i].getBooleanCondition()
var criteria = rule.getCriteriaType()
var value = rule.getCriteriaValues()
var bakcolor = rule.getBackground()
Logger.log(criteria+ " -> " + value + ":" + bakcolor);
}
} else {
Logger.log('Conditional Format rule null')
}
}

How to get weight data from Google fitness api?

Existing script for step count works perfectly and I can get the data from Google Fit
// see step count example at https://developers.google.com/fit/scenarios/read-daily-
step-total
function getSteps() {
var start = new Date();
start.setHours(0,0,0,0);
start.setDate(start.getDate()-1);
var end = new Date();
end.setHours(23,59,59,999);
end.setDate(end.getDate()-1);
var fitService = getFitService();
var request = {
"aggregateBy": [{
"dataTypeName": "com.google.step_count.delta",
"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"
}],
"bucketByTime": { "durationMillis": 86400000 },
"startTimeMillis": start.getTime(),
"endTimeMillis": end.getTime()
};
var response = UrlFetchApp.fetch('https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate', {
headers: {
Authorization: 'Bearer ' + fitService.getAccessToken()
},
'method' : 'post',
'contentType' : 'application/json',
'payload' : JSON.stringify(request, null, 2)
});
var json = JSON.parse(response.getContentText());
var steps = json.bucket[0].dataset[0].point[0].value[0].intVal;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Weight');
sheet.appendRow([start, steps]);
}
Now I am trying to change this code to get by changing below 2 lines
"dataTypeName": "com.google.weight.summary",
"derived:com.google.step_count.delta:com.google.android.gms:merge_weight"
But I get an error at the response statement. Get an error stating
Request failed for https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate returned code 400. Truncated server response: { "error": { "errors": [ { "domain": "global", "reason": "invalidArgument", "message": "datasource not found: derived:<?> (use muteHttpExceptions option to examine full response) (line 39, file "Code")
Could not find what to define for the FetchURL to get the weight data. I coul dnot find any examples on getting weight.
As mentioned earlier the code works perfectly fine to get step count.
Any help is appreciated.
Solved: There was a typo in my dataSourceId. It should have been as below
"dataSourceId": "derived:com.google.weight:com.google.android.gms:merge_weight"
And when getting the weight data, we need to use fpVal instead of intVal
var steps = json.bucket[0].dataset[0].point[0].value[0].fpVal;
Thanks to Robert who provided the original script on his blog and also pointed out my mistake.
Link to blog article is here
https://ithoughthecamewithyou.com/post/export-google-fit-daily-steps-to-a-google-sheet

How to pass the request object as query string in Power Query Formula Language

I am trying to pull data from an API in power bi using power query formula language.
My code is:
let
obj= "{ ""dataset"": ""mydataset"",""queries"": [ { ""type"": ""single_measurement"", ""measure"": { ""aggregator"": ""unique_count"", ""column"": ""visitor_id"" } } ], ""start"":1451638800000,""end"":1468430640000,""max_groups"":1000,""group_by"":[""extrhike""]}",
authKey = "Token js+JG/FaGiZcFZPVAsAXmN+d20000",
url = "https:// myhostaddress.cloudapp.azure.com/api/v1/query?query=obj",
GetJson = Json.Document(Web.Contents(url,[Headers = [#"Authorization"=authKey, #"Content-Type"="application/json"]]))
in
GetJson
I want to pass the data request object(obj) as a query string like following
https://myhostaddress.cloudapp.azure.com/api/v1/query?query={ "dataset": "mydataset","queries": [ { "type": "single_measurement", "measure": { "aggregator": "unique_count", "column": "visitor_id" } } ], "start":1451638800000,"end":1468430640000,"max_groups":1000,"group_by":["extrhike"]}
I am unable to pass obj as a querystring value in power query.I am getting following error
DataFormat.Error: Invalid URI: The hostname could not be parsed.
Details:
https:// myhostaddress.cloudapp.azure.com/api/v1/query?query=obj
How do I pass the request object(obj) as query string in Power Query Formula Language.
Thanks in advance
Have you tried passing in your query parameters with the Query argument of Web.Contents ?
For e.g
let
Url = "https:// myhostaddress.cloudapp.azure.com"
Request = Json.Document(Web.Contents(url,
[Headers =
[#"Authorization"=authKey,
#"Content-Type"="application/json"],
RelativePath = "/api/v1/query",
Query = [
<insert record here of your query object>
]
]
An example of the Query record might be:
Query = [#"Argument 1" = "Foo", #"Argument 2" = "Bar", limit = "1000", skip="500"]
You can read about the options here: https://msdn.microsoft.com/en-us/library/mt260892.aspx
You need to add the strings together. It should be url = "https:// myhostaddress.cloudapp.azure.com/api/v1/query?query=" & obj,.
Try to use this
It POSTs content instead of GETting query
let
obj = "{ ""dataset"": ""mydataset"",""queries"": [ { ""type"": ""single_measurement"", ""measure"": { ""aggregator"": ""unique_count"", ""column"": ""visitor_id"" } } ], ""start"":1451638800000,""end"":1468430640000,""max_groups"":1000,""group_by"":[""extrhike""]}",
authKey = "Token js+JG/FaGiZcFZPVAsAXmN+d20000",
url = "https:// myhostaddress.cloudapp.azure.com/api/v1/query",
GetJson = Json.Document(Web.Contents(url,[
Headers = [#"Authorization"=authKey, #"Content-Type"="application/json"],
Content = Text.ToBinary(obj)
]))
in
GetJson
You also may use this
It escapes obj to percent-string and appends to "query" parameter
let
obj= "{ ""dataset"": ""mydataset"",""queries"": [ { ""type"": ""single_measurement"", ""measure"": { ""aggregator"": ""unique_count"", ""column"": ""visitor_id"" } } ], ""start"":1451638800000,""end"":1468430640000,""max_groups"":1000,""group_by"":[""extrhike""]}",
authKey = "Token js+JG/FaGiZcFZPVAsAXmN+d20000",
url = "https:// myhostaddress.cloudapp.azure.com/api/v1/query?query="&Uri.EscapeDataString(obj),
GetJson = Json.Document(Web.Contents(url,[Headers = [#"Authorization"=authKey, #"Content-Type"="application/json"]]))
in
GetJson