class Kounta::REST::Client

Public Class Methods

new(**options) click to toggle source
# File lib/kounta/rest/client.rb, line 8
def initialize(**options)
  @redirect_uri         = options[:redirect_uri]
  @consumer             = options[:consumer]
  @access_token         = options[:access_token]
  @refresh_token        = options[:refresh_token]
  @client               = OAuth2::Client.new(
    @consumer[:key], @consumer[:secret],
    site: Kounta::SITE_URI,
    authorize_url: Kounta::AUTHORIZATION_URI,
    token_url: Kounta::TOKEN_URI
  ) do |faraday|
    faraday.request :json
    faraday.use Faraday::Request::UrlEncoded
    faraday.use Faraday::Response::Logger if Kounta.enable_logging
    faraday.adapter Faraday.default_adapter
  end
end

Public Instance Methods

authenticated?() click to toggle source
# File lib/kounta/rest/client.rb, line 26
def authenticated?
  @access_token.present?
end
company(hash = {}) click to toggle source
# File lib/kounta/rest/client.rb, line 44
def company(hash = {})
  @company ||= Kounta::Company.new(self, hash)
end
filter_responses_in_date_range(parsed_responses, start, finish) click to toggle source
# File lib/kounta/rest/client.rb, line 161
def filter_responses_in_date_range(parsed_responses, start, finish)
  start_index = parsed_responses.index { |response| response['created_at_epoch'] >= start } || parsed_responses.length - 1
  finish_index = parsed_responses.rindex { |response| response['created_at_epoch'] <= finish } || 0
  parsed_responses[start_index..finish_index]
end
get_access_code_url(params = {}) click to toggle source
# File lib/kounta/rest/client.rb, line 30
def get_access_code_url(params = {})
  # Kounta's API seems to require the `state` param (can't find documentation on it anywhere)
  # learn more about it: http://homakov.blogspot.com.au/2012/07/saferweb-most-common-oauth2.html
  @client.auth_code.authorize_url(params.merge(redirect_uri: @redirect_uri, state: SecureRandom.hex(24)))
end
get_access_token(access_code) click to toggle source
# File lib/kounta/rest/client.rb, line 36
def get_access_token(access_code)
  @token = @client.auth_code.get_token(access_code, redirect_uri: @redirect_uri)
  @access_token = @token.token
  @expires_at = @token.expires_at
  @refresh_token = @token.refresh_token
  @token
end
object_from_response(klass, request_method, url_hash, options = {}) click to toggle source
# File lib/kounta/rest/client.rb, line 89
def object_from_response(klass, request_method, url_hash, options = {})
  response = perform(url_hash, request_method, options)
  klass.new(response.parsed)
end
objects_from_response(klass, request_method, url_hash, options = {}) click to toggle source
# File lib/kounta/rest/client.rb, line 75
def objects_from_response(klass, request_method, url_hash, options = {})
  response = perform(url_hash, request_method, options)
  last_page = response.headers['x-pages'].to_i - 1
  results = response.parsed

  # Already got page 0, start at page 1
  (1..last_page).each do |page_number|
    response = perform(url_hash, request_method, options.merge!(headers: { 'X-Page' => page_number.to_s }))
    results += response.parsed
  end

  results.map { |item| klass.new(item) }
end
objects_from_response_in_time_range(klass, request_method, url_hash, options = {}) click to toggle source
# File lib/kounta/rest/client.rb, line 94
def objects_from_response_in_time_range(klass, request_method, url_hash, options = {})
  if options.key?(:params) && (options[:params].key?(:created_gte) ^ options[:params].key?(:created_gt)) &&
     (options[:params].key?(:created_lte) ^ options[:params].key?(:created_lt))
    params = options[:params]
    start_equal = params.key?(:created_gte)
    finish_equal = params.key?(:created_lte)
    start = (start_equal ? params[:created_gte] : params[:created_gt]).to_time
    finish = (finish_equal ? params[:created_lte] : params[:created_lt]).to_time

    params.except!(:created_gte, :created_gt, :created_lte, :created_lt)

    start_date = start.to_date
    finish_date = finish.to_date

    start = start.to_i
    finish = finish.to_i

    results = []

    options[:params] = params.merge(created_gte: start_date, created_lte: finish_date)
    response = perform(url_hash, request_method, options)
    last_page = response.headers['x-pages'].to_i - 1
    parsed = response.parsed.map do |o|
      o['created_at_epoch'] = Time.parse(o['created_at']).to_i
      o
    end

    response_start = parsed.last['created_at_epoch']
    response_finish = parsed.first['created_at_epoch']

    # all current and future responses will be before the required start
    return results if response_finish < start

    # reverse to order them in ascending order
    results += filter_responses_in_date_range(parsed.reverse, start, finish)

    # all future responses will be before the required start
    return results if response_start < start

    (1..last_page).each do |page_number|
      response = perform(url_hash, request_method, options.merge!(headers: { 'X-Page' => page_number.to_s }))
      parsed = response.parsed.map do |o|
        o['created_at_epoch'] = Time.parse(o['created_at']).to_i
        o
      end

      response_start = parsed.last['created_at_epoch']
      response_finish = parsed.first['created_at_epoch']

      # all current and future responses will be before the required start
      break if response_finish < start

      # reverse to order them in ascending order
      results += filter_responses_in_date_range(parsed.reverse, start, finish)

      # all future responses will be before the required start
      break if response_start < start
    end

    # reverse to under reverses used to order them in ascending order
    results.reverse.map { |item| klass.new(item) }
  else
    raise ArgumentError, 'url_has must contain exactly one of [:created_gte, :created_gt] ' \
                         'and exactly one of [:created_lte, :created_lt]'
  end
end
path_from_hash(url_hash) click to toggle source
# File lib/kounta/rest/client.rb, line 48
def path_from_hash(url_hash)
  # TODO: there's probably a more correct way of doing this encoding
  url_hash.map { |key, value| value ? "#{key}/#{value.to_s.gsub('-', '%2D')}" : key.to_s }.join('/')
end
perform(url_hash, request_method, options = {}) click to toggle source
# File lib/kounta/rest/client.rb, line 53
def perform(url_hash, request_method, options = {})
  begin
    response = if url_hash.is_a? Hash
                 oauth_connection.request(request_method, "#{path_from_hash(url_hash)}.#{FORMAT}", options)
               else
                 oauth_connection.request(request_method, url_hash, options)
               end
  rescue Exception => ex # rubocop:disable Lint/RescueException
    msg = ex.message
    if !msg.nil? && (msg.include?('The access token provided has expired') || msg.include?('expired') || msg.include?('invalid'))
      @oauth_connection = refreshed_token
      retry
    end

    raise Kounta::Errors::RequestError, response.nil? ? 'Unknown Status' : response.status
  end

  raise Kounta::Errors::RequestError, 'Unknown Status' unless response

  response
end

Private Instance Methods

oauth_connection() click to toggle source
# File lib/kounta/rest/client.rb, line 169
def oauth_connection
  @oauth_connection ||= if @refresh_token
                          OAuth2::AccessToken.new(@client, @access_token, refresh_token: @refresh_token).refresh!
                        else
                          OAuth2::AccessToken.new(@client, @access_token)
                        end
end
refreshed_token() click to toggle source
# File lib/kounta/rest/client.rb, line 177
def refreshed_token
  OAuth2::AccessToken.from_hash(@client, refresh_token: @refresh_token).refresh!
end