module Rnnr

Constants

VERSION

Public Class Methods

auth() click to toggle source
# File lib/send.rb, line 71
def self.auth
  begin
    @config = load_config_file

    url = "https://www.mapmyfitness.com/v7.1/oauth2/uacf/authorize/"
    url << "?client_id=#{@config[:key]}"
    url << "&response_type=code"
    resp = Faraday.get url
    if resp.status == 302
      Launchy.open(resp.headers["location"])
      code = ask("Enter the code: ")

      conn = Faraday.new(:url => 'https://api.ua.com')
      resp = conn.post do |req|
        req.url "/v7.1/oauth2/uacf/access_token/"
        req.body = "grant_type=authorization_code"\
                   "&client_id=#{@config[:key]}"\
                   "&client_secret=#{@config[:secret]}"\
                   "&code=#{code}"
        req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
        req.headers['Api-Key'] = @config[:key]
      end

      if resp.status == 200
        update_config resp
        puts "SUCCESS!"
      else
        puts "FAILED."
      end
    else
      puts "FAILED. CHECK 'MAPMYRUN_KEY ENV VARIABLE.'"
    end
  rescue Interrupt => msg
    puts "Quitting..."
  rescue StandardError => msg
    puts "Error: #{msg}"
  end
end
load_config() click to toggle source
# File lib/send.rb, line 110
def self.load_config
  @config = load_config_file

  if @config[:expire] < Time.now.to_i
    conn = Faraday.new(:url => 'https://api.ua.com')
    resp = conn.post do |req|
      req.url "/v7.1/oauth2/uacf/access_token/"
      req.body = "grant_type=refresh_token"\
                 "&client_id=#{@config[:key]}"\
                 "&client_secret=#{@config[:secret]}"\
                 "&refresh_token=#{@config[:refresh]}"
      req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
      req.headers['Api-Key'] = @config[:key]
    end

    if resp.status == 200
      update_config resp
    else
      raise "Unable to retrieve access token"
    end
  end
end
load_config_file() click to toggle source
# File lib/send.rb, line 142
def self.load_config_file
  config_file = File.join(@config_dir, '.rnnr_config.yml')
  if !File.exists?(config_file)
    config = {
              :key    => ENV['MAPMYRUN_KEY'],
              :secret => ENV['MAPMYRUN_SECRET']
             }
  else
    config = YAML.load_file(config_file)
  end
  return config
end
log(msg) click to toggle source
# File lib/rnnr.rb, line 51
def self.log msg
  @log.info msg
end
plist_template() click to toggle source
# File lib/start.rb, line 17
def self.plist_template
  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"\
  "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "\
  "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"\
  "<plist version=\"1.0\">\n"\
  "<dict>\n"\
  "\t<key>Label</key>\n"\
  "\t<string>rnnr</string>\n"\
  "\t<key>ProgramArguments</key>\n"\
  "\t<array>\n"\
  "\t\t<string>#{File.expand_path('~/.rnnr.sh')}</string>\n"\
  "\t</array>\n"\
  "\t<key>StartCalendarInterval</key>\n"\
  "\t<array>\n"\
  "\t<!-- Run daily at 1:00 AM -->\n"\
  "\t\t<dict>\n"\
  "\t\t\t<key>Hour</key>\n"\
  "\t\t\t<integer>01</integer>\n"\
  "\t\t\t<key>Minute</key>\n"\
  "\t\t\t<integer>00</integer>\n"\
  "\t\t</dict>\n"\
  "\t</array>"\
  "\t<key>StandardOutPath</key>\n"\
  "\t<string>#{File.expand_path('~/.rnnr_stdout.log')}</string>\n"\
  "\t<key>StandardErrorPath</key>\n"\
  "\t<string>#{File.expand_path('~/.rnnr_stderr.log')}</string>\n"\
  "</dict>\n"\
  "</plist>"
end
run() click to toggle source
# File lib/rnnr.rb, line 13
def Rnnr.run
  program :name, 'Rnnr'
  program :version, Rnnr::VERSION
  program :description, 'Daily running reports'

  command :send do |c|
    c.syntax = 'rnnr send'
    c.description = 'Send email of year-to-date running total'
    c.option '--offset INTEGER', Integer, 'Offset for days in year'
    c.option '--email <true/false>', String, 'Send an email'
    c.option '--disp <true/false>', String, 'Print results to screen'
    c.option '--config_dir directory', String, 'Directory where your .rnnr_config.yml file lives'
    c.action do |args, options|
      options.default :offset => 0,
                      :email => 'false',
                      :disp => 'true',
                      :config_dir => "~/"
      Rnnr.send options
    end
  end

  command :auth do |c|
    c.syntax = 'rnnr auth'
    c.description = 'Authenticate the app'
    c.action do |args, options|
      Rnnr.auth
    end
  end

  command :start do |c|
    c.syntax = 'rnnr start'
    c.description = 'Create the launchd agents'
    c.action do |args, options|
      Rnnr.start
    end
  end
