From 602d66936f4f45cc763a5dca4933fedebdc399e4 Mon Sep 17 00:00:00 2001 From: soleblaze Date: Sat, 13 Aug 2016 22:23:05 -0500 Subject: [PATCH 1/3] Update fitbit plugin to support oauth2 This changes the authentication method of this gem from oauth1 to oauth2. This needs the git version of the fitbit gem. The easiest way to get this is to add the following line to the Slogger Gemfile and run bundle update: gem 'fitgem', :git => 'git://github.com/whazzmaster/fitgem' --- plugins_disabled/fitbit.rb | 145 +++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 71 deletions(-) diff --git a/plugins_disabled/fitbit.rb b/plugins_disabled/fitbit.rb index bf8b2af..1aabc83 100644 --- a/plugins_disabled/fitbit.rb +++ b/plugins_disabled/fitbit.rb @@ -2,13 +2,13 @@ Plugin: Fitbit Description: Grabs todays fitbit stats. See fitbit.com Author: Patrice Brend'amour - + Notes: 1. To run this plugin you need to install the fitgem gem first: $ sudo gem install fitgem 2. Afterwards you can aquire a valid Fitbit Consumer token: http://dev.fitbit.com if you want to use your own. A default one is provided. 3. Upon first start, the plugin will ask you to open a URL and authorize the access to your data - + =end @@ -16,10 +16,9 @@ 'fitbit_description' => [ 'Grabs todays fitbit stats. See fitbit.com', 'fitbit_unit_system defines the unit system used. Values: METRIC, US, UK. (default is US)'], - 'fitbit_consumer_key' => 'f6ec3c9a6996485bbc20e8296f25c671', - 'fitbit_consumer_secret' => '0af53444fc28434fbc9a88f3cad84764', - 'fitbit_oauth_token' => '', - 'fitbit_oauth_secret' => '', + 'fitbit_client_id' => '', + 'fitbit_client_secret' => '', + 'fitbit_refresh_token' => '', 'fitbit_unit_system' => 'US', 'fitbit_tags' => '#activities', 'fitbit_log_water' => true, @@ -38,9 +37,9 @@ class FitbitLogger < Slogger def do_log if @config.key?(self.class.name) config = @config[self.class.name] - + # Check that the user has configured the plugin - if !config.key?('fitbit_consumer_key') || config['fitbit_consumer_secret'] == "" + if !config.key?('fitbit_client_id') || config['fitbit_client_secret'] == "" @log.warn("Fitbit has not been configured, please create an application at http://dev.fitbit.com.") return end @@ -48,56 +47,62 @@ def do_log @log.warn("Fitbit has not been configured please edit your slogger_config file.") return end - + # ============================================================ # Init fitgem client - - oauth_token = config['fitbit_oauth_token'] - oauth_secret = config['fitbit_oauth_secret'] - fitbit_consumer_key = config['fitbit_consumer_key'] - fitbit_consumer_secret = config['fitbit_consumer_secret'] - - client = Fitgem::Client.new(:consumer_key => fitbit_consumer_key, :consumer_secret => fitbit_consumer_secret, :ssl => true, :unit_system => translateUnitSystem(config['fitbit_unit_system'])) + + refresh_token = config['fitbit_refresh_token'] + fitbit_client_id = config['fitbit_client_id'] + fitbit_client_secret = config['fitbit_client_secret'] + redirect_uri = 'https://localhost:3000' + token_url = 'https://api.fitbit.com/oauth2/token' + auth_url = "https://www.fitbit.com/oauth2/authorize?response_type=code&client_id=#{fitbit_client_id}&redirect_uri=#{redirect_uri}&scope=activity%20heartrate%20location%20nutrition%20profile%20settings%20sleep%20social%20weight&expires_in=604800" developMode = $options[:develop] - - + + # ============================================================ # request oauth token if needed - @log.info("#{oauth_token}") - if !oauth_token.nil? && !oauth_secret.nil? && !oauth_token.empty? && !oauth_secret.empty? - access_token = client.reconnect(oauth_token, oauth_secret) + if !refresh_token.nil? && !refresh_token.empty? + uri = URI.parse(token_url) + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true + request = Net::HTTP::Post.new(uri.request_uri) + request.basic_auth(fitbit_client_id, fitbit_client_secret) + request['Content-Type'] = 'application/x-www-form-urlencoded' + request.set_form_data( + 'grant_type' => 'refresh_token', + 'refresh_token' => refresh_token) + response = http.request(request) + response_json = JSON.parse(response.body) + config['fitbit_refresh_token'] = response_json['refresh_token'] + access_token = response_json['access_token'] else - request_token = client.request_token - token = request_token.token - secret = request_token.secret - @log.info("Fitbit requires configuration, please run from the command line and follow the prompts") - puts - puts "------------- Fitbit Configuration --------------" - puts "Slogger will now open an authorization page in your default web browser. Copy the code you receive and return here." - print "Press Enter to continue..." - gets - %x{open "http://www.fitbit.com/oauth/authorize?oauth_token=#{token}"} - print "Paste the code you received here: " - verifier = gets.strip - - begin - access_token = client.authorize(token, secret, { :oauth_verifier => verifier }) - - if developMode - @log.info("Verifier is: "+verifier) - @log.info("Token is: "+access_token.token) - @log.info("Secret is: "+access_token.secret) - end - - config['fitbit_oauth_token'] = access_token.token; - config['fitbit_oauth_secret'] = access_token.secret - @log.info("Fitbit successfully configured, run Slogger again to continue") - rescue - @log.error("Failed to authorize Fitbit. Please try again") - end - return config + @log.info('Fitbit requires configuration, please run from the command line and follow the prompts') + puts + puts 'Slogger will now open an authorization page in your default web browser. Copy the code located in the URL and return here.' + print 'Press Enter to continue...' + gets + `open '#{auth_url}'` + print 'Paste the code you received here: ' + code = gets.strip + uri = URI.parse(token_url) + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true + request = Net::HTTP::Post.new(uri.request_uri) + request.basic_auth(fitbit_client_id, fitbit_client_secret) + request['Content-Type'] = 'application/x-www-form-urlencoded' + request.set_form_data( + 'clientId' => fitbit_client_id, + 'grant_type' => 'authorization_code', + 'redirect_uri' => redirect_uri, + 'code' => code) + response = http.request(request) + response_json = JSON.parse(response.body) + refresh_token = response_json['refresh_token'] + config['fitbit_refresh_token'] = refresh_token + access_token = response_json['access_token'] end - + client = Fitgem::Client.new(:consumer_key => fitbit_client_id, :consumer_secret => fitbit_client_secret, :ssl => true, :unit_system => translateUnitSystem(config['fitbit_unit_system']), :token => access_token) # ============================================================ # iterate over the days and create entries $i = 0 @@ -105,9 +110,9 @@ def do_log until $i >= days do currentDate = Time.now - ((60 * 60 * 24) * $i) timestring = currentDate.strftime('%F') - + @log.info("Logging Fitbit summary for #{timestring}") - + activities = client.activities_on_date(timestring) summary = activities['summary'] steps = summary['steps'] @@ -117,7 +122,7 @@ def do_log veryActiveMinutes = summary['veryActiveMinutes'] caloriesOut = summary["caloriesOut"] foodsEaten = "" - + if config['fitbit_log_body_measurements'] measurements = client.body_measurements_on_date(timestring) weight = measurements['body']['weight'] @@ -128,25 +133,25 @@ def do_log water = client.water_on_date(timestring) waterSummary = water['summary'] loggedWater = waterSummary['water'] - waterUnit = client.label_for_measurement(:liquids, false) - end + waterUnit = client.label_for_measurement(:liquids, false) + end if config['fitbit_log_sleep'] sleep = client.sleep_on_date(timestring) - sleepSummary = sleep['summary'] - + sleepSummary = sleep['summary'] + hoursInBed = sleepSummary['totalTimeInBed'] / 60 minutesInBed = sleepSummary['totalTimeInBed'] - (hoursInBed * 60) timeInBed = "#{hoursInBed}h #{minutesInBed}min" - + hoursAsleep = sleepSummary['totalMinutesAsleep'] / 60 minutesAsleep = sleepSummary['totalMinutesAsleep'] - (hoursAsleep * 60) timeAsleep = "#{hoursAsleep}h #{minutesAsleep}min" end - + if config['fitbit_log_food'] foodData = client.foods_on_date(timestring) foods = foodData['foods'] - + mealList = Hash.new foodsEaten = "" totalCalories = 0 @@ -165,7 +170,7 @@ def do_log end end - + if developMode @log.info("Steps: #{steps}") @log.info("Distance: #{distance} #{distanceUnit}") @@ -179,12 +184,12 @@ def do_log @log.info("Time Asleep: #{timeAsleep}") @log.info("Foods Eaten:\n #{foodsEaten}") end - + tags = config['fitbit_tags'] || '' tags = "\n\n#{tags}\n" unless tags == '' - + output = "**Steps:** #{steps}\n**Floors:** #{floors}\n**Distance:** #{distance} #{distanceUnit}\n**Very Active Minutes:** #{veryActiveMinutes}\n**Calories Out:** #{caloriesOut}\n" - + if config['fitbit_log_body_measurements'] output += "**Weight:** #{weight} #{weightUnit}\n**BMI:** #{bmi}\n" end @@ -198,7 +203,7 @@ def do_log if config['fitbit_log_food'] output += "**Foods eaten:** #{totalCalories} calories\n#{foodsEaten}" end - + # Create a journal entry options = {} options['content'] = "## Fitbit - Summary for #{currentDate.strftime(@date_format)}\n\n#{output}#{tags}" @@ -209,7 +214,7 @@ def do_log end return config end - + def translateMeal(mealId) case mealId when 1 @@ -235,7 +240,7 @@ def translateUnitSystem(unitSystemString) return Fitgem::ApiUnitSystem.METRIC when "UK" return Fitgem::ApiUnitSystem.UK - else + else return Fitgem::ApiUnitSystem.US end end @@ -258,10 +263,8 @@ def to_s end return mealString end - + def calories @calories end end - - From ae43f7ab48c34c7576acec9915697310768a47a8 Mon Sep 17 00:00:00 2001 From: soleblaze Date: Sat, 13 Aug 2016 22:28:41 -0500 Subject: [PATCH 2/3] Update documentation for fitgem Updated the documentation for fitgem. This fitgem is no longer being supported and version 1.0.0 may not end up on rubygems.org. Right now it needs to be installed from https://github.com/whazzmaster/fitgem. --- plugins_disabled/fitbit.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins_disabled/fitbit.rb b/plugins_disabled/fitbit.rb index 1aabc83..6445682 100644 --- a/plugins_disabled/fitbit.rb +++ b/plugins_disabled/fitbit.rb @@ -4,8 +4,8 @@ Author: Patrice Brend'amour Notes: - 1. To run this plugin you need to install the fitgem gem first: - $ sudo gem install fitgem + 1. To run this plugin you need to install the git version fitgem gem first. The easiest way to do this is to add the following line to your Slogger Gemfile and run bundle update + gem 'fitgem', :git => 'git://github.com/whazzmaster/fitgem' 2. Afterwards you can aquire a valid Fitbit Consumer token: http://dev.fitbit.com if you want to use your own. A default one is provided. 3. Upon first start, the plugin will ask you to open a URL and authorize the access to your data From c4f07f9f9e94e92b084b66348eefd1aadb6d012a Mon Sep 17 00:00:00 2001 From: soleblaze Date: Sun, 21 Aug 2016 00:17:51 -0500 Subject: [PATCH 3/3] Update fitgem installation instructions --- plugins_disabled/fitbit.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins_disabled/fitbit.rb b/plugins_disabled/fitbit.rb index 6445682..b7342c7 100644 --- a/plugins_disabled/fitbit.rb +++ b/plugins_disabled/fitbit.rb @@ -4,8 +4,11 @@ Author: Patrice Brend'amour Notes: - 1. To run this plugin you need to install the git version fitgem gem first. The easiest way to do this is to add the following line to your Slogger Gemfile and run bundle update - gem 'fitgem', :git => 'git://github.com/whazzmaster/fitgem' + 1. To run this plugin you need to install the git version fitgem gem first. The easiest way to do this is to run the following commands: + git clone https://github.com/whazzmaster/fitgem + cd fitgem + rake build + sudo gem install pkg/fitgem-1.0.0.gem 2. Afterwards you can aquire a valid Fitbit Consumer token: http://dev.fitbit.com if you want to use your own. A default one is provided. 3. Upon first start, the plugin will ask you to open a URL and authorize the access to your data