Class: Kounta::REST::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/kounta/rest/client.rb

Instance Method Summary collapse

Constructor Details

#initialize(**options) ⇒ Client

Returns a new instance of Client.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 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

Instance Method Details

#authenticated?Boolean

Returns:

  • (Boolean)


26
27
28
# File 'lib/kounta/rest/client.rb', line 26

def authenticated?
  @access_token.present?
end

#company(hash = {}) ⇒ Object



44
45
46
# 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) ⇒ Object



161
162
163
164
165
# 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 = {}) ⇒ Object



30
31
32
33
34
# 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) ⇒ Object



36
37
38
39
40
41
42
# 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 = {}) ⇒ Object



89
90
91
92
# 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 = {}) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
# 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 = {}) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# 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) ⇒ Object



48
49
50
51
# 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 = {}) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 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