todaysplan 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0f11f6637035fa0e823a298286a69726d6906256
4
- data.tar.gz: a7fccf886bd13b23f2194b558cf7172e259a82fe
3
+ metadata.gz: 0f15a61fe0e7c44b9184e3eec252f2527f7f270d
4
+ data.tar.gz: 702570cbc3b9e829c37a90d9cdc3e3e5f95ab5a1
5
5
  SHA512:
6
- metadata.gz: 35d5eb9895c1c0b3a52bace60d768a6369e00eab837417887dc54f0c858b07eed7a54bf8d887e26b525c7a3ad5c12df902593e286702a97f70034563b4b3cb2a
7
- data.tar.gz: d4ee841df274b6db233af9cef40b40c8d15ed388d9ba7ec816b7032c87648a2ca322e5cbfde7ea7cfd8d67e8223d70eee0ce4542761d8a9b6162f37ef51a324e
6
+ metadata.gz: 21b04b33a7f90c9b8a556f14494f12ff2ea0b51d93e58b061042aede1982fa8bea40d96788ade9f80c270f1f72ffeeaae299f598f48b1cf8c70a7f0ccf93e509
7
+ data.tar.gz: bf26d14ee97f05b2991941b5fca413c12ea878b200bdf164a199eb9bb6add6bbab4cc9ee0278ffa60848d4d114429ea89f68a9c110de4b00485b52ca9f9c3ac4
data/README.md CHANGED
@@ -10,7 +10,7 @@ Pull Request to include additional calls.
10
10
  Add the gem to your app
11
11
 
12
12
  ```ruby
13
- gem 'todaysplan-ruby'
13
+ gem 'todaysplan-ruby', require: 'todays_plan
14
14
  ```
15
15
 
16
16
  ### Usage
@@ -40,4 +40,3 @@ timeout: 120
40
40
  logger: 'stdout'
41
41
  debug: true
