diff --git a/lib/bls/core.rb b/lib/bls/core.rb index f672ea4..52c5c75 100644 --- a/lib/bls/core.rb +++ b/lib/bls/core.rb @@ -7,7 +7,9 @@ require_relative "core/api_client" require_relative "core/api/v1" +require_relative "core/api/v2" require_relative "core/api/v1/authenticator" +require_relative "core/api/v2/authenticator" require_relative "core/api_operations/retrieve" require_relative "core/authorization/base" require_relative "core/authorization/basic" @@ -32,7 +34,8 @@ module Core class Error < StandardError; end class << self - attr_accessor :client_id, :client_secret, :environment + attr_accessor :client_id, :client_secret, :environment, :username, + :password def configure yield self diff --git a/lib/bls/core/api/v1/authenticator.rb b/lib/bls/core/api/v1/authenticator.rb index 77c9e17..6490b18 100644 --- a/lib/bls/core/api/v1/authenticator.rb +++ b/lib/bls/core/api/v1/authenticator.rb @@ -15,7 +15,7 @@ def save! path = "#{base_url}/token" body = { client_id: client_id, client_secret: client_secret } auth = Authorization::Basic. - factory(client_id: client_id, client_secret: client_secret) + factory(username: client_id, password: client_secret) client = Core::ApiClient.new(authentication: auth) response = client.post(path: path, body: body) handle_authentication_response!(response: response.data) diff --git a/lib/bls/core/api/v2.rb b/lib/bls/core/api/v2.rb new file mode 100644 index 0000000..3f6dd40 --- /dev/null +++ b/lib/bls/core/api/v2.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module Bls + module Core + class V2 + attr_accessor :authentication + attr_reader :environment, :username, :password + + PRODUCTION = "production" + STAGING = "staging" + + def initialize(username: nil, password: nil, authentication: nil, + environment: STAGING) + @authentication = authentication + @environment = environment + @username = username + @password = password + end + + def base_url + "https://core.batchlinesolutions.#{tld}" + end + + def authenticate! + return if authenticated? + + authenticator = V2::Authenticator.build(self) + @authentication = authenticator.save! + end + + def client + build_api_client! + end + + def authenticated? + authentication.present? + end + + def reset_authentication + @authentication = nil + self + end + + def self.build(config: Bls::Core) + new(environment: config.environment, + username: config.username, + password: config.password) + end + + protected + + def build_api_client! + authenticate! + Bls::Core::ApiClient.build(self) + end + + def tld + @tld ||= determine_tld + end + + def determine_tld + if environment == PRODUCTION + "com" + else + "dev" + end + end + end + end +end diff --git a/lib/bls/core/api/v2/authenticator.rb b/lib/bls/core/api/v2/authenticator.rb new file mode 100644 index 0000000..ea2c316 --- /dev/null +++ b/lib/bls/core/api/v2/authenticator.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Bls + module Core + class V2::Authenticator + attr_accessor :authentication + + def initialize(authentication:) + @authentication = authentication + end + + def save! + authentication + end + + def self.build(api) + authentication = Authorization::Basic. + factory(username: api.username, + password: api.password) + new(authentication: authentication) + end + end + end +end diff --git a/lib/bls/core/authorization/basic.rb b/lib/bls/core/authorization/basic.rb index 010c8ea..dd6d422 100644 --- a/lib/bls/core/authorization/basic.rb +++ b/lib/bls/core/authorization/basic.rb @@ -8,8 +8,8 @@ def header "Basic #{token}" end - def self.factory(client_id:, client_secret:) - encoded_token = Base64.strict_encode64("#{client_id}:#{client_secret}") + def self.factory(username:, password:) + encoded_token = Base64.strict_encode64("#{username}:#{password}") new(token: encoded_token) end end diff --git a/lib/bls/core/resources/api_error.rb b/lib/bls/core/resources/api_error.rb index 1a7475f..07ba116 100644 --- a/lib/bls/core/resources/api_error.rb +++ b/lib/bls/core/resources/api_error.rb @@ -22,7 +22,9 @@ def message def self.build(response) data = response.data - data => { status:, title:, details: } + status = data.fetch(:status, data[:type]) + title = data.fetch(:title, data[:message]) + details = data[:details] new(status: status, title: title, details: details) end diff --git a/spec/core/api/v2/authenticator_spec.rb b/spec/core/api/v2/authenticator_spec.rb new file mode 100644 index 0000000..39e7779 --- /dev/null +++ b/spec/core/api/v2/authenticator_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +RSpec.describe Bls::Core::V2::Authenticator do + describe "#save!" do + it "returns a authorization scheme" do + basic = Bls::Core::Authorization::Basic.new(token: "test") + auth = Bls::Core::V2::Authenticator.new(authentication: basic) + + result = auth.save! + + expect(result).to respond_to(:header) + end + end + + describe ".build" do + it "sets the authentication" do + api = Bls::Core::V2.new + basic = Bls::Core::Authorization::Basic.new(token: "test") + allow(Bls::Core::Authorization::Basic).to receive(:factory). + and_return(basic) + + result = Bls::Core::V2::Authenticator.build(api) + + expect(result.authentication).to eq(basic) + end + end + + def build_config(environment: "staging", client_id: "cid_123", + client_secret: "cs_123") + OpenStruct.new(environment: environment, client_id: client_id, + client_secret: client_secret) + end +end diff --git a/spec/core/api/v2_spec.rb b/spec/core/api/v2_spec.rb new file mode 100644 index 0000000..80915dc --- /dev/null +++ b/spec/core/api/v2_spec.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +RSpec.describe Bls::Core::V2 do + describe "#base_url" do + context "when the environment is production" do + it "returns the correct url" do + api = Bls::Core::V2.new(environment: "production") + + result = api.base_url + + expect(result).to eq("https://core.batchlinesolutions.com") + end + end + + context "when the environment is not production" do + it "returns the correct url" do + api = Bls::Core::V2.new(environment: "staging") + + result = api.base_url + + expect(result).to eq("https://core.batchlinesolutions.dev") + end + end + end + + describe "#client" do + it "returns a api client" do + api = Bls::Core::V2.new + build_stubbed_authenticator(api) + + result = api.client + + expect(result).to respond_to(:post) + end + end + + describe "#authenticate" do + it "builds a authenticator" do + api = Bls::Core::V2.new + build_stubbed_authenticator(api) + + api.authenticate! + + expect(Bls::Core::V2::Authenticator).to have_received(:build).once + end + + it "authenticates" do + api = Bls::Core::V2.new + authenticator = build_stubbed_authenticator(api) + + api.authenticate! + + expect(authenticator).to have_received(:save!).once + end + + context "when the authentication is present" do + it "is authenticated" do + api = Bls::Core::V2.new + build_stubbed_authenticator(api) + + api.authenticate! + + expect(api).to be_authenticated + end + end + end + + describe "reset authentication" do + it "removes the present authentication" do + auth = Bls::Core::Authorization::Basic.new(token: "1234") + api = Bls::Core::V2.new(authentication: auth) + + result = api.reset_authentication + + expect(result.authentication).to be_blank + end + + it "is not authenticated" do + auth = Bls::Core::Authorization::Basic.new(token: "1234") + api = Bls::Core::V2.new(authentication: auth) + + result = api.reset_authentication + + expect(result).not_to be_authenticated + end + end + + describe ".build" do + it "sets the environment" do + config = build_config(environment: "preview") + + result = Bls::Core::V2.build(config: config) + + expect(result.environment).to eq("preview") + end + + it "sets the username" do + config = build_config(username: "secretUsername") + + result = Bls::Core::V2.build(config: config) + + expect(result.username).to eq("secretUsername") + end + + it "sets the password" do + config = build_config(password: "secretPassword") + + result = Bls::Core::V2.build(config: config) + + expect(result.password).to eq("secretPassword") + end + end + + def build_config(environment: "staging", username: "string", + password: "string") + OpenStruct.new(environment: environment, username: username, + password: password) + end + + def build_stubbed_authenticator(api) + authenticator = Bls::Core::V2::Authenticator.build(api) + authentication = authenticator.authentication + client = Bls::Core::ApiClient.new(authentication: authentication) + allow(Bls::Core::V2::Authenticator).to receive(:build). + and_return(authenticator) + allow(authenticator).to receive(:save!).and_return(client) + authenticator + end +end diff --git a/spec/support/helpers/api_helper.rb b/spec/support/helpers/api_helper.rb index e64195b..f7bb825 100644 --- a/spec/support/helpers/api_helper.rb +++ b/spec/support/helpers/api_helper.rb @@ -28,6 +28,12 @@ def stub_api_v1_authentication(authenticated: true) allow(api).to receive(:authenticated?).and_return(authenticated) end + def stub_api_v2_authentication(authenticated: true) + api = Bls::Core::V2.build + allow(Bls::Core::V2).to receive(:new).and_return(api) + allow(api).to receive(:authenticated?).and_return(authenticated) + end + def stub_api_response(response: OpenStruct.new(body: "{}", code: 200), http: double) allow(Net::HTTP).to receive(:start).and_yield(http)