Skip to content

Commit 203c982

Browse files
authored
Merge pull request #32 from asgoel/ISSUE-31
Issue 31 - Add template preview API
2 parents 5d3bdc4 + f3e209c commit 203c982

File tree

11 files changed

+176
-14
lines changed

11 files changed

+176
-14
lines changed

lib/content/inline.ex

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,12 @@ defmodule SparkPost.Content.Inline do
2525
html: nil,
2626
attachments: nil,
2727
inline_images: nil
28+
29+
@doc """
30+
Convert a raw "from" field into a %SparkPost.Address{} object.
31+
"""
32+
def convert_from_field(%SparkPost.Endpoint.Error{} = content), do: content
33+
def convert_from_field(%__MODULE__{} = content) do
34+
%{content | from: SparkPost.Address.to_address(content.from)}
35+
end
2836
end

lib/endpoint.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ defmodule SparkPost.Endpoint do
4242
else
4343
Map.merge(headers, %{"Content-Type": "application/json"})
4444
end
45-
|> Map.merge(base_request_headers)
45+
|> Map.merge(base_request_headers())
4646

4747
request_options = options
4848
|> Keyword.put(:timeout, Application.get_env(:sparkpost, :http_timeout, 30000))

lib/mockserver.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@ defmodule SparkPost.MockServer do
1818
end
1919

2020
def mk_resp do
21-
SparkPost.MockServer.mk_http_resp(200, create_json)
21+
SparkPost.MockServer.mk_http_resp(200, create_json())
2222
end
2323

2424
def mk_fail do
25-
SparkPost.MockServer.mk_http_resp(400, create_fail_json)
25+
SparkPost.MockServer.mk_http_resp(400, create_fail_json())
2626
end
2727

2828
def mk_list do
29-
SparkPost.MockServer.mk_http_resp(200, list_json)
29+
SparkPost.MockServer.mk_http_resp(200, list_json())
3030
end
3131

3232
def mk_get do
33-
SparkPost.MockServer.mk_http_resp(200, get_json)
33+
SparkPost.MockServer.mk_http_resp(200, get_json())
3434
end
3535

3636
def mk_http_resp(status_code, body) do

lib/template.ex

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
defmodule SparkPost.Template do
2+
@moduledoc """
3+
The SparkPost Template API for working with templates. Use `SparkPost.Template.preview/2` to
4+
preview a template.
5+
6+
Check out the documentation for each function
7+
or use the [SparkPost API reference](https://developers.sparkpost.com/api/templates.html) for details.
8+
9+
Returned by `SparkPost.template.preview/2`.
10+
-from
11+
-email
12+
-name
13+
-subject
14+
-reply_to
15+
-text
16+
-html
17+
-headers
18+
"""
19+
20+
alias SparkPost.Endpoint
21+
22+
@doc """
23+
Generate a preview of an existing template.
24+
25+
### Parameters
26+
- %SparkPost.Content.TemplateRef{} consisting of:
27+
- template_id: The string id of the template to retrieve a preview or.
28+
- use_draft_template: If true, previews the most recent draft template.
29+
If false, previews the most recent published template. If nil,
30+
previews the most recently template version period.
31+
- substitution_data: k,v map consisting of substituions. See the
32+
[SparkPost Substitutions Reference](https://developers.sparkpost.com/api/substitutions-reference.html)
33+
for more details.
34+
"""
35+
def preview(%SparkPost.Content.TemplateRef{} = template, substitution_data) do
36+
qs = if is_nil(template.use_draft_template) do
37+
""
38+
else
39+
"?draft=#{template.use_draft_template}"
40+
end
41+
body = %{substitution_data: substitution_data}
42+
:post
43+
|> Endpoint.request("/templates/#{template.template_id}/preview#{qs}", body)
44+
|> Endpoint.marshal_response(SparkPost.Content.Inline)
45+
|> SparkPost.Content.Inline.convert_from_field
46+
end
47+
end

mix.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ defmodule SparkPost.Mixfile do
99
start_permanent: Mix.env == :prod,
1010
source_url: "https://github.com/SparkPost/elixir-sparkpost",
1111
description: "The official Elixir package for the SparkPost API",
12-
package: package,
13-
deps: deps,
12+
package: package(),
13+
deps: deps(),
1414
docs: [
1515
extras: ["README.md", "CONTRIBUTING.md", "CHANGELOG.md"]
1616
],

