Saving Point to a Google Fitness API (fitness.body.write) - ruby

Im trying to save a Point with float value into fitness.body.
Getting value is not a problem, while saving a new point causes 403. No permission to modify data for this source.
Im using DataSetId derived:com.google.weight:com.google.android.gms:merge_weight to find point and read value, and raw:com.google.weight:com.google.android.apps.fitness:user_input to insert data.
.
Here is a workflow using Ruby and google-api-ruby-client:
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
require 'pry'
# Initialize the client.
client = Google::APIClient.new(
:application_name => 'Example Ruby application',
:application_version => '1.0.0'
)
fitness = client.discovered_api('fitness')
# Load client secrets from your client_secrets.json.
client_secrets = Google::APIClient::ClientSecrets.load
flow = Google::APIClient::InstalledAppFlow.new(
:client_id => client_secrets.client_id,
:client_secret => client_secrets.client_secret,
:scope => ['https://www.googleapis.com/auth/fitness.body.write',
'https://www.googleapis.com/auth/fitness.activity.write',
'https://www.googleapis.com/auth/fitness.location.write']
)
client.authorization = flow.authorize
Forming my new data Point:
dataSourceId = 'raw:com.google.weight:com.google.android.apps.fitness:user_input'
startTime = (Time.now-1).to_i # 1 Second ago
endTime = (Time.now).to_i
metadata = {
dataSourceId: dataSourceId,
maxEndTimeNs: "#{startTime}000000000", # Faking nanoseconds with tailing zeros
minStartTimeNs: "#{endTime}000000000",
point: [
{
endTimeNanos: "#{endTime}000000000",
startTimeNanos: "#{startTime}000000000",
value: [
{ fpVal: 80 }
]
}
]
}
Attempting to save the point:
result = client.execute(
:api_method => fitness.users.data_sources.datasets.patch,
:body_object => metadata,
:parameters => {
'userId' => "me",
'dataSourceId' => dataSourceId,
'datasetId' => "#{Time.now.to_i-1}000000000-#{(Time.now).to_i}000000000"
}
)
And as I indicated previously im getting 403. No permission to modify data for this source
#<Google::APIClient::Schema::Fitness::V1::Dataset:0x3fe78c258f60 DATA:{"error"=>{"er
rors"=>[{"domain"=>"global", "reason"=>"forbidden", "message"=>"No permission to modif
y data for this source."}], "code"=>403, "message"=>"No permission to modify data for
this source."}}>
I believe, I selected all required permissions in the scope. I tried submitting the point to both accessible datasetid's for fitness.body.
Please let me know if im doing anything wrong here.
Thank you!

I encountered the same situation, turns out you can NOT insert data points directly into the datasource "raw:com.google.weight:com.google.android.apps.fitness:user_input". From the name, one might guess out this datasource is reserved. So the workaround is to add your own datasource, note should with dataType.name="com.google.weight", like this:
{
"dataStreamName": "xxxx.body.weight",
"dataType": {
"field": [
{
"name": "weight",
"format": "floatPoint"
}
],
"name": "com.google.weight"
},
"dataQualityStandard": [],
"application": {
"version": "1",
"name": "Foo Example App",
"detailsUrl": "http://example.com"
},
"device": {
"model": "xxxmodel",
"version": "1",
"type": "scale",
"uid": "xxx#yyy",
"manufacturer": "xxxxManufacturer"
},
"type": "derived"
}
then after the successful creation, you can use this datasource(datastream id) to insert your own data points, and then the inserted data points will also be included in the datasource "derived:com.google.weight:com.google.android.gms:merge_weight" when you do the querying with suffix "dataPointChanges".

Try adding an Authorization header:
result = client.execute(
:api_method => fitness.users.data_sources.datasets.patch,
:headers => {'Authorization' => 'Bearer YOUR_AUTH_TOKEN'},
:body_object => metadata,
:parameters => {
'userId' => "me",
'dataSourceId' => dataSourceId,
'datasetId' => "#{Time.now.to_i-1}000000000-#{(Time.now).to_i}000000000"
}
)

Related

Create a nested HASH from a API Call doesn't work properly

