teamsnap_rb 1.3.3 → 2.0.0.beta
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 +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
|