-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsent_controller.ex
136 lines (116 loc) · 4.02 KB
/
sent_controller.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
defmodule AppWeb.SentController do
use AppWeb, :controller
alias App.Ctx
alias App.Ctx.Sent
def index(conn, _params) do
sent = Ctx.list_sent()
render(conn, "index.html", sent: sent)
end
def new(conn, _params) do
changeset = Ctx.change_sent(%Sent{})
render(conn, "new.html", changeset: changeset)
end
def create(conn, params) do
attrs = Map.merge(Map.get(params, "sent"), %{"status" => "Pending"})
send_email(attrs)
conn
# |> put_flash(:info, "💌 Email sent to: " <> Map.get(attrs, "email"))
|> redirect(to: "/")
end
def send_email(attrs) do
sent = Ctx.upsert_sent(attrs)
payload = Map.merge(attrs, %{"id" => sent.id})
# see: https://github.com/dwyl/elixir-invoke-lambda-example
ExAws.Lambda.invoke("aws-ses-lambda-v1", payload, "no_context")
|> ExAws.request(region: System.get_env("AWS_REGION"))
sent
end
def send_email_check_auth_header(conn, params) do
case check_jwt_auth_header(conn) do
{:error, _} ->
unauthorized(conn, params)
{:ok, claims} ->
claims = Map.merge(claims, %{"status" => "Pending"})
sent = send_email(claims)
data = Map.merge(claims, %{"id" => sent.id})
conn
|> put_resp_header("content-type", "application/json;")
|> send_resp(200, Jason.encode!(data, pretty: true))
end
end
defp check_jwt_auth_header(conn) do
jwt = List.first(Plug.Conn.get_req_header(conn, "authorization"))
if is_nil(jwt) do
{:error, nil}
else # fast check for JWT format validity before slower verify:
case Enum.count(String.split(jwt, ".")) == 3 do
false ->
{:error, nil}
true -> # valid JWT proceed to verifying it
App.Token.verify_and_validate(jwt)
end
end
end
defp check_jwt_url_params(%{"jwt" => jwt}) do
if is_nil(jwt) do
{:error, nil}
else # fast check for JWT format validity before slower verify:
case Enum.count(String.split(jwt, ".")) == 3 do
false -> # invalid JWT return 401
{:error, :invalid}
true -> # valid JWT proceed to verifying it
App.Token.verify_and_validate(jwt)
end
end
end
@doc """
`unauthorized/2` reusable unauthorized response handler used in process_jwt/2
"""
def unauthorized(conn, _params) do
conn
|> send_resp(401, "unauthorized")
|> halt()
end
@doc """
`process_sns/2` processes an API request with a JWT in authorization header.
"""
def process_sns(conn, params) do
case check_jwt_auth_header(conn) do
{:error, _} ->
unauthorized(conn, params)
{:ok, claims} ->
# IO.inspect(claims)
sent = App.Ctx.upsert_sent(claims)
data = %{"id" => sent.id}
conn
|> put_resp_header("content-type", "application/json;")
|> send_resp(200, Jason.encode!(data, pretty: true))
end
end
# This is the Base64 encoding for a 1x1 transparent pixel GIF for issue#1
# stackoverflow.com/questions/4665960/most-efficient-way-to-display-a-1x1-gif
@image "\x47\x49\x46\x38\x39\x61\x1\x0\x1\x0\x80\x0\x0\xff\xff\xff\x0\x0\x0\x21\xf9\x4\x1\x0\x0\x0\x0\x2c\x0\x0\x0\x0\x1\x0\x1\x0\x0\x2\x2\x44\x1\x0\x3b"
@doc """
`render_pixel/2` extracts the id of a sent item from a JWT in the URL
and if the JWT is valid, updates the status to "Opened" and returns the pixel.
"""
def render_pixel(conn, params) do
case check_jwt_url_params(params) do
{:error, _} ->
unauthorized(conn, nil)
{:ok, claims} ->
App.Ctx.email_opened(Map.get(claims, "id"))
conn # instruct browser not to cache the image
|> put_resp_header("cache-control", "no-store, private")
|> put_resp_header("pragma", "no-cache")
|> put_resp_content_type("image/gif")
|> send_resp(200, @image)
end
end
# GET /ping https://github.com/dwyl/email/issues/30
def ping(conn, _params) do
conn
|> put_resp_header("content-type", "application/json;")
|> send_resp(200, Jason.encode!(Quotes.random(), pretty: true))
end
end