I am new here and i hope that I'm doing everything right.
I also searched the Forum and with Googel, but I didn't find the answer. (Or I did not notice that the solution lies before my eyes. Then I'm sorry >.< .)
i have a problem and i dont exactly know what i am doing wrong at the moment.
I make a API request and get a big JSON back. It looks somehow like that:
"apps": [
{
"title": "XX",
... many more data
},
{
"title": "XX",
... many more data
},
{
"title": "XX",
... many more data
}
... and so on
]
After that i want to create a hash with the data i need, for example it should look like:
{
"APP_0" => {"Title"=>"Name1", "ID"=>"1234", "OS"=>"os"}
"APP_1" => {"Title"=>"Name2", "ID"=>"5678", "OS"=>"os"}
}
but the values in the hash that i create with my code looks like:
"APP_1", {"Title"=>"Name2", "ID"=>"5678", "OS"=>"os"}
dont now if this is a valid hash? And after that i want to iterate through the Hash and just output the ID. But I get an error (TypeError). What am i doing wrong?
require 'json'
require 'net/http'
require 'uri'
require 'httparty'
response = HTTParty.get('https://xxx/api/2/app', {
headers: {"X-Toke" => "xyz"},
})
all_apps_parse = JSON.parse(response.body)
all_apps = Hash.new
all_apps_parse["apps"].each_with_index do |app, i|
all_apps["APP_#{i}"] = {'Title' => app["title"],
'ID' => app["id"],
'OS' => app["platform"]}
end
all_apps.each_with_index do |app, i|
app_id = app["App_#{i}"]["id"]
p app_id
end
I hope someone can understand the problem and can help me :-). Thanks in advance.
Assuming the data looks something like this:
all_apps_parse = { "apps" => [
{
"title" => "Name1",
"id" => 1234,
"platform" => "os"
},
{
"title" => "Name2",
"id" => 5678,
"platform" => "os"
},
{
"title" => "Name3",
"id" => 1111,
"platform" => "windows"
}]
}
and with a little idea of what you want to achieve, here is my solution:
all_apps = Hash.new
all_apps_parse["apps"].each_with_index do |app, i|
all_apps["APP_#{i}"] = { 'Title' => app["title"],
'ID' => app["id"],
'OS' => app["platform"] }
end
all_apps
=> {"APP_0"=>{"Title"=>"Name1", "ID"=>1234, "OS"=>"os"}, "APP_1"=>{"Title"=>"Name2", "ID"=>5678, "OS"=>"os"}, "APP_2"=>{"Title"=>"Name3", "ID"=>1111, "OS"=>"windows"}}
all_apps.each do |key, value|
puts key # => e.g. "APP_0"
puts value['ID'] # => e.g. 1234
end
# Prints
APP_0
1234
APP_1
5678
APP_2
1111

Cant get prefix query to work with elastic search for dotnet

I am playing with elastic search and made the following controller action in dotnet.
But the prefix query does not work.
[Entities(Name = "ListStreams")]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(StreamEntity[]), (int)HttpStatusCode.OK)]
public async Task<IActionResult> ListStreams(
[FromResourceProvider] ResourceProviderRouteData route)
{
var clientFactory = new ElasticServiceClientFacotry();
var client = await clientFactory.CreateClientAsync();
var documentSearchResult = await client.SearchAsync<StreamEntity>(
k => k.Index("streams")
.Routing(route.Routing)
.Query(q=>q.Prefix(c=> c.Field("id").Value(route.ResourceId)))
,
HttpContext.RequestAborted);
return Ok(documentSearchResult.Documents);
}
The following data items are in the index
[
{
"name": "swl2x33p_vjv",
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test/providers/EarthML.Streams/streams/swl2x33p_vjv",
"location": null,
"type": "EarthML.Streams/streams"
},
{
"name": "gkljqg2j_ic0",
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test/providers/EarthML.Streams/streams/gkljqg2j_ic0",
"location": null,
"type": "EarthML.Streams/streams"
}
]
and the route.ResourceId = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test/providers/EarthML.Streams"
I figured out the problem being with analyzers, and that I had not created the index myself but relied on the build in auto creation of a index.
As soon as I deleted my index and created it like the following
var descriptor = new CreateIndexDescriptor("streams")
.Mappings(ms => ms
.Map<StreamEntity>(m => m.AutoMap()
.Properties(props => props
.Keyword(s1 => s1.Name(p => p.Id).Norms(false))
.Keyword(k=>k.Name(p=>p.Name).Norms(false))
.Keyword(k=>k.Name(p=>p.Type).Norms(false))
.Keyword(k => k.Name(p => p.Location).Norms(false))
)));
then the prefix filter started working.
This also explains why it did not work with default mappings:
https://www.elastic.co/blog/strings-are-dead-long-live-strings
as the field for the keyword would be id.keyword instead now.

Uploading new products with multiple variant options

