utapi 0.0.1
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 +7 -0
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +66 -0
- data/Rakefile +1 -0
- data/lib/faraday/error_handler.rb +40 -0
- data/lib/utapi.rb +6 -0
- data/lib/utapi/account.rb +7 -0
- data/lib/utapi/authorization.rb +7 -0
- data/lib/utapi/client.rb +149 -0
- data/lib/utapi/connection.rb +52 -0
- data/lib/utapi/exceptions.rb +20 -0
- data/lib/utapi/login_service.rb +141 -0
- data/lib/utapi/persona.rb +7 -0
- data/lib/utapi/util.rb +5 -0
- data/lib/utapi/version.rb +3 -0
- data/spec/client_spec.rb +23 -0
- data/spec/login_service_spec.rb +29 -0
- data/spec/spec_helper.rb +18 -0
- data/utapi.gemspec +35 -0
- metadata +236 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 918543a3d5824f1f6a853a55cb907a2a4c104a12
|
4
|
+
data.tar.gz: fdf9a795faddcaa22d2ebe7dfbb76c7360f4f684
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bbbab1563cd57f25b76675028634476a246992eff6ce34697d0ca6da1e3892d3eb717621f4d65765e37b6ffbaab6aa73bfad780e3a01f8e4365e2e410101548e
|
7
|
+
data.tar.gz: 5ba150f13bf9d25e2582a3a1e8df6580979442f27e70e27a3cb3ff47b140fca57dfd0e4341105af110195c15f6897495a4c57f5ba1aee6874b202cde6aacd892
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Cameron Martin
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# UTApi
|
2
|
+
|
3
|
+
A thin api in ruby for ultimate team. It handles logging in, retrying requests, and http errors.
|
4
|
+
All the api calls (see below) return a hash which is just the json returned by that request
|
5
|
+
(I said it was thin).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'utapi'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install utapi
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
client = UTApi::Client.new(email, password, hash, platform)
|
25
|
+
client.login # true
|
26
|
+
client.credits
|
27
|
+
|
28
|
+
# {
|
29
|
+
# 'credits' => 16659,
|
30
|
+
# 'currencies' => [
|
31
|
+
# { 'name' => 'COINS', 'funds' => 16659, 'finalFunds' => 16659 },
|
32
|
+
# { 'name' => 'POINTS', 'funds' => 0, 'finalFunds' => 0 }
|
33
|
+
# ],
|
34
|
+
# 'unopenedPacks' => {
|
35
|
+
# 'preOrderPacks' => 0,
|
36
|
+
# 'recoveredPacks' => 0
|
37
|
+
# },
|
38
|
+
# 'bidTokens' => {}
|
39
|
+
# }
|
40
|
+
|
41
|
+
```
|
42
|
+
|
43
|
+
### Api Methods
|
44
|
+
|
45
|
+
* search(params)
|
46
|
+
* auction_status(ids)
|
47
|
+
* bid(trade_id, value)
|
48
|
+
* list_item(item_id, start_price, bin_price, duration)
|
49
|
+
* move_card(item_id, pile)
|
50
|
+
* trade_pile
|
51
|
+
* watch_list
|
52
|
+
* unassigned_items
|
53
|
+
* delete_from_trade_pile(trade_id)
|
54
|
+
* delete_from_watch_list(trade_id1, trade_id2, ...)
|
55
|
+
* get_credits
|
56
|
+
|
57
|
+
If you need more adding, just open an issue.
|
58
|
+
|
59
|
+
|
60
|
+
## Contributing
|
61
|
+
|
62
|
+
1. Fork it
|
63
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
64
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
65
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
66
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'utapi/exceptions'
|
3
|
+
|
4
|
+
module Faraday
|
5
|
+
class ErrorHandler < Middleware
|
6
|
+
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
|
10
|
+
begin
|
11
|
+
response = @app.call(env)
|
12
|
+
rescue Net::ReadTimeout, Errno::ETIMEDOUT, Timeout::Error, Faraday::Error::TimeoutError => e # Timeout Errors
|
13
|
+
raise UTApi::ConnectionError.new(e, response_values(env))
|
14
|
+
end
|
15
|
+
|
16
|
+
response.on_complete do |env|
|
17
|
+
handle_return_errors(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle_return_errors(env)
|
23
|
+
case env[:status]
|
24
|
+
when 302, 200, 461
|
25
|
+
# Let them pass through
|
26
|
+
when 401
|
27
|
+
raise UTApi::NotLoggedInError, response_values(env)
|
28
|
+
else
|
29
|
+
raise UTApi::ServerError, response_values(env)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def response_values(env)
|
34
|
+
{:status => env.status, :headers => env.response_headers, :body => env.body}
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Faraday::Middleware.register_middleware(:error_handler => Faraday::ErrorHandler)
|
data/lib/utapi.rb
ADDED
data/lib/utapi/client.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# Provides the public interface for the api
|
2
|
+
|
3
|
+
require 'utapi/exceptions'
|
4
|
+
require 'utapi/connection'
|
5
|
+
require 'utapi/login_service'
|
6
|
+
require 'utapi/account'
|
7
|
+
require 'utapi/util'
|
8
|
+
|
9
|
+
module UTApi
|
10
|
+
class Client
|
11
|
+
|
12
|
+
attr_reader :logged_in
|
13
|
+
|
14
|
+
def initialize(email, password, hash, platform)
|
15
|
+
@account = Account.new(email: email, password: password, hash: hash, platform: platform)
|
16
|
+
@logged_in = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def login
|
20
|
+
@authorization = generate_authorization
|
21
|
+
rescue LoginError
|
22
|
+
false
|
23
|
+
else
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def search(params)
|
28
|
+
|
29
|
+
action = 'transfermarket?' + Util.encode_query_string(params)
|
30
|
+
|
31
|
+
do_request(action).tap do |response|
|
32
|
+
raise ApiCallFailed, "response has no auctionInfo: #{response}" unless response.is_a?(Hash) and response.has_key?('auctionInfo')
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def auction_status(ids)
|
38
|
+
|
39
|
+
action = 'trade/status?' + Util.encode_query_string(tradeIds: ids.join(','))
|
40
|
+
|
41
|
+
do_request(action).tap do |response|
|
42
|
+
raise ApiCallFailed, "response has no auctionInfo: #{response}" unless response.is_a?(Hash) and response.has_key?('auctionInfo')
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def bid(trade_id, value)
|
48
|
+
response = do_request("trade/#{trade_id}/bid", :put, {bid: value})
|
49
|
+
response.is_a?(Hash) and response.has_key?('auctionInfo')
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def list_item(item_id, start_price, bin_price, duration)
|
54
|
+
|
55
|
+
response = do_request('auctionhouse', :post, {
|
56
|
+
startingBid: start_price,
|
57
|
+
duration: duration,
|
58
|
+
itemData: {
|
59
|
+
id: item_id
|
60
|
+
},
|
61
|
+
buyNowPrice: bin_price
|
62
|
+
})
|
63
|
+
|
64
|
+
response.is_a?(Hash) and response.has_key?('id')
|
65
|
+
end
|
66
|
+
|
67
|
+
def move_card(item_id, pile)
|
68
|
+
|
69
|
+
response = do_request('item', :put, {
|
70
|
+
itemData: [{ id: item_id, pile: pile }]
|
71
|
+
})
|
72
|
+
|
73
|
+
response.is_a?(Hash) and response.has_key?('itemData') and response['itemData'][0]['success']
|
74
|
+
end
|
75
|
+
|
76
|
+
def trade_pile
|
77
|
+
do_request('tradepile', :get).tap do |response|
|
78
|
+
raise ApiCallFailed, "Cannot get trade pile, response: #{response}" unless response.is_a?(Hash) and response.has_key?('auctionInfo')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def watch_list
|
83
|
+
do_request('watchlist', :get)
|
84
|
+
end
|
85
|
+
|
86
|
+
def unassigned_items
|
87
|
+
do_request('purchased/items', :get)
|
88
|
+
end
|
89
|
+
|
90
|
+
def delete_from_trade_pile(trade_id)
|
91
|
+
do_request("trade/#{trade_id}", :delete)
|
92
|
+
end
|
93
|
+
|
94
|
+
def delete_from_watch_list(*trade_ids)
|
95
|
+
action = 'watchlist?' + Util.encode_query_string(tradeId: trade_ids.join(','))
|
96
|
+
do_request(action, :delete)
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_credits
|
100
|
+
do_request('user/credits')
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def do_request(action, verb=:get, payload=nil)
|
106
|
+
|
107
|
+
retried = false
|
108
|
+
|
109
|
+
begin
|
110
|
+
|
111
|
+
headers = {
|
112
|
+
'Content-Type' => 'application/json',
|
113
|
+
'X-HTTP-Method-Override' => verb.to_s.upcase,
|
114
|
+
'X-UT-PHISHING-TOKEN' => authorization.phishing_token,
|
115
|
+
'X-UT-SID' => authorization.sid
|
116
|
+
}
|
117
|
+
|
118
|
+
response = connection.post("#{authorization.server}/ut/game/fifa14/#{action}", payload, headers)
|
119
|
+
rescue NotLoggedInError
|
120
|
+
@logged_in = false
|
121
|
+
if !retried && login
|
122
|
+
retried = true
|
123
|
+
retry
|
124
|
+
else
|
125
|
+
raise
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
response.env[:body]
|
130
|
+
end
|
131
|
+
|
132
|
+
# REVIEW: LoginError can leak out if login is not explicitly called
|
133
|
+
|
134
|
+
def authorization
|
135
|
+
@authorization ||= generate_authorization
|
136
|
+
end
|
137
|
+
|
138
|
+
def generate_authorization
|
139
|
+
LoginService.new(@account).execute.tap do |*|
|
140
|
+
@logged_in = true
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def connection
|
145
|
+
@connection ||= Connection.new
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'faraday-cookie_jar'
|
4
|
+
require 'faraday-rate_limiter'
|
5
|
+
require 'faraday/error_handler'
|
6
|
+
|
7
|
+
module UTApi
|
8
|
+
class Connection
|
9
|
+
|
10
|
+
attr_writer :cookie_jar
|
11
|
+
attr_writer :request_interval
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@user_agent = 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)'
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO: Define a better interface for these function
|
18
|
+
def get(*args, &block)
|
19
|
+
connection.get(*args, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def post(*args, &block)
|
23
|
+
connection.post(*args, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def cookie_jar
|
27
|
+
@cookie_jar ||= HTTP::CookieJar.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def request_interval
|
31
|
+
@request_interval ||= 2
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def connection
|
37
|
+
@connection ||= Faraday.new(ssl: {verify: false}, request: {timeout: 20, open_timeout: 20}, headers: { 'User-Agent' => @user_agent }) do |faraday|
|
38
|
+
faraday.response :follow_redirects, limit: 5
|
39
|
+
#faraday.response :raise_error # This catches generic http errors
|
40
|
+
faraday.request :retry, exceptions: [UTApi::ConnectionError, UTApi::ServerError], interval: 1, backoff_factor: 2, max: 3
|
41
|
+
faraday.use :error_handler # This is custom error handling
|
42
|
+
faraday.use :cookie_jar, jar: cookie_jar
|
43
|
+
faraday.request :url_encoded
|
44
|
+
faraday.request :json
|
45
|
+
faraday.response :json, content_type: 'application/json'
|
46
|
+
faraday.request :rate_limiter, interval: request_interval if request_interval > 0
|
47
|
+
faraday.adapter :net_http_persistent
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module UTApi
|
2
|
+
class NotLoggedInError < RuntimeError; end # Raised when the client is not logged in/the session has expired
|
3
|
+
class LoginError < RuntimeError; end # Raised when there is an error logging in
|
4
|
+
class ServerError < RuntimeError; end # Raised when the server returns something strange
|
5
|
+
class ApiCallFailed < RuntimeError; end
|
6
|
+
|
7
|
+
class ConnectionError < RuntimeError # Raised when we cannot connect to the server (timeouts mainly)
|
8
|
+
attr_reader :wrapped_exception
|
9
|
+
|
10
|
+
def initialize(wrapped_exception, *args, &block)
|
11
|
+
@wrapped_exception = wrapped_exception
|
12
|
+
super(*args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"#{@wrapped_exception.class}: #{super}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'utapi/authorization'
|
2
|
+
require 'utapi/persona'
|
3
|
+
require 'utapi/exceptions'
|
4
|
+
require 'utapi/connection'
|
5
|
+
|
6
|
+
# Returns a new instance of Authorization
|
7
|
+
|
8
|
+
# TODO: Do something with this, its a bit messy.
|
9
|
+
module UTApi
|
10
|
+
class LoginService
|
11
|
+
|
12
|
+
def initialize(account)
|
13
|
+
@account = account
|
14
|
+
|
15
|
+
@connection = Connection.new
|
16
|
+
@connection.request_interval = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def execute
|
21
|
+
@nucleus_user_id = do_initial_login
|
22
|
+
do_futweb_cookie_stage
|
23
|
+
@server = get_server
|
24
|
+
@persona = get_account_info
|
25
|
+
@sid = get_sid
|
26
|
+
@phishing_token = get_phishing_token
|
27
|
+
|
28
|
+
Authorization.new(server: @server, phishing_token: @phishing_token, sid: @sid)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def require_instance_variables(*vars)
|
34
|
+
vars.map!(&:to_s)
|
35
|
+
unless vars.all? { |var| instance_variable_defined?("@#{var}") }
|
36
|
+
raise "Required instance variables #{vars.join(', ')} not set"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def generate_headers(*fields)
|
41
|
+
{}.tap do |headers|
|
42
|
+
headers['Easw-Session-Data-Nucleus-Id'] = @nucleus_user_id.to_s if fields.include?(:nuc)
|
43
|
+
headers['X-UT-Route'] = @server || 'https://utas.fut.ea.com' if fields.include?(:route)
|
44
|
+
headers['X-UT-SID'] = @sid if fields.include?(:sid)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns nucleus user id
|
49
|
+
def do_initial_login
|
50
|
+
response = @connection.get 'http://www.easports.com/fifa/football-club/ultimate-team'
|
51
|
+
|
52
|
+
r2 = @connection.post(
|
53
|
+
response.env[:url],
|
54
|
+
{email: @account.email, password: @account.password, rememberMe: 'on', _rememberMe: 'on', _eventId: 'submit', facebookAuth: ''},
|
55
|
+
{referer: response.env[:url].to_s}
|
56
|
+
)
|
57
|
+
|
58
|
+
extract_nucleus_user_id(r2.env[:body])
|
59
|
+
end
|
60
|
+
|
61
|
+
def extract_nucleus_user_id(body)
|
62
|
+
nucleus_user_id = body.match /userid : "(\d+)"/
|
63
|
+
raise LoginError, 'Cannot get nucleus user id' if nucleus_user_id.nil? or nucleus_user_id[1].to_i == 0
|
64
|
+
nucleus_user_id[1].to_i
|
65
|
+
end
|
66
|
+
|
67
|
+
def do_futweb_cookie_stage
|
68
|
+
@connection.get('http://www.easports.com/iframe/fut/', {
|
69
|
+
locale: 'en_GB',
|
70
|
+
baseShowoffUrl: 'http://www.easports.com/uk/fifa/football-club/ultimate-team/show-off',
|
71
|
+
guest_app_uri:'http://www.easports.com/uk/fifa/football-club/ultimate-team'
|
72
|
+
})
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_server
|
76
|
+
# REVIEW: Do we need to send the route here?
|
77
|
+
require_instance_variables :nucleus_user_id
|
78
|
+
|
79
|
+
shards = @connection.get('http://www.easports.com/iframe/fut/p/ut/shards', {}, generate_headers(:nuc, :route))
|
80
|
+
|
81
|
+
shard = shards.env[:body]['shardInfo'].find do |shard|
|
82
|
+
shard['platforms'].include?(@account.platform.to_s)
|
83
|
+
end
|
84
|
+
|
85
|
+
raise LoginError, 'Could not find the server' if shard.nil?
|
86
|
+
|
87
|
+
"#{shard['clientProtocol']}://#{shard['clientFacingIpPort']}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def get_account_info
|
91
|
+
require_instance_variables :server, :nucleus_user_id
|
92
|
+
|
93
|
+
account_info = @connection.get('http://www.easports.com/iframe/fut/p/ut/game/fifa14/user/accountinfo', {}, generate_headers(:nuc, :route))
|
94
|
+
|
95
|
+
raise LoginError, "Could not get account info: #{account_info}" unless account_info.env[:body].is_a?(Hash)
|
96
|
+
|
97
|
+
persona = account_info.env[:body]['userAccountInfo']['personas'][0]
|
98
|
+
|
99
|
+
Persona.new(persona_id: persona['personaId'], persona_name: persona['personaName'])
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_sid
|
103
|
+
require_instance_variables :persona, :nucleus_user_id, :server
|
104
|
+
|
105
|
+
payload = {
|
106
|
+
isReadOnly: false,
|
107
|
+
sku: 'FUT14IOS',
|
108
|
+
clientVersion: 8,
|
109
|
+
#sku: 'FUT14WEB',
|
110
|
+
#clientVersion: 1,
|
111
|
+
nuc: @nucleus_user_id,
|
112
|
+
nucleusPersonaId: @persona.persona_id,
|
113
|
+
nucleusPersonaDisplayName: @persona.persona_name,
|
114
|
+
#nucleusPersonaPlatform: 'ps3', # 360 or ps3 REVIEW: Where do these come from? and is it needed?
|
115
|
+
locale: 'en-GB',
|
116
|
+
method: 'authcode',
|
117
|
+
priorityLevel: 4,
|
118
|
+
identification: { authCode: '' }
|
119
|
+
}
|
120
|
+
|
121
|
+
headers = generate_headers(:nuc, :route).merge({'Content-Type' => 'application/json'})
|
122
|
+
|
123
|
+
auth = @connection.post('http://www.easports.com/iframe/fut/p/ut/auth', payload, headers)
|
124
|
+
|
125
|
+
auth.env[:body]['sid']
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
def get_phishing_token
|
130
|
+
|
131
|
+
payload = { answer: @account.hash }
|
132
|
+
|
133
|
+
response = @connection.post('http://www.easports.com/iframe/fut/p/ut/game/fifa14/phishing/validate', payload, generate_headers(:nuc, :route, :sid))
|
134
|
+
|
135
|
+
# This must be parsed manually, because the content-type sent isn't right!
|
136
|
+
JSON.parse(response.env[:body])['token']
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
data/lib/utapi/util.rb
ADDED
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'utapi/client'
|
4
|
+
|
5
|
+
describe UTApi::Client, vcr: { cassette_name: 'requests' } do
|
6
|
+
|
7
|
+
subject(:client) do
|
8
|
+
UTApi::Client.new(
|
9
|
+
ENV['TEST_ACCOUNT_EMAIL'],
|
10
|
+
ENV['TEST_ACCOUNT_PASSWORD'],
|
11
|
+
ENV['TEST_ACCOUNT_HASH'],
|
12
|
+
ENV['TEST_ACCOUNT_PLATFORM']
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#get_credits' do
|
17
|
+
it 'should return credits' do
|
18
|
+
response = client.get_credits
|
19
|
+
|
20
|
+
expect(response['credits']).to be_kind_of(Integer)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'utapi/login_service'
|
4
|
+
require 'utapi/connection'
|
5
|
+
require 'utapi/account'
|
6
|
+
|
7
|
+
describe UTApi::LoginService, vcr: { cassette_name: 'requests' } do
|
8
|
+
|
9
|
+
let(:account) do
|
10
|
+
UTApi::Account.new(
|
11
|
+
email: ENV['TEST_ACCOUNT_EMAIL'],
|
12
|
+
password: ENV['TEST_ACCOUNT_PASSWORD'],
|
13
|
+
hash: ENV['TEST_ACCOUNT_HASH'],
|
14
|
+
platform: ENV['TEST_ACCOUNT_PLATFORM']
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:login_service) { UTApi::LoginService.new(account) }
|
19
|
+
|
20
|
+
describe '#execute' do
|
21
|
+
it 'does not raise error' do
|
22
|
+
expect { login_service.execute }.to_not raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns Authorization instance' do
|
26
|
+
expect(login_service.execute).to be_a(UTApi::Authorization)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'vcr'
|
5
|
+
require 'dotenv'
|
6
|
+
|
7
|
+
Dotenv.load
|
8
|
+
|
9
|
+
VCR.configure do |c|
|
10
|
+
c.cassette_library_dir = 'spec/cassettes'
|
11
|
+
c.hook_into :webmock
|
12
|
+
c.configure_rspec_metadata!
|
13
|
+
end
|
14
|
+
|
15
|
+
#require 'net-http-spy'
|
16
|
+
#
|
17
|
+
#Net::HTTP.http_logger = Logger.new(File.expand_path("../tmp/logs/login-#{Time.now}.log", File.dirname(__FILE__)))
|
18
|
+
#Net::HTTP.http_logger_options = { verbose: true }
|
data/utapi.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'utapi/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'utapi'
|
8
|
+
spec.version = UTApi::VERSION
|
9
|
+
spec.authors = ['Cameron Martin']
|
10
|
+
spec.email = ['cameronmartin123@gmail.com']
|
11
|
+
spec.description = %q{FIFA 14 Ultimate Team api in Ruby}
|
12
|
+
spec.summary = spec.description
|
13
|
+
spec.homepage = 'https://github.com/cameron-martin/utapi'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
24
|
+
spec.add_development_dependency 'vcr'
|
25
|
+
spec.add_development_dependency 'webmock'
|
26
|
+
spec.add_development_dependency 'dotenv'
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'faraday', '~> 0.9.0'
|
29
|
+
spec.add_runtime_dependency 'faraday_middleware', '~> 0.9.0'
|
30
|
+
spec.add_runtime_dependency 'faraday-cookie_jar'
|
31
|
+
spec.add_runtime_dependency 'faraday-rate_limiter'
|
32
|
+
|
33
|
+
spec.add_runtime_dependency 'net-http-persistent'
|
34
|
+
spec.add_runtime_dependency 'rattributes'
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,236 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: utapi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cameron Martin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: vcr
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: dotenv
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: faraday
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.9.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.9.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: faraday_middleware
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.9.0
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ~>
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.9.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: faraday-cookie_jar
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: faraday-rate_limiter
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: net-http-persistent
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - '>='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: rattributes
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - '>='
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
description: FIFA 14 Ultimate Team api in Ruby
|
182
|
+
email:
|
183
|
+
- cameronmartin123@gmail.com
|
184
|
+
executables: []
|
185
|
+
extensions: []
|
186
|
+
extra_rdoc_files: []
|
187
|
+
files:
|
188
|
+
- .gitignore
|
189
|
+
- Gemfile
|
190
|
+
- LICENSE.txt
|
191
|
+
- README.md
|
192
|
+
- Rakefile
|
193
|
+
- lib/faraday/error_handler.rb
|
194
|
+
- lib/utapi.rb
|
195
|
+
- lib/utapi/account.rb
|
196
|
+
- lib/utapi/authorization.rb
|
197
|
+
- lib/utapi/client.rb
|
198
|
+
- lib/utapi/connection.rb
|
199
|
+
- lib/utapi/exceptions.rb
|
200
|
+
- lib/utapi/login_service.rb
|
201
|
+
- lib/utapi/persona.rb
|
202
|
+
- lib/utapi/util.rb
|
203
|
+
- lib/utapi/version.rb
|
204
|
+
- spec/client_spec.rb
|
205
|
+
- spec/login_service_spec.rb
|
206
|
+
- spec/spec_helper.rb
|
207
|
+
- utapi.gemspec
|
208
|
+
homepage: https://github.com/cameron-martin/utapi
|
209
|
+
licenses:
|
210
|
+
- MIT
|
211
|
+
metadata: {}
|
212
|
+
post_install_message:
|
213
|
+
rdoc_options: []
|
214
|
+
require_paths:
|
215
|
+
- lib
|
216
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
217
|
+
requirements:
|
218
|
+
- - '>='
|
219
|
+
- !ruby/object:Gem::Version
|
220
|
+
version: '0'
|
221
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
222
|
+
requirements:
|
223
|
+
- - '>='
|
224
|
+
- !ruby/object:Gem::Version
|
225
|
+
version: '0'
|
226
|
+
requirements: []
|
227
|
+
rubyforge_project:
|
228
|
+
rubygems_version: 2.2.1
|
229
|
+
signing_key:
|
230
|
+
specification_version: 4
|
231
|
+
summary: FIFA 14 Ultimate Team api in Ruby
|
232
|
+
test_files:
|
233
|
+
- spec/client_spec.rb
|
234
|
+
- spec/login_service_spec.rb
|
235
|
+
- spec/spec_helper.rb
|
236
|
+
has_rdoc:
|