diff --git a/lib/mailtrap.rb b/lib/mailtrap.rb index 3b6af23..e5d76d1 100644 --- a/lib/mailtrap.rb +++ b/lib/mailtrap.rb @@ -11,6 +11,7 @@ require_relative 'mailtrap/contact_imports_api' require_relative 'mailtrap/suppressions_api' require_relative 'mailtrap/projects_api' +require_relative 'mailtrap/accounts_api' module Mailtrap # @!macro api_errors diff --git a/lib/mailtrap/account.rb b/lib/mailtrap/account.rb new file mode 100644 index 0000000..ce168d6 --- /dev/null +++ b/lib/mailtrap/account.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Mailtrap + # Data Transfer Object for Project + # @see https://docs.mailtrap.io/developers/account-management/general-api/accounts + # @attr_reader id [Integer] The account ID + # @attr_reader name [String] The account name + # @attr_reader access_levels [Array] The account access levels + # + Account = Struct.new( + :id, + :name, + :access_levels, + keyword_init: true + ) do + # @return [Hash] The Project attributes as a hash + def to_h + super.compact + end + end +end diff --git a/lib/mailtrap/accounts_api.rb b/lib/mailtrap/accounts_api.rb new file mode 100644 index 0000000..056e4b6 --- /dev/null +++ b/lib/mailtrap/accounts_api.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require_relative 'base_api' +require_relative 'account' + +module Mailtrap + class AccountsAPI + include BaseAPI + + self.response_class = Account + + # Lists all accounts + # @return [Array] Array of accounts + # @!macro api_errors + def list + base_list + end + + private + + def base_path + '/api/accounts' + end + end +end diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_AccountsAPI/_list/maps_response_data_to_Account_objects.yml b/spec/fixtures/vcr_cassettes/Mailtrap_AccountsAPI/_list/maps_response_data_to_Account_objects.yml new file mode 100644 index 0000000..6fc59c4 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_AccountsAPI/_list/maps_response_data_to_Account_objects.yml @@ -0,0 +1,79 @@ +--- +http_interactions: +- request: + method: get + uri: https://mailtrap.io/api/accounts + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - mailtrap-ruby (https://github.com/mailtrap/mailtrap-ruby) + Host: + - mailtrap.io + Authorization: + - Bearer + Content-Type: + - application/json + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 05 Jan 2026 12:24:36 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Server: + - cloudflare + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Vary: + - Accept + X-Mailtrap-Version: + - v2 + X-Ratelimit-Limit: + - '150' + X-Ratelimit-Remaining: + - '149' + Etag: + - W/"42e73e96e1ed3c973620c8c09d2f244c" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - 10a9a535-2aa9-4004-baa2-6efbf6c7e701 + X-Runtime: + - '0.042150' + X-Cloud-Trace-Context: + - 26c79d159ce04474883f150f101a74b1;o=0 + Strict-Transport-Security: + - max-age=0 + Cf-Cache-Status: + - DYNAMIC + Cf-Ray: + - 9b92f41c6ab0d2eb-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: '[{"id":2326475,"name":"Yahor Vaitsiakhouski","access_levels":[100]}]' + recorded_at: Mon, 05 Jan 2026 12:24:36 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/Mailtrap_AccountsAPI/_list/when_api_key_is_incorrect/raises_authorization_error.yml b/spec/fixtures/vcr_cassettes/Mailtrap_AccountsAPI/_list/when_api_key_is_incorrect/raises_authorization_error.yml new file mode 100644 index 0000000..c231550 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Mailtrap_AccountsAPI/_list/when_api_key_is_incorrect/raises_authorization_error.yml @@ -0,0 +1,79 @@ +--- +http_interactions: +- request: + method: get + uri: https://mailtrap.io/api/accounts + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - mailtrap-ruby (https://github.com/mailtrap/mailtrap-ruby) + Host: + - mailtrap.io + Authorization: + - Bearer + Content-Type: + - application/json + response: + status: + code: 401 + message: Unauthorized + headers: + Date: + - Mon, 05 Jan 2026 12:24:37 GMT + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '31' + Connection: + - keep-alive + Server: + - cloudflare + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + X-Content-Type-Options: + - nosniff + X-Download-Options: + - noopen + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Www-Authenticate: + - Token realm="Application" + Vary: + - Accept + X-Mailtrap-Version: + - v2 + X-Ratelimit-Limit: + - '150' + X-Ratelimit-Remaining: + - '149' + Cache-Control: + - no-cache + X-Request-Id: + - bb687a17-5205-409a-84fc-9a7efca5378e + X-Runtime: + - '0.007537' + X-Cloud-Trace-Context: + - 3810f5b5e5114fb3cd66b23e840b3a23;o=0 + Strict-Transport-Security: + - max-age=0 + Cf-Cache-Status: + - DYNAMIC + Cf-Ray: + - 9b92f41f8c68f65d-FRA + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: UTF-8 + string: '{"error":"Incorrect API token"}' + recorded_at: Mon, 05 Jan 2026 12:24:37 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/mailtrap/account_spec.rb b/spec/mailtrap/account_spec.rb new file mode 100644 index 0000000..fca8e52 --- /dev/null +++ b/spec/mailtrap/account_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +RSpec.describe Mailtrap::Account do + describe '#initialize' do + subject(:account) { described_class.new(attributes) } + + let(:attributes) do + { + id: '123456', + name: 'Account 1', + access_levels: [ + 1000 + ] + } + end + + it 'creates a project with all attributes' do + expect(account).to match_struct( + id: '123456', + name: 'Account 1', + access_levels: [1000] + ) + end + end + + describe '#to_h' do + subject(:hash) { account.to_h } + + let(:account) do + described_class.new( + id: '123456', + name: 'Account 1', + access_levels: [ + 1000 + ] + ) + end + + it 'returns a hash with all attributes' do + expect(hash).to eq( + id: '123456', + name: 'Account 1', + access_levels: [1000] + ) + end + + context 'when some attributes are nil' do + let(:account) do + described_class.new( + id: '123456' + ) + end + + it 'returns a hash with only non-nil attributes' do + expect(hash).to eq( + id: '123456' + ) + end + end + end +end diff --git a/spec/mailtrap/accounts_api_spec.rb b/spec/mailtrap/accounts_api_spec.rb new file mode 100644 index 0000000..f9bf109 --- /dev/null +++ b/spec/mailtrap/accounts_api_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +RSpec.describe Mailtrap::AccountsAPI, :vcr do + subject(:accounts_api) { described_class.new(account_id, client) } + + let(:account_id) { ENV.fetch('MAILTRAP_ACCOUNT_ID', 1_111_111) } + let(:client) { Mailtrap::Client.new(api_key: ENV.fetch('MAILTRAP_API_KEY', 'local-api-key')) } + + describe '#list' do + subject(:list) { accounts_api.list } + + it 'maps response data to Account objects' do + expect(list).to all(be_a(Mailtrap::Account)) + expect(list.size).to eq(1) + end + + context 'when api key is incorrect' do + let(:client) { Mailtrap::Client.new(api_key: 'incorrect-api-key') } + + it 'raises authorization error' do + expect { list }.to raise_error do |error| + expect(error).to be_a(Mailtrap::AuthorizationError) + expect(error.message).to include('Incorrect API token') + expect(error.messages.any? { |msg| msg.include?('Incorrect API token') }).to be true + end + end + end + end +end