I am trying to upload products via ruby (not with rails). I have uploaded 100 + products via API, although I cannot upload a product with more than one option value. Even if I assign three option values, it will not populate the other two.
Here is the script:
require 'shopify_api'
require 'open-uri'
require 'json'
begin_time = Time.now
shop_url = "*https*(yes I know the * are their)://-YouWish-:-I'dShareNakedPics-#dev-tactical.myshopify.com/admin/products.json"
include ShopifyAPI
ShopifyAPI::Base.site ="*https*://-YouWish-:-I'dShareNakedPics-#dev-tactical.myshopify.com/admin/"
raw_product_data = JSON.parse(open('omg.json') {|f| f.read }.force_encoding('UTF-8'))
raw_product_data_size = raw_product_data.size
puts '========================================================================='
puts "#{raw_product_data_size} seconds till explosion. assistance
needed..."
puts '-------------------------------------------------------------------------'
single_product_begin_time = Time.now
# Create new product
new_product = ShopifyAPI::Product.new
new_product.title = "Variants Suck"
new_product.body_html = "So"
new_product.product_type = "Much"
new_product.vendor = "Please"
new_product.tags = "Help"
new_product.variants = [
{
"option1" => "This One Works",
"option2" => "Lost Cause",
"option3" => "/wrist",
"postion" => "1",
"price" => "10.00",
"sku" => "12345",
"inventory_management" => "shopify",
} ]
new_product.images = [
{
src: "https://cdn.shopify.com/s/files/1/0750/0067/files/Pro-Tapes.jpg?11603036243532110652"
} ]
new_product.save
creation_time = Time.now - single_product_begin_time
puts '-------------------------------------------------------------------------'
puts "Sorry About the mess babe, atleast it only took #{begin_time - Time.now} minutes."
puts '========================================================================='
I am testing this on a dev shop, but I am attempting to rebuild something previously built on magento, where I can have people convert my csv data entry to json, then array/hash the data.
Please don't link me to the (shopify)/API info. I have read it. I don't understand the formatting of it. If I were to shopify-cli console, and paste the api example in irb, it won't execute properly. I am sure I am just lacking the required knowledge of working with APIs, although if you can help me just slightly it would be much appreciated.
This node.js script adds item with variants. The difference here is that it includes a list of options on the product element. Note that if you comment out the options element then I get the same problem you are reporting in that only the first option is imported.
var https = require('https');
var cred = new Buffer(privateAppAPIKey +":"+ privateAppPassword).toString('base64');
var headers = {Authorization: "Basic "+cred, "Content-Type": "application/json"};
var options = {
host: 'kotntest1.myshopify.com',
port: 443,
path: '/admin/products.json',
method: 'POST',
headers: headers
};
// Setup the request. The options parameter is
// the object we defined above.
var req = https.request(options, function(res) {
res.setEncoding('utf-8');
var responseString = '';
res.on('data', function(data) {
responseString += data;
console.log(data);
});
res.on('end', function() {
var resultObject = JSON.parse(responseString);
});
});
req.on('error', function(e) {
// TODO: handle error.
console.log(e);
});
var product = {
product:{
title:'My First Test Product',
options : [
{name : "First"},
{name : "Second"},
{name : "Third"}
],
variants: [
{
title:'v1',
option1: 'Red',
option2: "Honda",
option3: 'Prelude'
},
{
title:'v2',
option1 :'Blue',
option2 :'Ford',
option3 :'Escort'
}
]
}
};
req.write(JSON.stringify(product));
req.end();
I used #bknights code as a reference and got my code to work in ruby. You just have to set the option names on the product level first:
new_product = ShopifyAPI::Product.new
new_product.options = [{"name" => "Size"}, {"name" => "Color"}]
Then adding variants work:
new_product.variants = [
{
"option1" => "S",
"option2" => "Black",
"position" => "1",
"price" => "10.00"
},
{
"option1" => "M",
"option2" => "Black",
"position" => "1",
"price" => "10.00"
}
]
new_product.save

What else should I send for Paypal chained payments?

