Skip to content

Commit 67319c1

Browse files
Add extended API support (Templates, ContactLists)
1 parent ec7b23b commit 67319c1

File tree

5 files changed

+417
-0
lines changed

5 files changed

+417
-0
lines changed

lib/mailtrap.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@
66
require_relative 'mailtrap/version'
77
require_relative 'mailtrap/resources/batch_sender'
88
require_relative 'mailtrap/resources/contacts'
9+
require_relative 'mailtrap/resources/templates'
10+
require_relative 'mailtrap/resources/contact_lists'
911

1012
module Mailtrap; end
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# frozen_string_literal: true
2+
3+
module Mailtrap
4+
module Resources
5+
class ContactLists
6+
ALLOWED_CREATE_KEYS = %i[name description].freeze
7+
ALLOWED_UPDATE_KEYS = %i[name description].freeze
8+
9+
EXPECTED_KEYS = %i[
10+
id name description contacts_count created_at updated_at
11+
].freeze
12+
13+
def initialize(api_client, strict_mode: false)
14+
@client = api_client
15+
@strict_mode = strict_mode
16+
end
17+
18+
def list(account_id:, page: 1, per_page: 50)
19+
response = @client.get("/api/accounts/#{account_id}/contact_lists", params: {
20+
page: page,
21+
per_page: per_page
22+
})
23+
validate_response_keys!(response[:data]) if @strict_mode
24+
response
25+
end
26+
27+
def find(account_id:, list_id:)
28+
response = @client.get("/api/accounts/#{account_id}/contact_lists/#{list_id}")
29+
validate_response_keys!([response]) if @strict_mode
30+
response
31+
end
32+
33+
def create(account_id:, **attrs)
34+
validate_keys!(attrs, ALLOWED_CREATE_KEYS)
35+
@client.post("/api/accounts/#{account_id}/contact_lists", body: attrs)
36+
end
37+
38+
def update(account_id:, list_id:, **attrs)
39+
validate_keys!(attrs, ALLOWED_UPDATE_KEYS)
40+
@client.patch("/api/accounts/#{account_id}/contact_lists/#{list_id}", body: attrs.compact)
41+
end
42+
43+
def delete(account_id:, list_id:)
44+
@client.delete("/api/accounts/#{account_id}/contact_lists/#{list_id}")
45+
end
46+
47+
private
48+
49+
def validate_keys!(input, allowed_keys)
50+
return unless @strict_mode
51+
52+
input.each_key do |key|
53+
raise ArgumentError, "Unexpected key in payload: #{key}" unless allowed_keys.include?(key)
54+
end
55+
end
56+
57+
def validate_response_keys!(records)
58+
records.each do |record|
59+
record.each_key do |key|
60+
raise ArgumentError, "Unexpected key in response: #{key}" unless EXPECTED_KEYS.include?(key)
61+
end
62+
63+
EXPECTED_KEYS.each do |key|
64+
raise ArgumentError, "Missing key in contact list object: #{key}" unless record.key?(key)
65+
end
66+
end
67+
end
68+
end
69+
end
70+
end