mix.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
"ex_doc": {:hex, :ex_doc, "0.14.3", "e61cec6cf9731d7d23d254266ab06ac1decbb7651c3d1568402ec535d387b6f7", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]},
66
"excoveralls": {:hex, :excoveralls, "0.5.7", "5d26e4a7cdf08294217594a1b0643636accc2ad30e984d62f1d166f70629ff50", [:mix], [{:exjsx, "~> 3.0", [hex: :exjsx, optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, optional: false]}]},
77
"exjsx": {:hex, :exjsx, "3.2.1", "1bc5bf1e4fd249104178f0885030bcd75a4526f4d2a1e976f4b428d347614f0f", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, optional: false]}]},
8-
"hackney": {:hex, :hackney, "1.6.3", "d489d7ca2d4323e307bedc4bfe684323a7bf773ecfd77938f3ee8074e488e140", [:rebar3, :mix], [{:certifi, "0.7.0", [hex: :certifi, optional: false]}, {:idna, "1.2.0", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]},
8+
"hackney": {:hex, :hackney, "1.6.3", "d489d7ca2d4323e307bedc4bfe684323a7bf773ecfd77938f3ee8074e488e140", [:mix, :rebar3], [{:certifi, "0.7.0", [hex: :certifi, optional: false]}, {:idna, "1.2.0", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]},
99
"httpoison": {:hex, :httpoison, "0.9.2", "a211a8e87403a043c41218e64df250d321f236ac57f786c6a0ccf3e9e817c819", [:mix], [{:hackney, "~> 1.6.0", [hex: :hackney, optional: false]}]},
1010
"httpotion": {:hex, :httpotion, "2.1.0", "3fe84fbd13d4560c2514da656d022b1191a079178ee4992d245fc3c33c01ee18", [:mix], []},
1111
"ibrowse": {:git, "https://github.com/cmullaparthi/ibrowse.git", "ea3305d21f37eced4fac290f64b068e56df7de80", [tag: "v4.1.2"]},
1212
"idna": {:hex, :idna, "1.2.0", "ac62ee99da068f43c50dc69acf700e03a62a348360126260e87f2b54eced86b2", [:rebar3], []},
1313
"jsx": {:hex, :jsx, "2.8.0", "749bec6d205c694ae1786d62cea6cc45a390437e24835fd16d12d74f07097727", [:mix, :rebar], []},
14-
"meck": {:hex, :meck, "0.8.4", "59ca1cd971372aa223138efcf9b29475bde299e1953046a0c727184790ab1520", [:rebar, :make], []},
14+
"meck": {:hex, :meck, "0.8.4", "59ca1cd971372aa223138efcf9b29475bde299e1953046a0c727184790ab1520", [:make, :rebar], []},
1515
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []},
1616
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []},
1717
"mock": {:hex, :mock, "0.2.0", "5991877be6bb514b647dbd6f4869bc12bd7f2829df16e86c98d6108f966d34d7", [:mix], [{:meck, "~> 0.8.2", [hex: :meck, optional: false]}]},
1818
"poison": {:hex, :poison, "3.0.0", "625ebd64d33ae2e65201c2c14d6c85c27cc8b68f2d0dd37828fde9c6920dd131", [:mix], []},
19-
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:rebar, :make], []},
19+
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []},
2020
"ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5", "2e73e068cd6393526f9fa6d399353d7c9477d6886ba005f323b592d389fb47be", [:make], []}}

test/data/previewtemplate.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"results": {
3+
"from": {
4+
"email": "marketing@bounces.company.example",
5+
"name": "Example Company Marketing"
6+
},
7+
"subject": "Summer deals for Natalie",
8+
"reply_to": "Summer deals <summer_deals@company.example>",
9+
"text": "Check out these deals Natalie!",
10+
"html": "<b>Check out these deals Natalie!</b>",
11+
"headers": {
12+
"X-Customer-Campaign-ID": "Summer2014"
13+
}
14+
}
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"results": {
3+
"from": "marketing@bounces.company.example",
4+
"subject": "Summer deals for Natalie",
5+
"reply_to": "Summer deals <summer_deals@company.example>",
6+
"text": "Check out these deals Natalie!",
7+
"html": "<b>Check out these deals Natalie!</b>",
8+
"headers": {
9+
"X-Customer-Campaign-ID": "Summer2014"
10+
}
11+
}
12+
}