I'm working on an App where a user A can buy up to 10 items from different sellers, so I need to send money to different users at the same time and I'm trying to use Paypal Chained Payments.
Right now I'm just playing around with Classic API (Adaptive payments) but I'm just wondering why I'm always getting this error:
"The fee payer PRIMARYRECEIVER can only be used if a primary receiver is specified"
I already specified a primary receiver and I'm still getting that error.
I found these examples: https://paypal-sdk-samples.herokuapp.com/adaptive_payments/pay
and I tried to do a chained payment:
This is my pay request:
require 'paypal-sdk-adaptivepayments'
#api = PayPal::SDK::AdaptivePayments::API.new
# Build request object
#pay = #api.build_pay({
:actionType => "PAY",
:cancelUrl => "https://paypal-sdk-samples.herokuapp.com/adaptive_payments/pay",
:currencyCode => "USD",
:feesPayer => "PRIMARYRECEIVER",
:ipnNotificationUrl => "https://paypal-sdk-samples.herokuapp.com/adaptive_payments/ipn_notify",
:receiverList => {
:receiver => [{
:amount => 1.0,
:email => "platfo_1255612361_per#gmail.com",
:primary => true }] },
:returnUrl => "https://paypal-sdk-samples.herokuapp.com/adaptive_payments/pay",
:sender => {
:useCredentials => true } })
# Make API call & get response
#pay_response = #api.pay(#pay)
And this is the response
{
:responseEnvelope => {
:timestamp => "2013-11-20T05:16:31-08:00",
:ack => "Failure",
:correlationId => "b002d0e27fd33",
:build => "7935900" },
:error => [{
:errorId => 580023,
:domain => "PLATFORM",
:subdomain => "Application",
:severity => "Error",
:category => "Application",
:message => "The fee payer PRIMARYRECEIVER can only be used if a primary receiver is specified",
:parameter => [{
:value => "feesPayer" },{
:value => "PRIMARYRECEIVER" }] }] }
Thanks in advance!
taking a look at your call, you're indeed specifying a primary receiver. however, for chained payment, you will have to specify a secondary receiver.
I just ran a quick test with the following paramters:
actionType = PAY
requestEnvelope.errorLanguage = en_US
cancelUrl = http://abortURL
returnUrl = http://returnURL
ipnNotificationUrl = http://ipnURL
applicationId = Test
memo = Test
currencyCode = USD
receiverList.receiver(0).email = test#test.com
receiverList.receiver(0).amount = 5.00
receiverList.receiver(0).primary = true
feesPayer = PRIMARYRECEIVER
and got the result:
responseEnvelope.timestamp=2013-11-20T05:41:56.751-08:00
responseEnvelope.ack=Failure
responseEnvelope.correlationId=b61a6b31ea2ab
responseEnvelope.build=7935900
error(0).errorId=580023
error(0).domain=PLATFORM
error(0).subdomain=Application
error(0).severity=Error
error(0).category=Application
error(0).message=The fee payer PRIMARYRECEIVER can only be used if a primary receiver is specified
error(0).parameter(0)=feesPayer
error(0).parameter(1)=PRIMARYRECEIVER
However, once I change the FeesPayer to EACHRECEIVER, I get the error message that is causing the chained payment to fail in the first place:
responseEnvelope.timestamp=2013-11-20T05:48:09.202-08:00
responseEnvelope.ack=Failure
responseEnvelope.correlationId=987210ec4d03a
responseEnvelope.build=7935900
error(0).errorId=579008
error(0).domain=PLATFORM
error(0).subdomain=Application
error(0).severity=Error
error(0).category=Application
error(0).message=You must specify only one primary receiver and at least one secondary receiver
error(0).parameter(0)=1
I hope this helps.
Please refer to the PayPal Adaptive Payments SDK available under http://paypal.github.io/#adaptive-payments for some additional examples and inspiration

How do I extract values from nested JSON?

After parsing some JSON:
data = JSON.parse(data)['info']
puts data
I get:
[
{
"title"=>"CEO",
"name"=>"George",
"columns"=>[
{
"display_name"=> "Salary",
"value"=>"3.85",
}
, {
"display_name"=> "Bonus",
"value"=>"994.19",
}
, {
"display_name"=> "Increment",
"value"=>"8.15",
}
]
}
]
columns has nested data in itself.
I want to save the data in a database or CSV file.
title, name, value_Salary, value_Bonus, value_increment
But I'm not concerned about getting display_name, so just the values of first of columns, second of columns data, etc.
Ok I tried data.map after converting to hash & hash.flatten could find a way out.. .map{|x| x['columns']}
.map {|s| s["value"]}
tried to get the values atleast separately - but couldnt...
This is a simple problem, and resolves down to a couple nested map blocks.
Here's the data retrieved from JSON, plus an extra row to demonstrate how easy it is to handle a more complex JSON response:
data = [
{
"title" => "CEO",
"name" => "George",
"columns" => [
{
"display_name" => "Salary",
"value" => "3.85",
},
{
"display_name" => "Bonus",
"value" => "994.19",
},
{
"display_name" => "Increment",
"value" => "8.15",
}
]
},
{
"title" => "CIO",
"name" => "Fred",
"columns" => [
{
"display_name" => "Salary",
"value" => "3.84",
},
{
"display_name" => "Bonus",
"value" => "994.20",
},
{
"display_name" => "Increment",
"value" => "8.15",
}
]
}
]
Here's the code:
records = data.map { |record|
title, name = record.values_at('title', 'name')
values = record['columns'].map{ |column| column['value'] }
[title, name, *values]
}
Here's the resulting data structure, an array of arrays:
records
# => [["CEO", "George", "3.85", "994.19", "8.15"],
# ["CIO", "Fred", "3.84", "994.20", "8.15"]]
Saving it into a database or CSV is left for you to figure out, but Ruby's CSV class makes it trivial to write a file, and an ORM like Sequel makes it really easy to insert the data into a database.

Resources