teamsnap_rb 1.3.3 → 2.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +131 -29
- data/lib/config/inflecto.rb +13 -0
- data/lib/config/oj.rb +5 -0
- data/lib/teamsnap.rb +36 -376
- data/lib/teamsnap/api.rb +113 -0
- data/lib/teamsnap/auth_middleware.rb +62 -0
- data/lib/teamsnap/client.rb +51 -0
- data/lib/teamsnap/collection.rb +125 -0
- data/lib/teamsnap/item.rb +100 -0
- data/lib/teamsnap/response.rb +101 -0
- data/lib/teamsnap/structure.rb +80 -0
- data/lib/teamsnap/version.rb +1 -1
- data/spec/cassettes/apiv3-init.yml +756 -124
- data/spec/cassettes/client/when_calling_via_s_on_the_client/does_not_raise_an_error_when_the_HTTP_actions_are_called.yml +56 -0
- data/spec/cassettes/structure/_create_collection_class/registers_new_classes_via_introspection_of_the_root_collection.yml +110 -0
- data/spec/cassettes/structure/_create_collection_class/sets_the_href_attribute_on_the_new_class.yml +57 -0
- data/spec/cassettes/structure/_init/has_all_classes_in_schema_loaded_except_for_exceptions_list_endpoints.yml +56 -0
- data/spec/cassettes/structure/has_all_classes_in_schema_loaded_except_for_exceptions_list_endpoints.yml +56 -0
- data/spec/cassettes/teamsnap__client/when_calling_via_s_on_the_client/does_not_raise_an_error_when_the_HTTP_actions_are_called.yml +69 -0
- data/spec/cassettes/teamsnap__client/when_calling_via_s_on_the_client/passes_them_to_the_faraday_client_using_method_missing.yml +69 -0
- data/spec/cassettes/teamsnap__collection/adds_find_if_search_is_available.yml +61 -0
- data/spec/cassettes/teamsnap__collection/adds_href_to_items.yml +62 -0
- data/spec/cassettes/teamsnap__collection/can_follow_plural_links.yml +179 -0
- data/spec/cassettes/teamsnap__collection/can_follow_singular_links.yml +120 -0
- data/spec/cassettes/teamsnap__collection/can_handle_links_with_no_data.yml +107 -0
- data/spec/cassettes/{teamsnap_rb/can_handle_errors_generated_by_command.yml → teamsnap__collection/can_handle_no_argument_errors_generated_by_command.yml} +10 -16
- data/spec/cassettes/teamsnap__collection/handles_executing_an_action_via_commands.yml +64 -0
- data/spec/cassettes/teamsnap__collection/handles_executing_an_action_via_commands_with_multiple_params.yml +70 -0
- data/spec/cassettes/teamsnap__collection/handles_fetching_data_via_queries.yml +61 -0
- data/spec/cassettes/teamsnap__collection/handles_queries_with_no_data.yml +57 -0
- data/spec/cassettes/teamsnap__collection/raises_an_exception_if_find_returns_nothing.yml +57 -0
- data/spec/cassettes/teamsnap__collection/supports_relations_with_expected_behaviors/when_a_plural_relation_is_called/responds_with_an_array_of_objects_when_successful.yml +117 -0
- data/spec/cassettes/teamsnap__collection/supports_relations_with_expected_behaviors/when_a_plural_relation_is_called/responds_with_an_empty_array_when_no_objects_exist.yml +111 -0
- data/spec/cassettes/teamsnap__collection/supports_relations_with_expected_behaviors/when_a_singular_relation_is_called/responds_with_nil_if_it_does_NOT_exist.yml +111 -0
- data/spec/cassettes/teamsnap__collection/supports_relations_with_expected_behaviors/when_a_singular_relation_is_called/responds_with_the_object_if_it_exists.yml +124 -0
- data/spec/cassettes/teamsnap__structure/_create_collection_class/registers_new_classes_via_introspection_of_the_root_collection.yml +57 -0
- data/spec/cassettes/teamsnap__structure/_create_collection_class/sets_the_href_attribute_on_the_new_class.yml +57 -0
- data/spec/cassettes/teamsnap__structure/_init/has_all_classes_in_schema_loaded_except_for_exceptions_list_endpoints.yml +69 -0
- data/spec/cassettes/teamsnap_rb/_bulk_load/can_handle_an_empty_bulk_load.yml +55 -0
- data/spec/cassettes/teamsnap_rb/{can_handle_an_error_with_bulk_load.yml → _bulk_load/can_handle_an_error_with_bulk_load.yml} +11 -23
- data/spec/cassettes/teamsnap_rb/_bulk_load/can_use_bulk_load.yml +121 -0
- data/spec/cassettes/teamsnap_rb/_client_send/when_sent_a_known_via_/calls_DELETE_on_the_given_client.yml +2405 -0
- data/spec/cassettes/teamsnap_rb/_client_send/when_sent_a_known_via_/calls_GET_on_the_given_client.yml +69 -0
- data/spec/cassettes/teamsnap_rb/_client_send/when_sent_a_known_via_/calls_PATCH_on_the_given_client.yml +2404 -0
- data/spec/cassettes/teamsnap_rb/_client_send/when_sent_a_known_via_/calls_POST_on_the_given_client.yml +2404 -0
- data/spec/cassettes/teamsnap_rb/_run/processes_the_response.yml +267 -0
- data/spec/cassettes/teamsnap_rb/adds_find_if_search_is_available.yml +27 -30
- data/spec/cassettes/teamsnap_rb/adds_href_to_items.yml +31 -19
- data/spec/cassettes/teamsnap_rb/can_follow_plural_links.yml +118 -67
- data/spec/cassettes/teamsnap_rb/can_follow_singular_links.yml +59 -56
- data/spec/cassettes/teamsnap_rb/can_handle_links_with_no_data.yml +48 -38
- data/spec/cassettes/teamsnap_rb/can_handle_no_argument_errors_generated_by_command.yml +42 -0
- data/spec/cassettes/teamsnap_rb/handles_executing_an_action_via_commands.yml +32 -20
- data/spec/cassettes/teamsnap_rb/handles_executing_an_action_via_commands_with_multiple_params.yml +29 -404
- data/spec/cassettes/teamsnap_rb/handles_fetching_data_via_queries.yml +26 -23
- data/spec/cassettes/teamsnap_rb/handles_queries_with_no_data.yml +24 -28
- data/spec/cassettes/teamsnap_rb/raises_an_exception_if_find_returns_nothing.yml +24 -28
- data/spec/cassettes/teamsnap_rb/supports_relations_with_expected_behaviors/when_a_plural_relation_is_called/responds_with_an_array_of_objects_when_successful.yml +53 -45
- data/spec/cassettes/teamsnap_rb/supports_relations_with_expected_behaviors/when_a_plural_relation_is_called/responds_with_an_empty_array_when_no_objects_exist.yml +50 -54
- data/spec/cassettes/teamsnap_rb/supports_relations_with_expected_behaviors/when_a_singular_relation_is_called/responds_with_nil_if_it_does_NOT_exist.yml +50 -54
- data/spec/cassettes/teamsnap_rb/supports_relations_with_expected_behaviors/when_a_singular_relation_is_called/responds_with_the_object_if_it_exists.yml +59 -58
- data/spec/spec_helper.rb +2 -0
- data/spec/teamsnap/client_spec.rb +75 -0
- data/spec/teamsnap/collection_spec.rb +155 -0
- data/spec/teamsnap/item_spec.rb +155 -0
- data/spec/teamsnap/structure_spec.rb +63 -0
- data/spec/teamsnap_spec.rb +169 -157
- data/teamsnap_rb.gemspec +1 -1
- metadata +92 -15
- data/spec/cassettes/teamsnap_rb/can_handle_an_empty_bulk_load.yml +0 -60
- data/spec/cassettes/teamsnap_rb/can_use_bulk_load.yml +0 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a93f427c06bd23b1c461e7972a5be914b48afa1c
|
4
|
+
data.tar.gz: b49a4d94aa26ee91aea101677ad74f3d3941b1bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9485d5d81583191d1d4027d61e050b6e99f1312f732d045faa7a9951f4b1e5ba31a3536ea2cd9b757d0acc22fef45863e8a655944e9e8dd6bb3dae8b9d3d03e7
|
7
|
+
data.tar.gz: 18ba0a37191961fe69074e67f13a82dffb2ef208094423118c9eb15f6dc092d9f0f63d18f4c921139d311579cacb7c10d2ef75099ebcf4f08ebe2c6a315d3a82
|
data/CHANGELOG.md
CHANGED
@@ -14,3 +14,9 @@ v1.3.3
|
|
14
14
|
|
15
15
|
- Have the ability to search for a /schemas endpoint and create the collections
|
16
16
|
off of the schema endpoint instead of hitting each endpoint individually
|
17
|
+
|
18
|
+
v2.0.0.beta
|
19
|
+
------
|
20
|
+
|
21
|
+
- Full CRUD actions available along with TeamSnap::Response option for better
|
22
|
+
control-flow statements.
|
data/README.md
CHANGED
@@ -12,37 +12,139 @@
|
|
12
12
|
_Note: You'll need an OAuth2 Token from TeamSnap. Checkout our API docs
|
13
13
|
[here](http://developer.teamsnap.com/documentation/apiv3/)_
|
14
14
|
|
15
|
-
|
16
|
-
λ
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
=>
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
15
|
+
λ gem install teamsnap_rb
|
16
|
+
λ irb
|
17
|
+
TeamSnap.init(:client_id => XXXXX, :client_secret => XXXXX)
|
18
|
+
=> true
|
19
|
+
|
20
|
+
# Now you have your base connection to the API under:
|
21
|
+
TeamSnap.root_client
|
22
|
+
=> #<TeamSnap::Client:...>
|
23
|
+
|
24
|
+
# The below imply usage of:
|
25
|
+
client = TeamSnap.root_client
|
26
|
+
|
27
|
+
t = TeamSnap::Team.find(client, 1)
|
28
|
+
=> #<TeamSnap::Team::...>
|
29
|
+
t.name
|
30
|
+
=> "TeamSnap"
|
31
|
+
rs = client.bulk_load(client, {:team_id => 1, :types => "team,member"})
|
32
|
+
=> [
|
33
|
+
=> #<TeamSnap::Team:...>,
|
34
|
+
=> #<TeamSnap::Member:...>,
|
35
|
+
=> # ...
|
36
|
+
=> #<TeamSnap::Member:...>
|
37
|
+
=> ]
|
38
|
+
rs[1].first_name
|
39
|
+
=> "Andrew"
|
40
|
+
|
41
|
+
|
42
|
+
#########################
|
43
|
+
Class Syntax
|
44
|
+
#########################
|
45
|
+
- raises error on exception
|
46
|
+
- returns Object(TeamSnap::Class) / Objects(Array) as response
|
47
|
+
|
48
|
+
# find
|
49
|
+
team = TeamSnap::Team.find(client, XXX)
|
50
|
+
|
51
|
+
# create
|
52
|
+
team = TeamSnap::Team.create(client, {:attribute_name => value})
|
53
|
+
|
54
|
+
# update
|
55
|
+
team = TeamSnap::Team.update(client, {:id => XXX, :attribute_name => value})
|
56
|
+
|
57
|
+
# delete
|
58
|
+
no_team = TeamSnap::Team.delete(client, id)
|
59
|
+
|
60
|
+
# search
|
61
|
+
teams = TeamSnap::Team.search(client, {:filter_on => filter_value})
|
62
|
+
|
63
|
+
# command
|
64
|
+
team = TeamSnap::Team.command_name(client, {:attr => val})
|
65
|
+
|
66
|
+
|
67
|
+
#########################
|
68
|
+
Api Class Syntax
|
69
|
+
#########################
|
70
|
+
- returns TeamSnap::Response object with select methods
|
71
|
+
- optionally converts attributes hash into template: { data: {}}
|
72
|
+
|
73
|
+
# find
|
74
|
+
response = TeamSnap::Api.run(client, :find, :members, 1)
|
75
|
+
=> #<TeamSnap::Response:...>
|
76
|
+
response.success?
|
77
|
+
=> true
|
78
|
+
member = response.objects.first
|
79
|
+
=> #<TeamSnap::Member:...>
|
80
|
+
response.errors?
|
81
|
+
=> false
|
82
|
+
response.message
|
83
|
+
=> "Data retrieved successfully"
|
84
|
+
|
85
|
+
# create
|
86
|
+
response = TeamSnap::Api.run(client, :create, TeamSnap::Member, {:attr_name => attr_value}, true)
|
87
|
+
=> #<TeamSnap::Response:...>
|
88
|
+
response.success?
|
89
|
+
=> false
|
90
|
+
response.errors?
|
91
|
+
=> true
|
92
|
+
response.message
|
93
|
+
=> "first_name can't be blank; team_id can't be blank"
|
94
|
+
|
95
|
+
# update
|
96
|
+
TeamSnap::Api.run(client, :update, :member, {}, true)
|
97
|
+
=> #<TeamSnap::Response:...>
|
98
|
+
|
99
|
+
# delete
|
100
|
+
TeamSnap::Api.run(client, :delete, :members, id)
|
101
|
+
=> #<TeamSnap::Response:...>
|
102
|
+
|
103
|
+
# search & other queries
|
104
|
+
TeamSnap::Api.run(client, :search, TeamSnap::Member, {:team_id => some_team_id})
|
105
|
+
=> #<TeamSnap::Response:...>
|
106
|
+
|
107
|
+
# commands
|
108
|
+
TeamSnap::Api.run(client, :command, :member, {:optional_attr => value})
|
109
|
+
=> #<TeamSnap::Response:...>
|
110
|
+
|
111
|
+
|
112
|
+
#########################
|
113
|
+
Client Object Calls
|
114
|
+
#########################
|
115
|
+
- returns TeamSnap::Response object with select methods
|
116
|
+
- automatically translates attributes to / from template: { data: {}}
|
117
|
+
|
118
|
+
# find
|
119
|
+
client.api(:find, :forum_posts, 1)
|
120
|
+
=> #<TeamSnap::Response:...>
|
121
|
+
|
122
|
+
# search and other 'queries' (arguments patch 'as-is')
|
123
|
+
client.api(:search, TeamSnap::ForumPost, {:forum_topic_id => 2})
|
124
|
+
=> #<TeamSnap::Response:...>
|
125
|
+
|
126
|
+
# create (arguments post in template data format)
|
127
|
+
client.api(:create, :forum_post, forum_post_success)
|
128
|
+
=> #<TeamSnap::Response:...>
|
129
|
+
|
130
|
+
# update (arguments post in template data format)
|
131
|
+
client.api(:update, TeamSnap::ForumPost, forum_patch_success)
|
132
|
+
=> #<TeamSnap::Response:...>
|
133
|
+
|
134
|
+
# delete
|
135
|
+
client.api(:delete, :forum_posts, 1)
|
136
|
+
=> #<TeamSnap::Response:...>
|
137
|
+
|
138
|
+
# commands (arguments post 'as-is')
|
139
|
+
client.api(:command_name, :forum_post, {})
|
140
|
+
=> #<TeamSnap::Response:...>
|
141
|
+
|
142
|
+
# queries (arguments sent in href key/value pairs)
|
143
|
+
client.api(:query_name, :members, {})
|
144
|
+
=> #<TeamSnap::Response:...>
|
145
|
+
|
42
146
|
|
43
147
|
|
44
148
|
## Todo
|
45
149
|
|
46
|
-
- Literate style docs?
|
47
150
|
- Cache items with threadsafe Hash (https://github.com/headius/thread_safe).
|
48
|
-
- Implement create, update and delete.
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Inflecto.inflections do |inflect|
|
2
|
+
inflect.irregular "broadcast_sms", "broadcast_smses"
|
3
|
+
inflect.irregular "division_member_preferences", "division_members_preferences"
|
4
|
+
inflect.irregular "division_preferences", "divisions_preferences"
|
5
|
+
inflect.irregular "member_preferences", "member_preferences"
|
6
|
+
inflect.irregular "member_preferences", "members_preferences"
|
7
|
+
inflect.irregular "opponent_results", "opponent_results"
|
8
|
+
inflect.irregular "opponent_results", "opponents_results"
|
9
|
+
inflect.irregular "team_preferences", "team_preferences"
|
10
|
+
inflect.irregular "team_preferences", "teams_preferences"
|
11
|
+
inflect.irregular "team_results", "team_results"
|
12
|
+
inflect.irregular "team_results", "teams_results"
|
13
|
+
end
|
data/lib/config/oj.rb
ADDED
data/lib/teamsnap.rb
CHANGED
@@ -1,219 +1,61 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require
|
5
|
-
require "inflecto"
|
6
|
-
require "virtus"
|
7
|
-
require "date"
|
8
|
-
require "securerandom"
|
1
|
+
%w(
|
2
|
+
faraday typhoeus typhoeus/adapters/faraday oj inflecto virtus
|
3
|
+
date securerandom
|
4
|
+
).each { |x| require x }
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
:class_cache => true
|
16
|
-
}
|
17
|
-
|
18
|
-
Faraday::Request.register_middleware(
|
19
|
-
:teamsnap_auth_middleware => -> { TeamSnap::AuthMiddleware }
|
20
|
-
)
|
21
|
-
|
22
|
-
Inflecto.inflections do |inflect|
|
23
|
-
inflect.irregular "broadcast_sms", "broadcast_smses"
|
24
|
-
inflect.irregular "member_preferences", "member_preferences"
|
25
|
-
inflect.irregular "member_preferences", "members_preferences"
|
26
|
-
inflect.irregular "opponent_results", "opponent_results"
|
27
|
-
inflect.irregular "opponent_results", "opponents_results"
|
28
|
-
inflect.irregular "team_preferences", "team_preferences"
|
29
|
-
inflect.irregular "team_preferences", "teams_preferences"
|
30
|
-
inflect.irregular "team_results", "team_results"
|
31
|
-
inflect.irregular "team_results", "teams_results"
|
32
|
-
end
|
6
|
+
%w(
|
7
|
+
config/inflecto config/oj teamsnap/version teamsnap/api
|
8
|
+
teamsnap/auth_middleware teamsnap/client teamsnap/collection teamsnap/item
|
9
|
+
teamsnap/response teamsnap/structure
|
10
|
+
).each { |x| require_relative x }
|
33
11
|
|
34
12
|
module TeamSnap
|
35
|
-
EXCLUDED_RELS = %w(me apiv2_root root self dude sweet random xyzzy schemas
|
13
|
+
EXCLUDED_RELS = %w(me apiv2_root root self dude sweet random xyzzy schemas
|
14
|
+
authorization plans_all tsl_photos)
|
36
15
|
DEFAULT_URL = "https://apiv3.teamsnap.com"
|
37
16
|
Error = Class.new(StandardError)
|
38
17
|
NotFound = Class.new(TeamSnap::Error)
|
39
18
|
|
40
|
-
class AuthMiddleware < Faraday::Middleware
|
41
|
-
def initialize(app, options)
|
42
|
-
@options = options
|
43
|
-
super(app)
|
44
|
-
end
|
45
|
-
|
46
|
-
def call(env)
|
47
|
-
if token
|
48
|
-
env[:request_headers].merge!({"Authorization" => "Bearer #{token}"})
|
49
|
-
elsif client_id && client_secret
|
50
|
-
query_params = Hash[URI.decode_www_form(env.url.query || "")]
|
51
|
-
.merge({
|
52
|
-
hmac_client_id: client_id,
|
53
|
-
hmac_nonce: SecureRandom.uuid,
|
54
|
-
hmac_timestamp: Time.now.to_i
|
55
|
-
})
|
56
|
-
env.url.query = URI.encode_www_form(query_params)
|
57
|
-
|
58
|
-
env.request_headers["X-Teamsnap-Hmac"] = OpenSSL::HMAC.hexdigest(
|
59
|
-
digest, client_secret, message_hash(env)
|
60
|
-
)
|
61
|
-
end
|
62
|
-
|
63
|
-
@app.call(env)
|
64
|
-
end
|
65
|
-
|
66
|
-
def token
|
67
|
-
@token ||= @options[:token]
|
68
|
-
end
|
69
|
-
|
70
|
-
def client_id
|
71
|
-
@client_id ||= @options[:client_id]
|
72
|
-
end
|
73
|
-
|
74
|
-
def client_secret
|
75
|
-
@client_secret ||= @options[:client_secret]
|
76
|
-
end
|
77
|
-
|
78
|
-
def digest
|
79
|
-
OpenSSL::Digest.new("sha256")
|
80
|
-
end
|
81
|
-
|
82
|
-
def message_hash(env)
|
83
|
-
digest.hexdigest(
|
84
|
-
query_string(env) + message(env)
|
85
|
-
)
|
86
|
-
end
|
87
|
-
|
88
|
-
def query_string(env)
|
89
|
-
"/?" + env.url.query.to_s
|
90
|
-
end
|
91
|
-
|
92
|
-
def message(env)
|
93
|
-
env.body || ""
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
19
|
class << self
|
98
|
-
|
99
|
-
Module.new do
|
100
|
-
define_singleton_method(:included) do |descendant|
|
101
|
-
descendant.send(:include, TeamSnap::Item)
|
102
|
-
descendant.extend(TeamSnap::Collection)
|
103
|
-
descendant.instance_variable_set(:@href, href)
|
104
|
-
descendant.instance_variable_set(:@resp, resp)
|
105
|
-
descendant.instance_variable_set(:@parsed_collection, parsed_collection)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def hashify(arr)
|
111
|
-
arr.to_h
|
112
|
-
rescue NoMethodError
|
113
|
-
arr.inject({}) { |hash, (key, value)| hash[key] = value; hash }
|
114
|
-
end
|
20
|
+
attr_accessor :client_id, :client_secret, :root_client, :token, :url
|
115
21
|
|
116
22
|
def init(opts = {})
|
117
|
-
opts[:
|
118
|
-
|
119
|
-
opts.include?(:client_id) && opts.include?(:client_secret)
|
120
|
-
)
|
121
|
-
raise ArgumentError.new(
|
122
|
-
"You must provide a :token or :client_id and :client_secret pair to '.init'"
|
123
|
-
)
|
124
|
-
end
|
125
|
-
|
126
|
-
self.client = Faraday.new(
|
127
|
-
:url => opts.fetch(:url),
|
128
|
-
:parallel_manager => Typhoeus::Hydra.new
|
129
|
-
) do |c|
|
130
|
-
c.request :teamsnap_auth_middleware, {
|
131
|
-
:token => opts[:token],
|
132
|
-
:client_id => opts[:client_id],
|
133
|
-
:client_secret => opts[:client_secret]
|
134
|
-
}
|
135
|
-
c.adapter :typhoeus
|
23
|
+
unless opts[:token] || (opts[:client_id] && opts[:client_secret])
|
24
|
+
raise ArgumentError.new("You must provide a :token or :client_id and :client_secret pair to '.init'")
|
136
25
|
end
|
137
26
|
|
138
|
-
|
27
|
+
## setup variables required
|
28
|
+
self.client_id = opts.fetch(:client_id) {}
|
29
|
+
self.client_secret = opts.fetch(:client_secret) {}
|
30
|
+
self.token = opts.fetch(:token) {}
|
31
|
+
self.url = opts.fetch(:url) { DEFAULT_URL }
|
139
32
|
|
140
|
-
|
33
|
+
## create universally accessible TeamSnap.root_client
|
34
|
+
self.root_client = TeamSnap::Client.new(:token => token)
|
141
35
|
|
142
|
-
|
143
|
-
|
144
|
-
.find { |link| link[:rel] == "schemas" } || {}
|
145
|
-
|
146
|
-
if schema[:href]
|
147
|
-
href_to_rel = collection
|
148
|
-
.fetch(:links) { [] }
|
149
|
-
.reject { |link| EXCLUDED_RELS.include?(link[:rel]) }
|
150
|
-
.map { |link| [link[:href], link[:rel]]}
|
151
|
-
.to_h
|
152
|
-
|
153
|
-
resp = client.get(schema[:href])
|
154
|
-
if resp.status == 200
|
155
|
-
collections = Oj.load(resp.body)
|
156
|
-
classes = collections.map { |collection|
|
157
|
-
col = collection.fetch(:collection) { {} }
|
158
|
-
if rel = href_to_rel[col[:href]]
|
159
|
-
create_collection_class(rel, col[:href], nil, col)
|
160
|
-
end
|
161
|
-
}
|
162
|
-
.compact
|
163
|
-
else
|
164
|
-
error_message = TeamSnap.parse_error(resp)
|
165
|
-
raise TeamSnap::Error.new(error_message)
|
166
|
-
end
|
167
|
-
else
|
168
|
-
client.in_parallel do
|
169
|
-
classes = collection
|
170
|
-
.fetch(:links) { [] }
|
171
|
-
.map { |link| classify_rel(link) }
|
172
|
-
.compact
|
173
|
-
end
|
174
|
-
end
|
175
|
-
classes.each { |cls| cls.parse_collection }
|
36
|
+
## Make the apiv3 root call. collection is parsed JSON
|
37
|
+
collection = TeamSnap.run(root_client, :get, "/", {})
|
176
38
|
|
177
|
-
|
178
|
-
|
39
|
+
## Setup Dynamic Classes from the collection
|
40
|
+
TeamSnap::Structure.init(root_client, collection)
|
179
41
|
|
180
|
-
|
181
|
-
|
182
|
-
resp = client_send(via, href, args)
|
183
|
-
rescue Faraday::TimeoutError
|
184
|
-
warn("Connection to API failed. Initializing with empty class structure")
|
185
|
-
{:links => []}
|
186
|
-
else
|
187
|
-
if resp.success?
|
188
|
-
Oj.load(resp.body).fetch(:collection)
|
189
|
-
else
|
190
|
-
error_message = parse_error(resp)
|
191
|
-
raise TeamSnap::Error.new(error_message)
|
192
|
-
end
|
193
|
-
end
|
42
|
+
## Queries and Commands parsing for shortcut methods
|
43
|
+
TeamSnap::Collection.apply_endpoints(self, collection) && true
|
194
44
|
end
|
195
45
|
|
196
|
-
def run(via, href, args = {})
|
197
|
-
resp = client_send(via, href, args)
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
error_message = parse_error(resp)
|
203
|
-
raise TeamSnap::Error.new(error_message)
|
204
|
-
else
|
205
|
-
raise TeamSnap::Error.new("`#{via}` call was unsuccessful. " +
|
206
|
-
"Unexpected response content-type. " +
|
207
|
-
"Check TeamSnap APIv3 connection")
|
208
|
-
end
|
209
|
-
end
|
46
|
+
def run(client, via, href, args = {})
|
47
|
+
resp = client_send(client, via, href, args)
|
48
|
+
return TeamSnap::Response.load_collection(resp)
|
49
|
+
rescue Faraday::TimeoutError
|
50
|
+
warn("Connection to API failed with TimeoutError")
|
51
|
+
{:links => []}
|
210
52
|
end
|
211
53
|
|
212
|
-
def client_send(via, href, args)
|
54
|
+
def client_send(client, via, href, args)
|
213
55
|
case via
|
214
|
-
when :get
|
56
|
+
when :get, :delete
|
215
57
|
client.send(via, href, args)
|
216
|
-
when :post
|
58
|
+
when :patch, :post
|
217
59
|
client.send(via, href) do |req|
|
218
60
|
req.body = Oj.dump(args)
|
219
61
|
end
|
@@ -222,187 +64,5 @@ module TeamSnap
|
|
222
64
|
end
|
223
65
|
end
|
224
66
|
|
225
|
-
def parse_error(resp)
|
226
|
-
begin
|
227
|
-
Oj.load(resp.body)
|
228
|
-
.fetch(:collection)
|
229
|
-
.fetch(:error)
|
230
|
-
.fetch(:message)
|
231
|
-
rescue KeyError
|
232
|
-
resp.body
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
def load_items(collection)
|
237
|
-
collection
|
238
|
-
.fetch(:items) { [] }
|
239
|
-
.map { |item|
|
240
|
-
data = parse_data(item).merge(:href => item[:href])
|
241
|
-
type = type_of(item)
|
242
|
-
cls = load_class(type, data)
|
243
|
-
|
244
|
-
cls.new(data).tap { |obj|
|
245
|
-
obj.send(:load_links, item.fetch(:links) { [] })
|
246
|
-
}
|
247
|
-
}
|
248
|
-
end
|
249
|
-
|
250
|
-
def apply_endpoints(obj, collection)
|
251
|
-
collection
|
252
|
-
.fetch(:queries) { [] }
|
253
|
-
.each { |endpoint| register_endpoint(obj, endpoint, :via => :get) }
|
254
|
-
|
255
|
-
collection
|
256
|
-
.fetch(:commands) { [] }
|
257
|
-
.each { |endpoint| register_endpoint(obj, endpoint, :via => :post) }
|
258
|
-
end
|
259
|
-
|
260
|
-
private
|
261
|
-
|
262
|
-
attr_accessor :client
|
263
|
-
|
264
|
-
def classify_rel(link)
|
265
|
-
return if EXCLUDED_RELS.include?(link.fetch(:rel))
|
266
|
-
|
267
|
-
rel = link.fetch(:rel)
|
268
|
-
href = link.fetch(:href)
|
269
|
-
resp = client.get(href)
|
270
|
-
|
271
|
-
create_collection_class(rel, href, resp, nil)
|
272
|
-
end
|
273
|
-
|
274
|
-
def create_collection_class(rel, href, resp, collection)
|
275
|
-
name = Inflecto.classify(rel)
|
276
|
-
TeamSnap.const_set(
|
277
|
-
name, Class.new { include TeamSnap.collection(href, resp, collection) }
|
278
|
-
) unless TeamSnap.const_defined?(name, false)
|
279
|
-
end
|
280
|
-
|
281
|
-
def register_endpoint(obj, endpoint, opts)
|
282
|
-
rel = endpoint.fetch(:rel)
|
283
|
-
href = endpoint.fetch(:href)
|
284
|
-
valid_args = endpoint.fetch(:data) { [] }
|
285
|
-
.map { |datum| datum.fetch(:name).to_sym }
|
286
|
-
via = opts.fetch(:via)
|
287
|
-
|
288
|
-
obj.define_singleton_method(rel) do |*args|
|
289
|
-
args = Hash[*args]
|
290
|
-
|
291
|
-
unless args.all? { |arg, _| valid_args.include?(arg) }
|
292
|
-
raise ArgumentError.new(
|
293
|
-
"Invalid argument(s). Valid argument(s) are #{valid_args.inspect}"
|
294
|
-
)
|
295
|
-
end
|
296
|
-
|
297
|
-
TeamSnap.load_items(
|
298
|
-
TeamSnap.run(via, href, args)
|
299
|
-
)
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
def parse_data(item)
|
304
|
-
data = item
|
305
|
-
.fetch(:data)
|
306
|
-
.map { |datum|
|
307
|
-
name = datum.fetch(:name)
|
308
|
-
value = datum.fetch(:value)
|
309
|
-
type = datum.fetch(:type) { :default }
|
310
|
-
|
311
|
-
value = DateTime.parse(value) if value && type == "DateTime"
|
312
|
-
|
313
|
-
[name, value]
|
314
|
-
}
|
315
|
-
TeamSnap.hashify(data)
|
316
|
-
end
|
317
|
-
|
318
|
-
def type_of(item)
|
319
|
-
item
|
320
|
-
.fetch(:data)
|
321
|
-
.find { |datum| datum.fetch(:name) == "type" }
|
322
|
-
.fetch(:value)
|
323
|
-
end
|
324
|
-
|
325
|
-
def load_class(type, data)
|
326
|
-
TeamSnap.const_get(Inflecto.camelize(type), false).tap { |cls|
|
327
|
-
unless cls.include?(Virtus::Model::Core)
|
328
|
-
cls.class_eval do
|
329
|
-
include Virtus.value_object
|
330
|
-
|
331
|
-
values do
|
332
|
-
attribute :href, String
|
333
|
-
data.each { |name, value| attribute name, value.class }
|
334
|
-
end
|
335
|
-
end
|
336
|
-
end
|
337
|
-
}
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
module Item
|
342
|
-
private
|
343
|
-
|
344
|
-
def load_links(links)
|
345
|
-
links.each do |link|
|
346
|
-
next if EXCLUDED_RELS.include?(link.fetch(:rel))
|
347
|
-
|
348
|
-
rel = link.fetch(:rel)
|
349
|
-
href = link.fetch(:href)
|
350
|
-
is_singular = rel == Inflecto.singularize(rel)
|
351
|
-
|
352
|
-
define_singleton_method(rel) {
|
353
|
-
instance_variable_get("@#{rel}") || instance_variable_set(
|
354
|
-
"@#{rel}", -> {
|
355
|
-
coll = TeamSnap.load_items(
|
356
|
-
TeamSnap.run(:get, href)
|
357
|
-
)
|
358
|
-
is_singular ? coll.first : coll
|
359
|
-
}.call
|
360
|
-
)
|
361
|
-
}
|
362
|
-
end
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
module Collection
|
367
|
-
def href
|
368
|
-
self.instance_variable_get(:@href)
|
369
|
-
end
|
370
|
-
|
371
|
-
def resp
|
372
|
-
self.instance_variable_get(:@resp)
|
373
|
-
end
|
374
|
-
|
375
|
-
def parsed_collection
|
376
|
-
self.instance_variable_get(:@parsed_collection)
|
377
|
-
end
|
378
|
-
|
379
|
-
def parse_collection
|
380
|
-
if resp
|
381
|
-
if resp.status == 200
|
382
|
-
collection = Oj.load(resp.body)
|
383
|
-
.fetch(:collection) { [] }
|
384
|
-
else
|
385
|
-
error_message = TeamSnap.parse_error(resp)
|
386
|
-
raise TeamSnap::Error.new(error_message)
|
387
|
-
end
|
388
|
-
elsif parsed_collection
|
389
|
-
collection = parsed_collection
|
390
|
-
end
|
391
|
-
|
392
|
-
TeamSnap.apply_endpoints(self, collection)
|
393
|
-
enable_find if respond_to?(:search)
|
394
|
-
end
|
395
|
-
|
396
|
-
private
|
397
|
-
|
398
|
-
def enable_find
|
399
|
-
define_singleton_method(:find) do |id|
|
400
|
-
search(:id => id).first.tap do |object|
|
401
|
-
raise TeamSnap::NotFound.new(
|
402
|
-
"Could not find a #{self} with an id of '#{id}'."
|
403
|
-
) unless object
|
404
|
-
end
|
405
|
-
end
|
406
|
-
end
|
407
67
|
end
|
408
68
|
end
|