test/endpoint_test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ defmodule SparkPost.EndpointTest do
99
defmodule Headers do
1010
def for_method(method) do
1111
cond do
12-
method in [:post, :put] -> Map.merge(for_body_requests, core)
13-
true -> core
12+
method in [:post, :put] -> Map.merge(for_body_requests(), core())
13+
true -> core()
1414
end
1515
end
1616

test/template_test.exs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
defmodule SparkPost.TemplateTest do
2+
use ExUnit.Case, async: false
3+
4+
alias SparkPost.Content.{TemplateRef, Inline}
5+
alias SparkPost.{Endpoint, MockServer, Template}
6+
7+
import Mock
8+
9+
defmodule TestStruct do
10+
def basic_template do
11+
%TemplateRef{template_id: "TEMPLATE_ID", use_draft_template: nil}
12+
end
13+
14+
def template_with_draft do
15+
%TemplateRef{template_id: "TEMPLATE_ID", use_draft_template: true}
16+
end
17+
18+
def substitution_data do
19+
%{
20+
key1: "value1",
21+
key2: "value2"
22+
}
23+
end
24+
end
25+
26+
test_with_mock "Template.preview succeeds with Content.Inline",
27+
HTTPoison, [request: fn (method, url, body, headers, opts) ->
28+
assert method == :post
29+
# draft not set
30+
assert String.ends_with?(url, "preview")
31+
fun = MockServer.mk_http_resp(200, MockServer.get_json("previewtemplate"))
32+
fun.(method, url, body, headers, opts)
33+
end] do
34+
resp = Template.preview(TestStruct.basic_template(), TestStruct.substitution_data())
35+
assert %Inline{} = resp
36+
end
37+
38+
test_with_mock "Template.preview succeeds with Content.Inline and draft set",
39+
HTTPoison, [request: fn (method, url, body, headers, opts) ->
40+
assert method == :post
41+
assert String.ends_with?(url, "preview?draft=true")
42+
fun = MockServer.mk_http_resp(200, MockServer.get_json("previewtemplate"))
43+
fun.(method, url, body, headers, opts)
44+
end] do
45+
resp = Template.preview(TestStruct.template_with_draft(), TestStruct.substitution_data())
46+
assert %Inline{} = resp
47+
end
48+
49+
test_with_mock "Template.preview fails with Endpoint.Error", HTTPoison,
50+
[request: MockServer.mk_fail] do
51+
resp = Template.preview(TestStruct.basic_template(), TestStruct.substitution_data())
52+
assert %Endpoint.Error{} = resp
53+
end
54+
55+
test_with_mock "Template.preview unmarshals complex from field correctly", HTTPoison,
56+
[request: fn (method, url, body, headers, opts) ->
57+
assert method == :post
58+
fun = MockServer.mk_http_resp(200, MockServer.get_json("previewtemplate"))
59+
fun.(method, url, body, headers, opts)
60+
end] do
61+
resp = Template.preview(TestStruct.basic_template(), TestStruct.substitution_data())
62+
assert %SparkPost.Address{
63+
name: "Example Company Marketing",
64+
"email": "marketing@bounces.company.example"
65+
} == resp.from
66+
end
67+
68+
test_with_mock "Template.preview unmarshals simple from field correctly", HTTPoison,
69+
[request: fn (method, url, body, headers, opts) ->
70+
assert method == :post
71+
fun = MockServer.mk_http_resp(200, MockServer.get_json("previewtemplate_simpleemail"))
72+
fun.(method, url, body, headers, opts)
73+
end] do
74+
resp = Template.preview(TestStruct.basic_template(), TestStruct.substitution_data())
75+
assert %SparkPost.Address{
76+
name: nil,
77+
"email": "marketing@bounces.company.example"
78+
} == resp.from
79+
end
80+
end

0 commit comments

Comments
 (0)