embulk-input-healthplanet 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a6559e9ab461422fdb84aae86853330560023ae9
4
+ data.tar.gz: b67eb584c925f946fa95a2e038a2cf82dc389062
5
+ SHA512:
6
+ metadata.gz: f3f1233856605a544b0e10f74d26510c1f6b038f868fe0ca621a2716a41ffbaa6aeabb726fb54387e5f47c1e47007ad421361f81a559ac9e06a62bd0d59bdb3f
7
+ data.tar.gz: c1c046e24a1f549b2d7185bf999814b97924946f6110640e91db0e31369389ec5547ac27091f578270ccd400588fdc82750ece5a2930072b7bed24ae5c31ca5f
@@ -0,0 +1,5 @@
1
+ *~
2
+ /pkg/
3
+ /tmp/
4
+ /.bundle/
5
+ /Gemfile.lock
@@ -0,0 +1 @@
1
+ jruby-9.0.0.0
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org/'
2
+ gemspec
@@ -0,0 +1,21 @@
1
+
2
+ MIT License
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,56 @@
1
+ # Healthplanet input plugin for Embulk
2
+
3
+ Retrieve your innerscan data through Health Planet API v1.
4
+
5
+ This plugin only supports 'innerscan' scope. Other scopes such as 'sphygmomanometer', 'pedometer' and 'smug' are not supported.
6
+
7
+ ## Overview
8
+
9
+ * **Plugin type**: input
10
+ * **Resume supported**: no
11
+ * **Cleanup supported**: no
12
+ * **Guess supported**: no
13
+
14
+ ## Install
15
+
16
+ ```
17
+ $ embulk gem install embulk-input-healthplanet
18
+ ```
19
+
20
+ ## Configuration
21
+
22
+ - **login_id**: Login ID for Health Planet website (string, required)
23
+ - **password**: Password for Health Planet website (string, required)
24
+ - **client_id**: Client ID for your client application using this plugin (string, required)
25
+ - **client_secret**: Client Secret for your client application using this plugin (string, required)
26
+ - **next_from**: Retrieve data from the time '%Y-%m-%d %H:%M:%S' (string, default: 1 year ago)
27
+
28
+ ## Example
29
+
30
+ ```yaml
31
+ in:
32
+ type: healthplanet
33
+ login_id: example_login_id
34
+ password: example_password
35
+ client_id: example.apps.healthplanet.jp
36
+ client_secret: 12345678901123-ExampleClientSecret
37
+ next_from: '2015-01-01 00:00:00'
38
+ exec: {}
39
+ out:
40
+ type: file
41
+ path_prefix: ./healthplanet/
42
+ file_ext: csv
43
+ formatter:
44
+ type: csv
45
+ default_timezone: 'Asia/Tokyo'
46
+ ```
47
+
48
+ If only new records are required, please use -o option as follows:
49
+
50
+ ```
51
+ $ embulk run config.yml -o config.yml
52
+ ```
53
+
54
+ ## References
55
+
56
+ * [Health Planet API Specification Ver. 1.0 (Japanese)](http://www.healthplanet.jp/apis/api.html)
@@ -0,0 +1,3 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task default: :build
@@ -0,0 +1,24 @@
1
+
2
+ Gem::Specification.new do |spec|
3
+ spec.name = "embulk-input-healthplanet"
4
+ spec.version = "1.0.0"
5
+ spec.authors = ["Masahiro Yoshizawa"]
6
+ spec.summary = "Healthplanet input plugin for Embulk"
7
+ spec.description = "Retrieve your innerscan data through Health Planet API v1."
8
+ spec.email = ["muziyoshiz@gmail.com"]
9
+ spec.licenses = ["MIT"]
10
+ spec.homepage = "https://github.com/muziyoshiz/embulk-input-healthplanet"
11
+
12
+ spec.files = `git ls-files`.split("\n") + Dir["classpath/*.jar"]
13
+ spec.test_files = spec.files.grep(%r{^(test|spec)/})
14
+ spec.require_paths = ["lib"]
15
+
16
+ #spec.add_dependency 'YOUR_GEM_DEPENDENCY', ['~> YOUR_GEM_DEPENDENCY_VERSION']
17
+ spec.add_development_dependency 'embulk', ['~> 0.7.10']
18
+ spec.add_development_dependency 'bundler', ['~> 1.0']
19
+ spec.add_development_dependency 'rake', ['>= 10.0']
20
+
21
+ spec.add_dependency 'faraday', ['~> 0.8.11']
22
+ spec.add_dependency 'faraday-cookie_jar', ['~> 0.0.6']
23
+ spec.add_dependency 'oga', ['~> 2.0.0']
24
+ end
@@ -0,0 +1,245 @@
1
+ require 'faraday'
2
+ require 'faraday-cookie_jar'
3
+ require 'oga'
4
+ require 'nkf'
5
+ require 'json'
6
+ require 'time'
7
+
8
+ module Embulk
9
+ module Input
10
+
11
+ class Healthplanet < InputPlugin
12
+ Plugin.register_input("healthplanet", self)
13
+
14
+ # Default redirect URI for Client Application
15
+ REDIRECT_URI = 'https://www.healthplanet.jp/success.html'
16
+
17
+ # Default scope
18
+ DEFAULT_SCOPE = 'innerscan'
19
+
20
+ # Default response type
21
+ DEFAULT_RESPONSE_TYPE = 'code'
22
+
23
+ # Default grant type
24
+ DEFAULT_GRANT_TYPE = 'authorization_code'
25
+
26
+ # All tags for innerscan
27
+ ALL_TAGS = '6021,6022,6023,6024,6025,6026,6027,6028,6029'
28
+
29
+ # Health Planet API can response only in 3 months
30
+ RESPONSE_INTERVAL = 60*60*24*30*3
31
+
32
+ # embulk-input-healthplanet retrieves data from one year ago by default
33
+ # If you need data more than one year ago, please set 'next_from' parameter
34
+ DEFAULT_FROM_TIME = 60*60*24*365
35
+
36
+ def self.transaction(config, &control)
37
+ # configuration code:
38
+ task = {
39
+ # Account for Health Planet
40
+ 'login_id' => config.param('login_id', :string),
41
+ 'password' => config.param('password', :string),
42
+ # Credential for embulk-input-healthplanet, application type "Client Application"
43
+ 'client_id' => config.param('client_id', :string),
44
+ 'client_secret' => config.param('client_secret', :string),
45
+ # This plugin retrieves new data after this time
46
+ 'next_from' => config.param('next_from', :string, :default => nil)
47
+ }
48
+
49
+ columns = [
50
+ Column.new(0, 'time', :timestamp),
51
+ Column.new(1, 'model', :string),
52
+ Column.new(2, 'weight', :double),
53
+ Column.new(3, 'body fat %', :double),
54
+ Column.new(4, 'muscle mass', :double),
55
+ Column.new(5, 'muscle score', :long),
56
+ Column.new(6, 'visceral fat level 2', :double),
57
+ Column.new(7, 'visceral fat level 1', :long),
58
+ Column.new(8, 'basal metabolic rate', :long),
59
+ Column.new(9, 'metabolic age', :long),
60
+ Column.new(10, 'estimated bone mass', :double),
61
+ # Not supported by Health Planet API Ver. 1.0
62
+ # Column.new(11, 'body water mass', :string),
63
+ ]
64
+
65
+ resume(task, columns, 1, &control)
66
+ end
67
+
68
+ def self.resume(task, columns, count, &control)
69
+ task_reports = yield(task, columns, count)
70
+
71
+ next_config_diff = task_reports.first
72
+ return next_config_diff
73
+ end
74
+
75
+ def init
76
+ login_id = task['login_id']
77
+ password = task['password']
78
+ client_id = task['client_id']
79
+ client_secret = task['client_secret']
80
+ if task['next_from']
81
+ @next_from = Time.strptime(task['next_from'], '%Y-%m-%d %H:%M:%S')
82
+ end
83
+
84
+ # Setup connection
85
+ @conn = Faraday.new(:url => 'https://www.healthplanet.jp') do |faraday|
86
+ faraday.request :url_encoded
87
+ faraday.response :logger
88
+ faraday.use :cookie_jar
89
+ faraday.adapter Faraday.default_adapter
90
+ end
91
+
92
+ # Request Authentication page: /oauth/auth
93
+ response = @conn.get do |req|
94
+ req.url '/oauth/auth'
95
+ req.params[:client_id] = client_id
96
+ req.params[:redirect_uri] = REDIRECT_URI
97
+ req.params[:scope] = DEFAULT_SCOPE
98
+ req.params[:response_type] = DEFAULT_RESPONSE_TYPE
99
+ end
100
+
101
+ # Login and set session information
102
+ response = @conn.post 'login_oauth.do', { :loginId => login_id, :passwd => password, :send => '1', :url => "https://www.healthplanet.jp/oauth/auth?client_id=#{client_id}&redirect_uri=#{REDIRECT_URI}&scope=#{DEFAULT_SCOPE}&response_type=#{DEFAULT_RESPONSE_TYPE}" }
103
+
104
+ unless response.status == 302
105
+ # TODO return error in Embulk manner
106
+ print "Login failure\n"
107
+ end
108
+
109
+ # Get auth page again with JSESSIONID
110
+ response = @conn.get do |req|
111
+ req.url '/oauth/auth'
112
+ req.params[:client_id] = client_id
113
+ req.params[:redirect_uri] = REDIRECT_URI
114
+ req.params[:scope] = DEFAULT_SCOPE
115
+ req.params[:response_type] = DEFAULT_RESPONSE_TYPE
116
+ end
117
+
118
+ # Read oauth_token
119
+ document = Oga.parse_html(NKF.nkf('-Sw', response.body))
120
+ oauth_token = document.at_xpath('//input[@name="oauth_token"]').get('value')
121
+
122
+ # Post /oauth/approval.do
123
+ response = @conn.post '/oauth/approval.do', { :approval => 'true', :oauth_token => oauth_token }
124
+
125
+ # Read code
126
+ document = Oga.parse_html(NKF.nkf('-Sw', response.body))
127
+ code = document.at_xpath('//textarea[@id="code"]').text
128
+
129
+ # Get request token
130
+ response = @conn.post do |req|
131
+ req.url '/oauth/token'
132
+ req.params[:client_id] = client_id
133
+ req.params[:client_secret] = client_secret
134
+ req.params[:redirect_uri] = REDIRECT_URI
135
+ req.params[:code] = code
136
+ req.params[:grant_type] = DEFAULT_GRANT_TYPE
137
+ end
138
+
139
+ tokens = JSON.parse(response.body)
140
+ @access_token = tokens['access_token']
141
+ end
142
+
143
+ def run
144
+ from = @next_from.nil? ? (Time.now - DEFAULT_FROM_TIME) : @next_from
145
+ last_date = nil
146
+
147
+ while from < Time.now
148
+ to = from + RESPONSE_INTERVAL
149
+ date = innerscan(from, to)
150
+ # Update last_date if any data exists
151
+ last_date = date if date
152
+
153
+ # Next request must start from 1 minute later to avoid redundant data
154
+ from = to + 60
155
+ end
156
+
157
+ page_builder.finish
158
+
159
+ task_report = {}
160
+ unless preview? or last_date.nil?
161
+ # Next request must start from 1 minute later to avoid redundant data
162
+ task_report = { :next_from => (last_date + 60).strftime('%Y-%m-%d %H:%M:%S') }
163
+ end
164
+ return task_report
165
+ end
166
+
167
+ def innerscan(from = nil, to = nil)
168
+ response = @conn.get do |req|
169
+ req.url 'status/innerscan.json'
170
+ req.params[:access_token] = @access_token
171
+ # 0: registered time, 1: measured time
172
+ req.params[:date] = 1
173
+ req.params[:from] = from.strftime('%Y%m%d%H%M%S') unless from.nil?
174
+ req.params[:to] = to.strftime('%Y%m%d%H%M%S') unless to.nil?
175
+ req.params[:tag] = ALL_TAGS
176
+ end
177
+
178
+ data = JSON.parse(response.body)
179
+
180
+ result = {}
181
+
182
+ data['data'].each do |record|
183
+ date = Time.strptime(record['date'], '%Y%m%d%H%M')
184
+
185
+ result[date] ||= {}
186
+ result[date]['model'] ||= record['model']
187
+ result[date][record['tag']] = record['keydata']
188
+ end
189
+
190
+ dates = result.keys.sort
191
+ last_date = dates.last
192
+
193
+ dates.each do |date|
194
+ page = Array.new(11)
195
+ page[0] = date
196
+ result[date].each do |key, value|
197
+ case key
198
+ when 'model'
199
+ page[1] = value
200
+ when '6021'
201
+ # weight
202
+ page[2] = value.to_f
203
+ when '6022'
204
+ # body fat %
205
+ page[3] = value.to_f
206
+ when '6023'
207
+ # muscle mass
208
+ page[4] = value.to_f
209
+ when '6024'
210
+ # muscle score
211
+ page[5] = value.to_i
212
+ when '6025'
213
+ # visceral fat level 2
214
+ page[6] = value.to_f
215
+ when '6026'
216
+ # visceral fat level 1
217
+ page[7] = value.to_i
218
+ when '6027'
219
+ # basal metabolic rate
220
+ page[8] = value.to_i
221
+ when '6028'
222
+ # metabolic age
223
+ page[9] = value.to_i
224
+ when '6029'
225
+ # estimated bone mass
226
+ page[10] = value.to_f
227
+ end
228
+ end
229
+
230
+ page_builder.add(page)
231
+ end
232
+
233
+ last_date
234
+ end
235
+
236
+ def preview?
237
+ begin
238
+ org.embulk.spi.Exec.isPreview()
239
+ rescue java.lang.NullPointerException => e
240
+ false
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: embulk-input-healthplanet
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Masahiro Yoshizawa
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: embulk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.7.10
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.7.10
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: faraday
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.8.11
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 0.8.11
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday-cookie_jar
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: 0.0.6
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 0.0.6
83
+ - !ruby/object:Gem::Dependency
84
+ name: oga
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 2.0.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 2.0.0
97
+ description: Retrieve your innerscan data through Health Planet API v1.
98
+ email:
99
+ - muziyoshiz@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - .gitignore
105
+ - .ruby-version
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - embulk-input-healthplanet.gemspec
111
+ - lib/embulk/input/healthplanet.rb
112
+ homepage: https://github.com/muziyoshiz/embulk-input-healthplanet
113
+ licenses:
114
+ - MIT
115
+ metadata: {}
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 2.0.14
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: Healthplanet input plugin for Embulk
136
+ test_files: []