lib/attune/client.rb in attune-0.0.3 vs lib/attune/client.rb in attune-0.0.4
- old
+ new
@@ -5,10 +5,16 @@
def initialize(message="Attune library disabled though config")
super(message)
end
end
+ class AuthenticationException < Faraday::Error::ClientError
+ def initialize(message="Authentication credentials not accepted")
+ super(message)
+ end
+ end
+
class Client
include Attune::Configurable
# Initializes a new Client
#
@@ -17,17 +23,48 @@
# endpoint: "http://example.com:8080/",
# timeout: 10
# )
#
# @param [Hash] options Options for connection (see Attune::Configurable)
- # @returns A new client object
+ # @return A new client object
def initialize(options={})
Attune::Configurable::KEYS.each do |key|
send("#{key}=", options[key] || Attune::Default.send(key))
end
end
+ # Request an auth token
+ #
+ # @example Generate a new auth token
+ # token = client.get_auth_token("client id", "secret")
+ # @param [String] client_id The client identifier.
+ # @param [String] client_secret The secret key for the client.
+ # @return An auth token if credentials accepted
+ # @raise [ArgumentError] if client_id or client_secret is not provided
+ # @raise [AuthenticationException] if client_id or client_secret are not accepted
+ # @raise [Faraday::Error::ClientError] if the request fails or exceeds the timeout
+ def get_auth_token(client_id, client_secret)
+ raise ArgumentError, "client_id required" unless client_id
+ raise ArgumentError, "client_secret required" unless client_secret
+
+ response = post_form("oauth/token",
+ client_id: client_id,
+ client_secret: client_secret,
+ grant_type: :client_credentials
+ )
+ if response
+ body = JSON.parse(response.body)
+ if body['error']
+ raise AuthenticationException, body['error_description']
+ end
+ body['access_token']
+ else
+ # Return a new UUID if there was an exception and we're in mock mode
+ SecureRandom.uuid
+ end
+ end
+
# Create an anonymous tracked user
#
# @example Generate a new id (preferred)
# anonymous_id = client.create_anonymous(
# user_agent: 'Mozilla/5.0'
@@ -41,17 +78,18 @@
# @option options [String] :id optional. An id will be generated if this is not provided
# @option options [String] :user_agent The user agent for the application used by the anonymous users
# @return id [String]
# @raise [ArgumentError] if user_agent is not provided
# @raise [Faraday::Error::ClientError] if the request fails or exceeds the timeout
+ # @raise [AuthenticationException] if authorization header not accepted
def create_anonymous(options)
raise ArgumentError, "user_agent required" unless options[:user_agent]
if id = options[:id]
put("anonymous/#{id}", {user_agent: options[:user_agent]})
id
else
- if response = post("anonymous", {user_agent: options[:user_agent]})
+ if response = post_json("anonymous", {user_agent: options[:user_agent]})
response[:location][/\Aurn:id:([a-z0-9\-]+)\Z/, 1]
else
# Return a new UUID if there was an exception and we're in mock mode
SecureRandom.uuid
end
@@ -75,10 +113,11 @@
# @option options [String] :ip ip address of remote user. Used for geolocation (optional)
# @option options [String] :customer id of customer (optional)
# @return ranking [Array<String>] The entities in their ranked order
# @raise [ArgumentError] if required parameters are missing
# @raise [Faraday::Error::ClientError] if the request fails or exceeds the timeout
+ # @raise [AuthenticationException] if authorization header not accepted
def get_rankings(options)
qs = encoded_ranking_params(options)
if response = get("rankings/#{qs}", customer: options.fetch(:customer, 'none'))
JSON.parse(response.body)['ranking']
else
@@ -105,10 +144,11 @@
# }
# ])
# @param [Array<Hash>] multi_options An array of options (see #get_rankings)
# @return [Array<Array<String>>] rankings
# @raise [Faraday::Error::ClientError] if the request fails or exceeds the timeout
+ # @raise [AuthenticationException] if authorization header not accepted
def multi_get_rankings(multi_options)
requests = multi_options.map do |options|
encoded_ranking_params(options)
end
if response = get("rankings", ids: requests)
@@ -137,10 +177,11 @@
# rankings = client.bind(
# '25892e17-80f6-415f-9c65-7395632f022',
# 'cd171f7c-560d-4a62-8d65-16b87419a58'
# )
# @raise [Faraday::Error::ClientError] if the request fails or exceeds the timeout
+ # @raise [AuthenticationException] if authorization header not accepted
def bind(id, customer_id)
put("bindings/anonymous=#{id}&customer=#{customer_id}")
true
end
@@ -166,25 +207,41 @@
adapter.put(path, ::JSON.dump(params))
rescue Faraday::Error::ClientError => e
handle_exception(e)
end
- def post(path, params={})
- adapter.post(path, ::JSON.dump(params))
+ def post_form(path, params={})
+ adapter.post(path, params)
rescue Faraday::Error::ClientError => e
handle_exception(e)
end
+ def post_json(path, params={})
+ adapter.post do |req|
+ req.url path
+ req.headers['Content-Type'] = 'application/json'
+ req.body = ::JSON.dump(params)
+ end
+ rescue Faraday::Error::ClientError => e
+ handle_exception(e)
+ end
+
def handle_exception e
if exception_handler == :mock
nil
else
- raise e
+ if e.response && e.response[:status] == 401
+ raise AuthenticationException, e
+ else
+ raise e
+ end
end
end
def adapter
raise DisabledException if disabled?
- Faraday.new(url: endpoint, builder: middleware, request: {timeout: timeout})
+ conn = Faraday.new(url: endpoint, builder: middleware, request: {timeout: timeout})
+ conn.authorization :Bearer, auth_token unless !auth_token
+ conn
end
end
end