Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DONUT MERGE] refresh app_access_token when expired #102

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions lib/funky/connections/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module Funky
module Connection
class API < Base
def self.fetch_all(path_query)
uri = URI "https://#{host}/v2.9/#{path_query}&limit=100&access_token=#{app_id}%7C#{app_secret}"
uri = URI "https://#{host}/v2.9/#{path_query}&limit=100"
fetch_data_with_paging_token(uri)
end

Expand All @@ -24,7 +24,7 @@ def self.fetch_data_with_paging_token(uri)
end

def self.fetch(path_query, is_array: false)
uri = URI "https://#{host}/v2.8/#{path_query}&limit=100&access_token=#{app_id}%7C#{app_secret}"
uri = URI "https://#{host}/v2.8/#{path_query}&limit=100"
is_array ? fetch_multiple_pages(uri).uniq : json_for(uri)
rescue URI::InvalidURIError
raise Funky::ContentNotFound, "Invalid URL"
Expand Down Expand Up @@ -66,17 +66,16 @@ def self.fetch_multiple_pages(uri)
def self.request(id:, fields:)
uri = URI::HTTPS.build host: host,
path: "/v2.8/#{id}",
query: "access_token=#{app_id}%7C#{app_secret}&fields=#{fields}"
query: "fields=#{fields}"
response_for(get_http_request(uri), uri)
end

def self.batch_request(ids:, fields:)
uri = URI::HTTPS.build host: host,
path: "/",
query: "include_headers=false&access_token=#{app_id}%7C#{app_secret}"
query: "include_headers=false"
batch = create_batch_for ids, fields
http_request = post_http_request uri
http_request.set_form_data batch: batch.to_json
http_request = post_http_request(uri, batch: batch.to_json)
response_for(http_request, uri)
end

Expand All @@ -94,10 +93,6 @@ def self.app_secret
Funky.configuration.app_secret
end

def self.post_http_request(uri)
Net::HTTP::Post.new uri
end

def self.create_batch_for(ids, fields)
ids.map do |id|
{"method":"GET", "relative_url": "/v2.8/#{id}?fields=#{fields}"}
Expand Down
46 changes: 45 additions & 1 deletion lib/funky/connections/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,30 @@ class Base

private

def self.post_http_request(uri, form_data={})
http_request = Net::HTTP::Post.new uri
http_request.set_form_data form_data
http_request
end

def self.get_http_request(uri)
Net::HTTP::Get.new(uri.request_uri)
Net::HTTP::Get.new(uri)
end

def self.response_for(http_request, uri, max_retries = 5)
uri = uri_with_query(uri, access_token: app_access_token)
http_request = req_with_query(http_request, access_token: app_access_token)

response = Net::HTTP.start(uri.host, 443, use_ssl: true) do |http|
http.request http_request
end
if response.is_a? Net::HTTPSuccess
response
elsif response.is_a? Net::HTTPServerError
sleep_and_retry_response_for(http_request, uri, max_retries, response.body)
elsif response.is_a?(Net::HTTPBadRequest) && response.body =~ /access token/i
@app_access_token = nil
response_for(http_request, uri)
else
raise ContentNotFound, "Error #{response.code}: #{response.body}"
end
Expand All @@ -37,6 +49,38 @@ def self.json_for(uri, max_retries = 3)
response = response_for(get_http_request(uri), uri)
JSON.parse(response.body, symbolize_names: true)
end

def self.uri_with_query(uri, query={})
return nil if uri.nil?
new_query = URI.decode_www_form(uri.query).to_h.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}.merge(query)
uri.query = URI.encode_www_form(new_query)
uri
end

def self.req_with_query(http_request, query={})
return nil if http_request.nil?
new_uri = uri_with_query(http_request.uri, query)
case http_request
when Net::HTTP::Get
get_http_request(new_uri)
when Net::HTTP::Post
req = Net::HTTP::Post.new new_uri
req.set_form_data URI.decode_www_form(http_request.body)
req
end
end

def self.app_access_token
@app_access_token ||= begin
uri = URI::HTTPS.build host: host, path: "/v2.8/oauth/access_token",
query: URI.encode_www_form({client_id: app_id, client_secret: app_secret, grant_type: 'client_credentials'})
req = get_http_request(uri)
response = Net::HTTP.start(uri.host, 443, use_ssl: true) do |http|
http.request req
end
JSON.parse(response.body, symbolize_names: true)[:access_token]
end
end
end
end
end
12 changes: 12 additions & 0 deletions spec/pages/find_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,17 @@

it { expect { page }.to raise_error(Funky::ContentNotFound) }
end

context 'with invalid app access token' do
before { Funky::Connection::API.instance_variable_set :@app_access_token, 'invalid-token' }

context 'given an existing page ID' do
let(:page_id) { existing_page_id }

specify 'does not raise error by refreshing' do
expect{ page }.not_to raise_error
end
end
end
end
end