42
42
  ```
43
-
@@ -11,6 +11,7 @@ module TodaysPlan
11
11
  attr_reader :coach
12
12
  attr_reader :email
13
13
  attr_reader :dob
14
+ attr_reader :country
14
15
 
15
16
 
16
17
  def initialize(fields)
@@ -18,16 +19,15 @@ module TodaysPlan
18
19
  @name = fields['_name']
19
20
  @first_name = fields['firstname']
20
21
  @last_name = fields['lastname']
21
- @timezone = fields['timezone']
22
+ @timezone =fields['timezone']
22
23
  @coach = fields['coach']["id"].to_i if fields.has_key?("coach")
23
24
  @email = fields['email']
24
25
  @dob = Time.at(fields['dob'].to_i/1000)
26
+ @country = fields['country']
25
27
  end
26
28
 
27
29
  # Find a single athlete
28
- # +client+:: the authenticated client
29
30
  # +id+:: the athlete id
30
- # +options+:: has of options
31
31
  def self.find(id)
32
32
  all().find{|a| a.id==id}
33
33
  end
@@ -39,5 +39,40 @@ module TodaysPlan
39
39
  new(data)
40
40
  end
41
41
  end
42
+
43
+ # Create new Athlete\
44
+ # options
45
+ # user_email - email address of new user
46
+ # firstname - first name of new user
47
+ # lastname - last name of new user
48
+ # password - password of new user
49
+ # coach_email - coach email in todaysplan
50
+ def self.create(options, client = nil)
51
+
52
+ #preregister
53
+ response = RestClient.get("#{TodaysPlan.endpoint}/auth/preregister")
54
+
55
+ # register the user
56
+ payload = {email: options[:user_email], firstname: options[:firstname],
57
+ lastname: options[:lastname], password: options[:password]}
58
+ response = RestClient.post("#{TodaysPlan.endpoint}/auth/register",payload.to_json,
59
+ { content_type: :json})
60
+ response.body
61
+ athlete = new(JSON.parse(response.body))
62
+ # user invites coach
63
+ user_client = TodaysPlan::Client.new(options[:user_email], options[:password])
64
+ invite={"email"=>options[:coach_email],"state"=> "pending_coach",
65
+ "relationship"=> "coach"}.to_json
66
+ response = Connector.new('/users/delegates/invite', user_client).post(invite)
67
+
68
+ # find invitation and accept
69
+ Connector.new('/users/delegates/search/0/100', client).
70
+ post({ "state"=> "pending_coach"}.to_json)["results"].each do |result|
71
+ id = result["id"]
72
+ Connector.new("/users/delegates/invite/accept/#{id}", client).get()
73
+
74
+ end
75
+ athlete
76
+ end
42
77
  end
43
78
  end
@@ -12,28 +12,60 @@ module TodaysPlan
12
12
  #
13
13
  # Returns the parsed JSON response body.
14
14
  def get()
15
- @response = RestClient::Request.execute(method: :get, url: @uri,
16
- timeout: @timeout,
17
- headers: {:Authorization => "Bearer #{@client.token}",accept: :json} )
18
- puts "#{@response.body}" if TodaysPlan.debug
19
- @body = JSON.parse(@response.body)
15
+ options={
16
+ method: :get,
17
+ headers:{ accept: :json}
18
+ }
19
+ run(options)
20
20
  end
21
21
 
22
22
  # Internal: Run GET request.
23
23
  #
24
24
  # Returns the parsed JSON response body.
25
25
  def post(payload = {})
26
- @response = RestClient::Request.execute(method: :post,
27
- payload: payload, url: @uri,
26
+ options={method: :post,
27
+ payload: payload,
28
+ headers:{content_type: :json, accept: :json}
29
+ }
30
+ run(options)
31
+ end
32
+
33
+ private
34
+
35
+ def run(options)
36
+ @response = RestClient::Request.execute(
37
+ method: options[:method],
38
+ payload: options[:payload], url: @uri,
28
39
  timeout: @timeout,
29
- headers:{:Authorization => "Bearer #{@client.token}",
30
- content_type: :json,
31
- accept: :json})
32
- puts "#{@response.body}" if TodaysPlan.debug
40
+ headers: options[:headers].merge({:Authorization => "Bearer #{@client.token}"})
41
+ )
42
+ if @response.body.nil? || @response.body.empty?
43
+ raise TodaysPlan::ServerError.new(0, 'Server error', 'Try to connect later')
44
+ end
45
+
46
+ puts "#{@response.inspect}" if TodaysPlan.debug
47
+
33
48
  @body = JSON.parse(@response.body)
34
- @body
49
+ case @response.code
50
+ when 200..207
51
+ @body
52
+ else
53
+ raise_error
54
+ end
35
55
  end
36
56
 
37
-
57
+ # Internal: Raise an error with the class depending on @response.
58
+ #
59
+ # Returns an Array with arguments.
60
+ def raise_error
61
+ klass = case @response.to_s
62
+ when "RestClient::BadRequest" then TodaysPlan::BadRequestError
63
+ when "RestClient::Unauthorized" then TodaysPlan::UnauthorizedError
64
+ when "RestClient::NotFound" then TodaysPlan::NotFoundError
65
+ else
66
+ TodaysPlan::ServerError
67
+ end
68
+ raise klass.new(body['code'], body['message'], body['resolve'])
69
+ end
38
70
  end
39
71
  end
@@ -0,0 +1,37 @@
1
+ module TodaysPlan
2
+ # Public: Exception to throw when there are configuration problems
3
+ class NotConfiguredError < StandardError; end
4
+
5
+ # Internal: Base class for TodaysPlan errors
6
+ class TodaysPlanError < StandardError
7
+ attr_reader :code, :resolve
8
+
9
+ # Internal: Initialize a error with proper attributes.
10
+ #
11
+ # code - The Integer code (e.g. 1501).
12
+ # message - The String message, describing the error.
13
+ # resolve - The String description how to fix the error.
14
+ def initialize(code, message, resolve)
15
+ @code = code
16
+ @resolve = resolve
17
+
18
+ super "Code #{@code}: #{message}. #{resolve}"
19
+ end
20
+ end
21
+
22
+ # Public: Exception which is thrown when TodaysPlan API returns a 400 response.
23
+ class BadRequestError < TodaysPlanError; end
24
+
25
+ # Public: Exception which is thrown when TodaysPlan API returns a 401 response.
26
+ class UnauthorizedError < TodaysPlanError; end
27
+
28
+ # Public: Exception which is thrown when TodaysPlan API returns a 402 response.
29
+ class RequestFailedError < TodaysPlanError; end
30
+
31
+ # Public: Exception which is thrown when TodaysPlan API returns a 404 response.
32
+ class NotFoundError < TodaysPlanError; end
33
+
34
+ # Public: Exception which is thrown when TodaysPlan API returns a response which
35
+ # is neither 2xx, nor 4xx. Presumably 5xx.
36
+ class ServerError < TodaysPlanError; end
37
+ end
@@ -1,3 +1,3 @@
1
1
  module TodaysPlan
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/todays_plan.rb CHANGED
@@ -3,6 +3,7 @@ require 'todays_plan/client'
3
3
  require 'todays_plan/connector'
4
4
  require 'todays_plan/athlete'
5
5
  require 'todays_plan/activity'
6
+ require 'todays_plan/errors'
6
7
  require 'rest_client'
7
8
 
8
9
  module TodaysPlan
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": 7171264,
3
+ "coach": {
4
+ "_name": "Coach Joh",
5
+ "id": 7186982,
6
+ "email": "curt@mtbcoach.com",
7
+ "firstname": "Curt",
8
+ "lastname": "Wilhelm",
9
+ "isPremium": true
10
+ },
11
+ "client": {
12
+ "_name": "curt wilhelm",
13
+ "id": 7189071,
14
+ "email": "curt+1@mtbcoach.com",
15
+ "dob": 315532800000,
16
+ "_dob-display": "1/1/80",
17
+ "firstname": "curt",
18
+ "lastname": "wilhelm",
19
+ "relationship": "coach",
20
+ "_relationship-display": "Coach",
21
+ "isPremium": true
22
+ },
23
+ "state": "active",
24
+ "_state-display": "Active",
25
+ "relationship": "coach",
26
+ "_relationship-display": "Coach"
27
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "cnt": 1,
3
+ "offset": 0,
4
+ "results": [{
5
+ "id": 98765,
6
+ "coach": {
7
+ "_name": "Coach John",
8
+ "id": 5678,
9
+ "email": "coach@example.com",
10
+ "firstname": "Coach",
11
+ "lastname": "john",
12
+ "isPremium": true
13
+ },
14
+ "client": {
15
+ "_name": "joe athlete",
16
+ "id": 1234,
17
+ "email": "joeathlete@example.com",
18
+ "firstname": "joe",
19
+ "lastname": "athlete"
20
+ },
21
+ "state": "pending_coach",
22
+ "_state-display": "Pending",
23
+ "relationship": "coach",
24
+ "_relationship-display": "Coach"
25
+ }]
26
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "id": 8765,
3
+ "coach": {
4
+ "_name": "coach John",
5
+ "id": 5678,
6
+ "email": "coach@example.com",
7
+ "firstname": "Coach",
8
+ "lastname": "John"
9
+ },
10
+ "client": {
11
+ "_name": "joe athlete",
12
+ "id": 1234,
13
+ "email": "joeathlete@example.com",
14
+ "firstname": "joe",
15
+ "lastname": "athlete",
16
+ "isPremium": true
17
+ },
18
+ "state": "pending_coach",
19
+ "_state-display": "Pending",
20
+ "relationship": "coach",
21
+ "_relationship-display": "Coach"
22
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "email": "joeathlete@example.com",
3
+ "uuid": "yyyy",
4
+ "firstname": "joe",
5
+ "lastname": "athlete",
6
+ "locale": "English (United States)",
7
+ "timezone": "Etc/UTC",
8
+ "weekStart": "sun",
9
+ "_weekStart-display": "Sunday",
10
+ "stripeId": "xxxx",
11
+ "prefsMask": 0,
12
+ "cls": "net.todaysplan.model.users.User",
13
+ "id": 1234
14
+ }
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe TodaysPlan::Athlete do
4
4
 
5
- let(:response){File.read("spec/fixtures/athletes/response.json")}
5
+ let(:response){File.read("spec/fixtures/athletes/search_response.json")}
6
6
 
7
7
  it "expect to get all athletes" do
8
8
  stub_request(:get, "#{TodaysPlan.endpoint}/users/delegates/users").
@@ -12,13 +12,13 @@ describe TodaysPlan::Athlete do
12
12
  all = TodaysPlan::Athlete.all()
13
13
  expect(all).to be_a(Array)
14
14
  expect(all[0]).to be_a(TodaysPlan::Athlete)
15
- expect(all[0].first_name).to_not be_nil
16
- expect(all[0].last_name).to_not be_nil
17
- expect(all[0].coach).to_not be_nil
18
- expect(all[0].timezone).to_not be_nil
19
- expect(all[0].id).to_not be_nil
20
- expect(all[0].name).to_not be_nil
21
- expect(all[0].email).to_not be_nil
15
+ expect(all[0].first_name).to eq "Joe"
16
+ expect(all[0].last_name).to eq "Athlete"
17
+ expect(all[0].coach).to eq 7187033
18
+ expect(all[0].timezone).to eq "US/Mountain"
19
+ expect(all[0].id).to eq 7187033
20
+ expect(all[0].name).to eq "Joe Athlete"
21
+ expect(all[0].email).to eq "joeathlete@example.com"
22
22
  end
23
23
 
24
24
  it "expect to get one athlete" do
@@ -38,5 +38,55 @@ describe TodaysPlan::Athlete do
38
38
  expect(athlete).to respond_to(:dob)
39
39
  end
40
40
 
41
+ it "expect to create one athlete" do
42
+ options = {user_email: 'joeathlete@example.com', firstname: 'joe',
43
+ lastname: 'athlete', password:'password', coach_email: 'coach@email.com'}
44
+ # preregister
45
+ stub_request(:get, "#{TodaysPlan.endpoint}/auth/preregister").
46
+ with(:headers => {'Accept'=>'*/*'}).
47
+ to_return(:status => 200, :body => "", :headers => {})
48
+ #register
49
+ stub_request(:post, "#{TodaysPlan.endpoint}/auth/register").
50
+ with(:body => '{"email":"joeathlete@example.com","firstname":"joe","lastname":"athlete","password":"password"}',
51
+ :headers => {'Accept'=>'*/*'}).
52
+ to_return(:status => 200,
53
+ :body => File.read("spec/fixtures/athletes/register_response.json"),
54
+ :headers => {})
55
+ #login as new user
56
+ stub_request(:post, TodaysPlan.endpoint+'/auth/login').
57
+ with(:body => "{\"username\":\"joeathlete@example.com\",\"password\":\"password\",\"token\":true}",
58
+ :headers => {'Accept'=>'application/json',
59
+ 'Content-Type'=>'application/json', }).
60
+ to_return(:status => 200, :body => '{"token":"abc-456"}', :headers => {})
61
+ #invite the coach
62
+ stub_request(:post, "#{TodaysPlan.endpoint}/users/delegates/invite").
63
+ with(:body => '{"email":"coach@email.com","state":"pending_coach","relationship":"coach"}',
64
+ :headers => {'Accept'=>'application/json',
65
+ 'Authorization'=>'Bearer abc-456',
66
+ 'Content-Type'=>'application/json'}).
67
+ to_return(:status => 200,
68
+ :body => File.read("spec/fixtures/athletes/invite_response.json"),
69
+ :headers => {})
70
+ # search for pending invites
71
+ stub_request(:post, "#{TodaysPlan.endpoint}/users/delegates/search/0/100").
72
+ with(:body => '{"state":"pending_coach"}',
73
+ :headers => {'Accept'=>'application/json',
74
+ 'Authorization'=>'Bearer abc-123',
75
+ 'Content-Type'=>'application/json'}).
76
+ to_return(:status => 200,
77
+ :body => File.read("spec/fixtures/athletes/delegates_response.json"),
78
+ :headers => {})
79
+ # accept invite
80
+ stub_request(:get, "#{TodaysPlan.endpoint}/users/delegates/invite/accept/98765").
81
+ with(:headers => {'Accept'=>'application/json', 'Authorization'=>'Bearer abc-123'}).
82
+ to_return(:status => 200,
83
+ :body => File.read("spec/fixtures/athletes/accept_response.json"),
84
+ :headers => {})
85
+ athlete = TodaysPlan::Athlete.create(options)
86
+ expect(athlete.first_name).to eq "joe"
87
+ expect(athlete.last_name).to eq "athlete"
88
+ expect(athlete.email).to eq "joeathlete@example.com"
89
+ expect(athlete.id).to eq(1234)
90
+ end
41
91
 
42
92
  end
@@ -17,25 +17,62 @@ describe TodaysPlan::Connector do
17
17
  end
18
18
 
19
19
  it "expect to create new connect with client" do
20
- client = double(token: 'abc-123')
20
+ client = double(token: 'abc-123', code: 200)
21
21
  expect(TodaysPlan::Client).to_not receive(:new)
22
22
  TodaysPlan::Connector.new("/test", client)
23
23
  end
24
24
 
25
25
  it "expect rest-client get request" do
26
- response = double(body: '{"message":"test"}')
26
+ response = double(body: '{"message":"test"}', code: 200)
27
27
  client = double(token: 'abc-123')
28
28
  expect(TodaysPlan::Client).to receive(:new).with(username, password).and_return(client)
29
29
  expect(RestClient::Request).to receive(:execute).and_return(response)
30
30
  expect(TodaysPlan::Connector.new("/test",).get()).to eq({"message"=>"test"})
31
31
  end
32
+
32
33
  it "expect rest-client post request" do
33
- response = double(body: '{"message":"test"}')
34
+ response = double(body: '{"message":"test"}', code: 201)
34
35
  client = double(token: 'abc-123')
35
36
  expect(TodaysPlan::Client).to receive(:new).with(username, password).and_return(client)
36
37
  expect(RestClient::Request).to receive(:execute).and_return(response)
37
38
  expect(TodaysPlan::Connector.new("/test",).post()).to eq({"message"=>"test"})
38
39
  end
39
40
 
40
-
41
+
42
+ it "expect rest-client post raise error empty body" do
43
+ response = double(body: nil, code: 503)
44
+ client = double(token: 'abc-123')
45
+ expect(TodaysPlan::Client).to receive(:new).with(username, password).and_return(client)
46
+ expect(RestClient::Request).to receive(:execute).and_return(response)
47
+ expect{TodaysPlan::Connector.new("/test",).post()}.to raise_error(TodaysPlan::ServerError)
48
+ end
49
+
50
+ it "expect rest-client get raise error empty body" do
51
+ response = double(body: nil, code: 200)
52
+ client = double(token: 'abc-123')
53
+ expect(TodaysPlan::Client).to receive(:new).with(username, password).and_return(client)
54
+ expect(RestClient::Request).to receive(:execute).and_return(response)
55
+ expect{TodaysPlan::Connector.new("/test",).get()}.to raise_error(TodaysPlan::ServerError)
56
+ end
57
+
58
+ it "expect rest-client get raise error 404" do
59
+ client = double(token: 'abc-123')
60
+ allow(RestClient::NotFound).to receive(:body).and_return('{"message":"testing"}')
61
+ allow(RestClient::NotFound).to receive(:code).and_return(404)
62
+ expect(TodaysPlan::Client).to receive(:new).with(username, password).and_return(client)
63
+ expect(RestClient::Request).to receive(:execute).and_return(RestClient::NotFound)
64
+ expect{TodaysPlan::Connector.new("/test",).get()}.to raise_error(TodaysPlan::NotFoundError)
65
+ end
66
+
67
+ it "expect rest-client get raise error 401" do
68
+ response = double('RestClient::Unauthorized',body: '{}', code: 401)
69
+ client = double(token: 'abc-123')
70
+ expect(TodaysPlan::Client).to receive(:new).with(username, password).and_return(client)
71
+ allow(RestClient::Unauthorized).to receive(:body).and_return('{"message":"testing"}')
72
+ allow(RestClient::Unauthorized).to receive(:code).and_return(401)
73
+ expect(RestClient::Request).to receive(:execute).and_return(RestClient::Unauthorized)
74
+ expect{TodaysPlan::Connector.new("/test",).get()}.to raise_error(TodaysPlan::UnauthorizedError)
75
+ end
76
+
77
+
41
78
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: todaysplan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Curt Wilhelm
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-13 00:00:00.000000000 Z
11
+ date: 2017-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -95,10 +95,15 @@ files:
95
95
  - lib/todays_plan/athlete.rb
96
96
  - lib/todays_plan/client.rb
97
97
  - lib/todays_plan/connector.rb
98
+ - lib/todays_plan/errors.rb
98
99
  - lib/todays_plan/version.rb
99
100
  - spec/fixtures/activities/incomplete.json
100
101
  - spec/fixtures/activities/incomplete_response.json
101
- - spec/fixtures/athletes/response.json
102
+ - spec/fixtures/athletes/accept_response.json
103
+ - spec/fixtures/athletes/delegates_response.json
104
+ - spec/fixtures/athletes/invite_response.json
105
+ - spec/fixtures/athletes/register_response.json
106
+ - spec/fixtures/athletes/search_response.json
102
107
  - spec/spec_helper.rb
103
108
  - spec/todays_plan/activity_spec.rb
104
109
  - spec/todays_plan/athlete_spec.rb
@@ -132,7 +137,11 @@ summary: A Ruby Library for TodaysPlan
132
137
  test_files:
133
138
  - spec/fixtures/activities/incomplete.json
134
139
  - spec/fixtures/activities/incomplete_response.json
135
- - spec/fixtures/athletes/response.json
140
+ - spec/fixtures/athletes/accept_response.json
141
+ - spec/fixtures/athletes/delegates_response.json
142
+ - spec/fixtures/athletes/invite_response.json
143
+ - spec/fixtures/athletes/register_response.json
144
+ - spec/fixtures/athletes/search_response.json
136
145
  - spec/spec_helper.rb
137
146
  - spec/todays_plan/activity_spec.rb
138
147
  - spec/todays_plan/athlete_spec.rb