rnnr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f9e3d92fcc6de1ab8c49b90ea5c95e14def6957e
4
+ data.tar.gz: 7fc201c4dd51ae57f34c0d3ed82607f04278aac6
5
+ SHA512:
6
+ metadata.gz: f9ac1e98d75d43cf19bb2a11519888269575b607791600f0c210a964b52e3b3bf755852ed3bfbe26bcbc712bb24c675b9e047a5c4e013d1704ab3407af767274
7
+ data.tar.gz: e26c219bfb11c1bf609453123bf3e0317d99c9875b3b2dd162e83e99e1afb3894f84fc44f717dd6b132f71baa644b71a64f7c3131a17bbd2ee836e819638e2ca
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rnnr.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Greg Merritt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,24 @@
1
+ # Henchman
2
+
3
+ ## Installation
4
+
5
+ Install it yourself as:
6
+
7
+ $ gem install rnnr
8
+
9
+ ## Usage
10
+
11
+ ## Development
12
+
13
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
14
+
15
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
16
+
17
+ ## Contributing
18
+
19
+ Bug reports and pull requests are welcome on GitHub at https://github.com/gremerritt/rnnr.
20
+
21
+
22
+ ## License
23
+
24
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rnnr"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rnnr"
4
+ Rnnr.run
@@ -0,0 +1,52 @@
1
+ require "rnnr/version"
2
+ require "send"
3
+ require "start"
4
+ require "commander/import"
5
+ require "logger"
6
+
7
+ module Rnnr
8
+ @log = Logger.new(STDOUT)
9
+ @log.formatter = proc do |severity, datetime, progname, msg|
10
+ "#{datetime.strftime('%F %R')} #{msg}\n"
11
+ end
12
+
13
+ def Rnnr.run
14
+ program :name, 'Rnnr'
15
+ program :version, Rnnr::VERSION
16
+ program :description, 'Daily running reports'
17
+
18
+ command :send do |c|
19
+ c.syntax = 'rnnr send'
20
+ c.description = 'Send email of year-to-date running total'
21
+ c.option '--offset INTEGER', Integer, 'Offset for days in year'
22
+ c.option '--email <true/false>', String, 'Send an email'
23
+ c.option '--config_dir directory', String, 'Directory where your .rnnr_config.yml file lives'
24
+ c.action do |args, options|
25
+ options.default :offset => 0,
26
+ :email => 'false',
27
+ :config_dir => "~/"
28
+ Rnnr.send options
29
+ end
30
+ end
31
+
32
+ command :auth do |c|
33
+ c.syntax = 'rnnr auth'
34
+ c.description = 'Authenticate the app'
35
+ c.action do |args, options|
36
+ Rnnr.auth
37
+ end
38
+ end
39
+
40
+ command :start do |c|
41
+ c.syntax = 'rnnr start'
42
+ c.description = 'Create the launchd agents'
43
+ c.action do |args, options|
44
+ Rnnr.start
45
+ end
46
+ end
47
+ end
48
+
49
+ def self.log msg
50
+ @log.info msg
51
+ end
52
+ end
@@ -0,0 +1,3 @@
1
+ module Rnnr
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,183 @@
1
+ require 'faraday'
2
+ require 'launchy'
3
+ require 'yaml'
4
+ require 'json'
5
+ require 'time'
6
+ require 'mail'
7
+
8
+ module Rnnr
9
+ def self.send options
10
+ begin
11
+ @config_dir = File.expand_path(options.config_dir)
12
+ load_config
13
+
14
+ today = DateTime.now
15
+ today_start = DateTime.new(today.year, today.month, today.day)
16
+ last_sunday = today_start - today_start.wday
17
+
18
+ conn = Faraday.new(:url => 'https://api.ua.com')
19
+ resp = conn.get do |req|
20
+ req.url "/v7.1/workout/"\
21
+ "?user=#{@config[:user]}"\
22
+ "&updated_after=#{Time.new(Time.now.year).utc.iso8601}"
23
+
24
+ req.headers['Authorization'] = "Bearer #{@config[:auth]}"
25
+ req.headers['Api-Key'] = @config[:key]
26
+ end
27
+
28
+ if resp.status == 200
29
+ body = JSON.parse(resp.body)
30
+ yearly_distance = 0.0
31
+ weekly_distance = 0.0
32
+ body['_embedded']['workouts'].each do |workout|
33
+ yearly_distance += workout['aggregates']['distance_total']
34
+
35
+ date = DateTime.parse(workout['start_datetime'])
36
+ if date > last_sunday
37
+ weekly_distance += workout['aggregates']['distance_total']
38
+ end
39
+ end
40
+ yearly_distance = yearly_distance.to_miles.round(2)
41
+ weekly_distance = weekly_distance.to_miles.round(2)
42
+ milesperday = (yearly_distance / (Date.today.yday - options.offset)).round(2)
43
+
44
+ rslt_str = "Yearly: #{yearly_distance}"\
45
+ "\nWeekly: #{weekly_distance}"\
46
+ "\nMiles/Day: #{milesperday}"\
47
+
48
+ if options.email == 'true'
49
+ send_email rslt_str
50
+ else
51
+ puts rslt_str
52
+ end
53
+ else
54
+ raise "Unable to retrieve workout data"
55
+ end
56
+ rescue StandardError => msg
57
+ log msg
58
+ return
59
+ end
60
+ end
61
+
62
+ def self.auth
63
+ begin
64
+ @config = load_config_file
65
+
66
+ url = "https://www.mapmyfitness.com/v7.1/oauth2/uacf/authorize/"
67
+ url << "?client_id=#{@config[:key]}"
68
+ url << "&response_type=code"
69
+ resp = Faraday.get url
70
+ if resp.status == 302
71
+ Launchy.open(resp.headers["location"])
72
+ code = ask("Enter the code: ")
73
+
74
+ conn = Faraday.new(:url => 'https://api.ua.com')
75
+ resp = conn.post do |req|
76
+ req.url "/v7.1/oauth2/uacf/access_token/"
77
+ req.body = "grant_type=authorization_code"\
78
+ "&client_id=#{@config[:key]}"\
79
+ "&client_secret=#{@config[:secret]}"\
80
+ "&code=#{code}"
81
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
82
+ req.headers['Api-Key'] = @config[:key]
83
+ end
84
+
85
+ if resp.status == 200
86
+ update_config resp
87
+ puts "SUCCESS!"
88
+ else
89
+ puts "FAILED."
90
+ end
91
+ else
92
+ puts "FAILED. CHECK 'MAPMYRUN_KEY ENV VARIABLE.'"
93
+ end
94
+ rescue Interrupt => msg
95
+ puts "Quitting..."
96
+ rescue StandardError => msg
97
+ puts "Error: #{msg}"
98
+ end
99
+ end
100
+
101
+ def self.load_config
102
+ @config = load_config_file
103
+
104
+ if @config[:expire] < Time.now.to_i
105
+ conn = Faraday.new(:url => 'https://api.ua.com')
106
+ resp = conn.post do |req|
107
+ req.url "/v7.1/oauth2/uacf/access_token/"
108
+ req.body = "grant_type=refresh_token"\
109
+ "&client_id=#{@config[:key]}"\
110
+ "&client_secret=#{@config[:secret]}"\
111
+ "&refresh_token=#{@config[:refresh]}"
112
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
113
+ req.headers['Api-Key'] = @config[:key]
114
+ end
115
+
116
+ if resp.status == 200
117
+ update_config resp
118
+ else
119
+ raise "Unable to retrieve access token"
120
+ end
121
+ end
122
+ end
123
+
124
+ def self.update_config resp
125
+ body = JSON.parse(resp.body)
126
+ @config[:refresh] = body['refresh_token']
127
+ @config[:auth] = body['access_token']
128
+ @config[:user] = body['user_id']
129
+ @config[:expire] = (Time.now.to_i + body['expires_in'])
130
+ save_config_file
131
+ end
132
+
133
+ def self.load_config_file
134
+ config_file = File.join(@config_dir, '.rnnr_config.yml')
135
+ if !File.exists?(config_file)
136
+ config = {
137
+ :key => ENV['MAPMYRUN_KEY'],
138
+ :secret => ENV['MAPMYRUN_SECRET']
139
+ }
140
+ else
141
+ config = YAML.load_file(config_file)
142
+ end
143
+ return config
144
+ end
145
+
146
+ def self.save_config_file
147
+ File.open(File.join(@config_dir, '.rnnr_config.yml'), "w+") do |f|
148
+ f.write @config.to_yaml
149
+ end
150
+ end
151
+
152
+ def self.send_email content
153
+ to_email = @config[:email][:to]
154
+ from_email = @config[:email][:username]
155
+ begin
156
+ options = { :address => "smtp.gmail.com",
157
+ :port => 587,
158
+ :user_name => @config[:email][:username],
159
+ :password => @config[:email][:password],
160
+ :authentication => 'plain',
161
+ :enable_starttls_auto => true }
162
+
163
+ Mail.defaults do
164
+ delivery_method :smtp, options
165
+ end
166
+
167
+ Mail.deliver do
168
+ to to_email
169
+ from from_email
170
+ subject "Running Summary #{Date.today.strftime('%b %e, %Y')}"
171
+ body content
172
+ end
173
+ rescue StandardError => msg
174
+ puts "mail error: #{msg}"
175
+ end
176
+ end
177
+ end
178
+
179
+ class Float
180
+ def to_miles
181
+ self * 0.000621371
182
+ end
183
+ end
@@ -0,0 +1,51 @@
1
+ module Rnnr
2
+ def self.start
3
+ puts "Creating agent"
4
+ plist = plist_template
5
+ plist_path = File.expand_path("~/Library/LaunchAgents/com.rnnr.plist")
6
+ shell_script_path = File.expand_path("~/.rnnr.sh")
7
+ File.write(plist_path, plist)
8
+ File.write(shell_script_path, shell_script)
9
+
10
+ puts "Launching agent"
11
+ `chmod +x #{shell_script_path}`
12
+ `launchctl load #{plist_path}`
13
+
14
+ puts "Done!"
15
+ end
16
+
17
+ def self.plist_template
18
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"\
19
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "\
20
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"\
21
+ "<plist version=\"1.0\">\n"\
22
+ "<dict>\n"\
23
+ "\t<key>Label</key>\n"\
24
+ "\t<string>rnnr</string>\n"\
25
+ "\t<key>ProgramArguments</key>\n"\
26
+ "\t<array>\n"\
27
+ "\t\t<string>#{File.expand_path('~/.rnnr.sh')}</string>\n"\
28
+ "\t</array>\n"\
29
+ "\t<key>StartCalendarInterval</key>\n"\
30
+ "\t<array>\n"\
31
+ "\t<!-- Run daily at 1:00 AM -->\n"\
32
+ "\t\t<dict>\n"\
33
+ "\t\t\t<key>Hour</key>\n"\
34
+ "\t\t\t<integer>01</integer>\n"\
35
+ "\t\t\t<key>Minute</key>\n"\
36
+ "\t\t\t<integer>00</integer>\n"\
37
+ "\t\t</dict>\n"\
38
+ "\t</array>"\
39
+ "\t<key>StandardOutPath</key>\n"\
40
+ "\t<string>#{File.expand_path('~/.rnnr_stdout.log')}</string>\n"\
41
+ "\t<key>StandardErrorPath</key>\n"\
42
+ "\t<string>#{File.expand_path('~/.rnnr_stderr.log')}</string>\n"\
43
+ "</dict>\n"\
44
+ "</plist>"
45
+ end
46
+
47
+ def self.shell_script
48
+ "#!/bin/sh\n"\
49
+ "#{`which rnnr`.chomp} send --offset 1 --email true"
50
+ end
51
+ end
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rnnr/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rnnr"
8
+ spec.version = Rnnr::VERSION
9
+ spec.authors = ["Greg Merritt"]
10
+ spec.email = ["gremerritt@gmail.com"]
11
+
12
+ spec.summary = %q{Daily running reports}
13
+ spec.description = %q{Daily running reports. Send daily year-to-date running totals}
14
+ spec.homepage = "https://www.github.com/gremerritt/rnnr"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org/"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|pkg)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency "commander", "~> 4.4"
31
+ spec.add_dependency "faraday", "~> 0.11"
32
+ spec.add_dependency "launchy", "~> 2.4"
33
+ spec.add_development_dependency "bundler", "~> 1.12"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "rspec", "~> 3.0"
36
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rnnr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Greg Merritt
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-01-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: commander
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.11'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.11'
41
+ - !ruby/object:Gem::Dependency
42
+ name: launchy
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.4'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ description: Daily running reports. Send daily year-to-date running totals
98
+ email:
99
+ - gremerritt@gmail.com
100
+ executables:
101
+ - rnnr
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - bin/console
111
+ - bin/setup
112
+ - exe/rnnr
113
+ - lib/rnnr.rb
114
+ - lib/rnnr/version.rb
115
+ - lib/send.rb
116
+ - lib/start.rb
117
+ - rnnr.gemspec
118
+ homepage: https://www.github.com/gremerritt/rnnr
119
+ licenses:
120
+ - MIT
121
+ metadata:
122
+ allowed_push_host: https://rubygems.org/
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.5.1
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Daily running reports
143
+ test_files: []