How to get weight data from Google fitness api? - google-fit-sdk

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

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)

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 use POST to set the results of a SurveyJS survey?

Is it possible to use POST to set the results of a SurveyJS survey?
I can use GET to get the survey results, but I am struggling with setting.
Here is the code I use to GET the results:
urlToSurvey = "https://dxsurvey.com/api/MySurveys/getSurveyResults/surveyID?accessKey=myKey";
$.get(urlToSurvey, function(res) {
console.log(res);
});
I want to use SurveyJS to store students' progress in an open-source plugin (Adapt Learning), so I want to directly post the progress data to SurveyJS as I cannot run a stand-alone html in the plugin.
Any help is appreciated. Thanks!
You can check this file - https://github.com/surveyjs/surveyjs/blob/master/src/dxSurveyService.ts
Here is the code responsible for sending the result:
public sendResult(
postId: string,
result: JSON,
onSendResult: (success: boolean, response: any) => void,
clientId: string = null,
isPartialCompleted: boolean = false
) {
var xhr = new XMLHttpRequest();
xhr.open("POST", dxSurveyService.serviceUrl + "/post/");
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
var data = { postId: postId, surveyResult: JSON.stringify(result) };
if (clientId) data["clientId"] = clientId;
if (isPartialCompleted) data["isPartialCompleted"] = true;
var dataStringify: string = JSON.stringify(data);
var self = this;
xhr.onload = xhr.onerror = function() {
if (!onSendResult) return;
onSendResult(xhr.status == 200, xhr.response);
};
xhr.send(dataStringify);
}
The required params are the postId and result json. You can get your postId from the MySurveys page of the service (https://surveyjs.io/Service/MySurveys/ note that MySurveys page requires authorization).
This is a TypeScript code, but I'm sure it can easily be converted to the JS.

Dynatree init from custom json data

There is an example on the website on how to construct child nodes from custom data:
$("#tree").dynatree({
[…]
onLazyRead: function(node){
$.ajax({
url: […],
success: function(data, textStatus){
// In this sample we assume that the server returns JSON like
// { "status": "...", "result": [ {...}, {...}, ...]}
if(data.status == "ok"){
// Convert the response to a native Dynatree JavaScipt object.
var list = data.result;
res = [];
for(var i=0, l=list.length; i<l; i++){
var e = list[i];
res.push({title: "" + i + ": " + e.fcurr + "-" + e.tcurr + ":" + e.ukurs,
icon: false});
}
// PWS status OK
node.setLazyNodeStatus(DTNodeStatus_Ok);
node.addChild(res);
}else{
// Server returned an error condition: set node status accordingly
node.setLazyNodeStatus(DTNodeStatus_Error, {
tooltip: data.faultDetails,
info: data.faultString
});
}
}
});
[…]
});
But there is no mention on how to do this for the initialization of the tree. I tried the following:
initAjax: {
type: "POST",
url: "/doSomething",
data: ...
contentType: "application/json; charset=utf-8"
success: function(data, textStatus){
// In this sample we assume that the server returns JSON like
// { "status": "...", "result": [ {...}, {...}, ...]}
if(data.status == "ok"){
// Convert the response to a native Dynatree JavaScipt object.
var list = data.result;
res = [];
for(var i=0, l=list.length; i<l; i++){
var e = list[i];
res.push({title: "" + i + ": " + e.fcurr + "-" + e.tcurr + ":" + e.ukurs,
icon: false});
}
// PWS status OK
node.setLazyNodeStatus(DTNodeStatus_Ok);
node.addChild(res);
}else{
// Server returned an error condition: set node status accordingly
node.setLazyNodeStatus(DTNodeStatus_Error, {
tooltip: data.faultDetails,
info: data.faultString
});
}
}
},
But then I get an error saying success doesn't work and to use some other method, but there is no documentation on how to use the other method? Can anyone help me out here? I tried using dataFilter to filter out my json string that is being returned, but that didn't work; I tried to use onPostInit and postProcess but don't know exactly what to do since there is no documentation: Do I return the data string after its been reformated, do I return the json version of the data? do I just do data = format(data)?
Any help would be greatly appreciated.
I will be having a lot of status codes and need to do different things based on the code; such as if I have code 1 it means I need to change the class of the node to have red text; or if I return code 2 it means there was an internal error and I need to add that to the node text; etc.

How can I use a payload instead of form-data for log4javascript

I am bound to the restrictions of my webservice: It expects a json-payload!
So, doing something like
var ajaxAppender = new log4javascript.AjaxAppender("clientLogger");
var jsonLayout = new log4javascript.JsonLayout();
ajaxAppender.setLayout(jsonLayout);
log.addAppender(ajaxAppender);
won't work, as it creates two keys in the forms-collection (data and layout).
How can I, with built-in options, get a json-payload?
I've created a JsonAppender
function JsonAppender(url) {
var isSupported = true;
var successCallback = function(data, textStatus, jqXHR) { return; };
if (!url) {
isSupported = false;
}
this.setSuccessCallback = function(successCallbackParam) {
successCallback = successCallbackParam;
};
this.append = function (loggingEvent) {
if (!isSupported) {
return;
}
$.post(url, {
'logger': loggingEvent.logger.name,
'timestamp': loggingEvent.timeStampInMilliseconds,
'level': loggingEvent.level.name,
'url': window.location.href,
'message': loggingEvent.getCombinedMessages(),
'exception': loggingEvent.getThrowableStrRep()
}, successCallback, 'json');
};
}
JsonAppender.prototype = new log4javascript.Appender();
JsonAppender.prototype.toString = function() {
return 'JsonAppender';
};
log4javascript.JsonAppender = JsonAppender;
used like so
var logger = log4javascript.getLogger('clientLogger');
var jsonAppender = new JsonAppender(url);
logger.addAppender(jsonAppender);
According to log4javascript's change log, with version 1.4.5, there is no longer the need to write a custom appender, if the details sent by Log4Javascript suffice.
1.4.5 (20/2/2013)
- Changed AjaxAppender to send raw data rather than URL-encoded form data when
content-type is not "application/x-www-form-urlencoded"
https://github.com/DECK36/log4javascript/blob/master/changelog.txt
Simply adding the 'Content-Type' header to the AjaxAppender and setting it to 'application/json' is enough
ajaxAppender.addHeader("Content-Type", "application/json;charset=utf-8");
A quick test using fiddler shows that log4javascipt sends a collection of objects. Here's a sample of the payload:
[{
"logger": "myLogger",
"timestamp": 1441881152618,
"level": "DEBUG",
"url": "http://localhost:5117/Test.Html",
"message": "Testing message"
}]