end
save_config_file() click to toggle source
# File lib/send.rb, line 155
def self.save_config_file
  File.open(File.join(@config_dir, '.rnnr_config.yml'), "w+") do |f|
    f.write @config.to_yaml
  end
end
send(options) click to toggle source
# File lib/send.rb, line 9
def self.send options
  begin
    @config_dir = File.expand_path(options.config_dir)
    load_config

    today = DateTime.now
    today_start = DateTime.new(today.year, today.month, today.day)
    last_sunday = today_start - today_start.wday
    month_ref = today_start - today_start.mday + 1

    conn = Faraday.new(:url => 'https://api.ua.com')
    resp = conn.get do |req|
      req.url "/v7.1/workout/"\
              "?user=#{@config[:user]}"\
              "&updated_after=#{Time.new(Time.now.year).utc.iso8601}"

      req.headers['Authorization'] = "Bearer #{@config[:auth]}"
      req.headers['Api-Key'] = @config[:key]
    end

    if resp.status == 200
      body = JSON.parse(resp.body)
      yearly_distance = 0.0
      weekly_distance = 0.0
      monthly_distance = 0.0
      body['_embedded']['workouts'].each do |workout|
        yearly_distance += workout['aggregates']['distance_total']

        date = DateTime.parse(workout['start_datetime'])
        if date > last_sunday
          weekly_distance += workout['aggregates']['distance_total']
        end

        if date > month_ref
          monthly_distance += workout['aggregates']['distance_total']
        end
      end
      yearly_distance = yearly_distance.to_miles.round(2)
      weekly_distance = weekly_distance.to_miles.round(2)
      monthly_distance = monthly_distance.to_miles.round(2)
      yearly_milesperday = (yearly_distance / (Date.today.yday - options.offset)).round(2)
      weekly_milesperday = (weekly_distance / (Date.today.wday - options.offset)).round(2)
      monthly_milesperday = (monthly_distance / (Date.today.mday - options.offset)).round(2)

      rslt_str = "Yearly: #{yearly_distance}"\
                 "\nMonthly: #{monthly_distance}"\
                 "\nWeekly: #{weekly_distance}"\
                 "\nYearly Avg Miles/Day: #{yearly_milesperday}"\
                 "\nMonthly Avg Miles/Day: #{monthly_milesperday}"\
                 "\nWeekly Avg Miles/Day: #{weekly_milesperday}"

      send_email rslt_str if options.email == 'true'
      puts rslt_str if options.disp == 'true'
    else
      raise "Unable to retrieve workout data"
    end
  rescue StandardError => msg
    log msg
    return
  end
end
send_email(content) click to toggle source
# File lib/send.rb, line 161
def self.send_email content
  to_email = @config[:email][:to]
  from_email = @config[:email][:username]
  begin
    options = { :address              => "smtp.gmail.com",
                :port                 => 587,
                :user_name            => @config[:email][:username],
                :password             => @config[:email][:password],
                :authentication       => 'plain',
                :enable_starttls_auto => true  }

    Mail.defaults do
      delivery_method :smtp, options
    end

    Mail.deliver do
       to to_email
       from from_email
       subject "Running Summary #{Date.today.strftime('%b %e, %Y')}"
       body content
    end
  rescue StandardError => msg
    puts "mail error: #{msg}"
  end
end
shell_script() click to toggle source
# File lib/start.rb, line 47
def self.shell_script
  "#!/bin/sh\n"\
  "#{`which rnnr`.chomp} send --offset 1 --email true"
end
start() click to toggle source
# File lib/start.rb, line 2
def self.start
  puts "Creating agent"
  plist = plist_template
  plist_path = File.expand_path("~/Library/LaunchAgents/com.rnnr.plist")
  shell_script_path = File.expand_path("~/.rnnr.sh")
  File.write(plist_path, plist)
  File.write(shell_script_path, shell_script)

  puts "Launching agent"
  `chmod +x #{shell_script_path}`
  `launchctl load #{plist_path}`

  puts "Done!"
end
update_config(resp) click to toggle source
# File lib/send.rb, line 133
def self.update_config resp
  body = JSON.parse(resp.body)
  @config[:refresh] = body['refresh_token']
  @config[:auth]    = body['access_token']
  @config[:user]    = body['user_id']
  @config[:expire]  = (Time.now.to_i + body['expires_in'])
  save_config_file
end