lib/mailtrap/resources/templates.rb

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# frozen_string_literal: true
2+
3+
module Mailtrap
4+
module Resources
5+
class Templates
6+
ALLOWED_CREATE_KEYS = %i[name subject category body_html body_text].freeze
7+
ALLOWED_UPDATE_KEYS = ALLOWED_CREATE_KEYS
8+
ALLOWED_RESPONSE_KEYS = %i[
9+
id uuid name subject category body_html body_text created_at updated_at
10+
].freeze
11+
12+
def initialize(api_client, strict_mode: false)
13+
@client = api_client
14+
@strict_mode = strict_mode
15+
end
16+
17+
def list(account_id:, page: 1, per_page: 50)
18+
response = @client.get("/api/accounts/#{account_id}/email_templates", params: {
19+
page: page,
20+
per_page: per_page
21+
})
22+
23+
validate_response_keys!(response[:data]) if @strict_mode
24+
response
25+
end
26+
27+
def find(account_id:, template_id:)
28+
response = @client.get("/api/accounts/#{account_id}/email_templates/#{template_id}")
29+
validate_response_keys!([response]) if @strict_mode
30+
response
31+
end
32+
33+
def create(account_id:, **attrs)
34+
validate_keys!(attrs, ALLOWED_CREATE_KEYS)
35+
36+
@client.post("/api/accounts/#{account_id}/email_templates", body: {
37+
email_template: attrs
38+
})
39+
end
40+
41+
def patch(account_id:, template_id:, **attrs)
42+
validate_keys!(attrs, ALLOWED_UPDATE_KEYS)
43+
44+
@client.patch("/api/accounts/#{account_id}/email_templates/#{template_id}", body: {
45+
email_template: attrs.compact
46+
})
47+
end
48+
49+
def delete(account_id:, template_id:)
50+
@client.delete("/api/accounts/#{account_id}/email_templates/#{template_id}")
51+
end
52+
53+
private
54+
55+
EXPECTED_KEYS = %i[id uuid name subject category body_html body_text created_at updated_at].freeze
56+
57+
def validate_keys!(input, allowed_keys)
58+
return unless @strict_mode
59+
60+
input.each_key do |key|
61+
unless allowed_keys.include?(key)
62+
raise ArgumentError, "Unexpected key in payload: #{key}"
63+
end
64+
end
65+
end
66+
67+
def validate_response_keys!(records)
68+
records.each do |record|
69+
record.each_key do |key|
70+
unless EXPECTED_KEYS.include?(key)
71+
raise ArgumentError, "Unexpected key in response: #{key}"
72+
end
73+
end
74+
75+
EXPECTED_KEYS.each do |key|
76+
unless record.key?(key)
77+
raise ArgumentError, "Missing key in template object: #{key}"
78+
end
79+
end
80+
end
81+
end
82+
end
83+
end
84+
end
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
require 'mailtrap/api/client'
5+
require 'mailtrap/resources/contact_lists'
6+
7+
RSpec.describe Mailtrap::Resources::ContactLists do
8+
let(:client) { instance_double(Mailtrap::Api::Client) }
9+
let(:resource) { described_class.new(client, strict_mode: true) }
10+
let(:account_id) { '12345' }
11+
let(:list_id) { 'list-uuid-999' }
12+
13+
let(:valid_response) do
14+
{
15+
id: list_id,
16+
name: 'VIP Clients',
17+
description: 'Top-tier clients',
18+
contacts_count: 42,
19+
created_at: 1_716_400_000,
20+
updated_at: 1_716_400_000
21+
}
22+
end
23+
24+
describe '#list' do
25+
let(:response_data) { { data: [valid_response] } }
26+
27+
it 'returns list and validates keys' do
28+
expect(client).to receive(:get).with(
29+
"/api/accounts/#{account_id}/contact_lists",
30+
params: { page: 1, per_page: 50 }
31+
).and_return(response_data)
32+
33+
expect(resource.list(account_id: account_id)).to eq(response_data)
34+
end
35+
36+
it 'raises error if extra key present' do
37+
bad_response = { data: [valid_response.merge(extra: 'oops')] }
38+
allow(client).to receive(:get).and_return(bad_response)
39+
40+
expect {
41+
resource.list(account_id: account_id)
42+
}.to raise_error(ArgumentError, /Unexpected key in response: extra/)
43+
end
44+
45+
it 'raises error if required key missing' do
46+
bad_response = { data: [valid_response.except(:description)] }
47+
allow(client).to receive(:get).and_return(bad_response)
48+
49+
expect {
50+
resource.list(account_id: account_id)
51+
}.to raise_error(ArgumentError, /Missing key in contact list object: description/)
52+
end
53+
end
54+
55+
describe '#find' do
56+
it 'returns single contact list' do
57+
expect(client).to receive(:get).with(
58+
"/api/accounts/#{account_id}/contact_lists/#{list_id}"
59+
).and_return(valid_response)
60+
61+
expect(resource.find(account_id: account_id, list_id: list_id)).to eq(valid_response)
62+
end
63+
end
64+
65+
describe '#create' do
66+
let(:params) { { name: 'New List', description: 'Optional desc' } }
67+
68+
it 'creates a contact list with allowed keys' do
69+
expect(client).to receive(:post).with(
70+
"/api/accounts/#{account_id}/contact_lists",
71+
body: params
72+
).and_return(valid_response)
73+
74+
expect(resource.create(account_id: account_id, **params)).to eq(valid_response)
75+
end
76+
77+
it 'raises error with unexpected keys' do
78+
expect {
79+
resource.create(account_id: account_id, name: 'Test', bad: 'key')
80+
}.to raise_error(ArgumentError, /Unexpected key in payload: bad/)
81+
end
82+
end
83+
84+
describe '#update' do
85+
let(:attrs) { { name: 'Renamed', description: 'Updated description' } }
86+
87+
it 'updates a contact list' do
88+
expect(client).to receive(:patch).with(
89+
"/api/accounts/#{account_id}/contact_lists/#{list_id}",
90+
body: attrs
91+
).and_return(valid_response)
92+
93+
expect(resource.update(account_id: account_id, list_id: list_id, **attrs)).to eq(valid_response)
94+
end
95+
96+
it 'raises error with unexpected update key' do
97+
expect {
98+
resource.update(account_id: account_id, list_id: list_id, foo: 'bar')
99+
}.to raise_error(ArgumentError, /Unexpected key in payload: foo/)
100+
end
101+
end
102+
103+
describe '#delete' do
104+
it 'deletes a contact list' do
105+
expect(client).to receive(:delete).with(
106+
"/api/accounts/#{account_id}/contact_lists/#{list_id}"
107+
).and_return({})
108+
109+
expect(resource.delete(account_id: account_id, list_id: list_id)).to eq({})
110+
end
111+
end
112+
end

0 commit comments

Comments
 (0)