Skip to content

Commit

Permalink
adds email notifications when a response has been made to some feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
jackcarlisle committed Apr 17, 2017
1 parent 1d3ea9e commit 11f9e58
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 99 deletions.
11 changes: 11 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]

# Configures mailing
config :feedback, Feedback.Mailer,
adapter: Bamboo.SMTPAdapter,
server: System.get_env("SES_SERVER"),
port: System.get_env("SES_PORT"),
username: System.get_env("SMTP_USERNAME"),
password: System.get_env("SMTP_PASSWORD"),
tls: :always, # can be `:always` or `:never`
ssl: false, # can be `true`
retries: 1

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env}.exs"
4 changes: 4 additions & 0 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ config :feedback, Feedback.Repo,

config :comeonin, :bcrypt_log_rounds, 4
config :comeonin, :pbkdf2_rounds, 1

# Configure Bamboo email
config :feedback, Feedback.Mailer,
adapter: Bamboo.TestAdapter
11 changes: 11 additions & 0 deletions lib/email.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule Feedback.Email do
use Bamboo.Phoenix, view: Feedback.FeedbackView

def send_email(to_email_address, subject, message) do
new_email()
|> to(to_email_address)
|> from(System.get_env("ADMIN_EMAIL")) # also needs to be a validated email
|> subject(subject)
|> text_body(message)
end
end
3 changes: 3 additions & 0 deletions lib/feedback/mailer.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
defmodule Feedback.Mailer do
use Bamboo.Mailer, otp_app: :feedback
end
7 changes: 5 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ defmodule Feedback.Mixfile do
def application do
[mod: {Feedback, []},
applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,
:phoenix_ecto, :postgrex, :comeonin]]
:phoenix_ecto, :postgrex, :comeonin, :bamboo]]
end

# Specifies which paths to compile per environment.
Expand All @@ -44,7 +44,10 @@ defmodule Feedback.Mixfile do
{:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"},
{:comeonin, "~> 2.0"},
{:excoveralls, "~> 0.6.2"}]
{:excoveralls, "~> 0.6.2"},
{:bamboo, "~> 0.7"},
{:bamboo_smtp, "~> 1.2.1"},
{:mock, "~> 0.2.0", only: :test}]
end

# Aliases are shortcuts or tasks specific to the current project.
Expand Down
8 changes: 7 additions & 1 deletion mix.lock
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
%{"certifi": {:hex, :certifi, "1.0.0", "1c787a85b1855ba354f0b8920392c19aa1d06b0ee1362f9141279620a5be2039", [:rebar3], []},
%{"bamboo": {:hex, :bamboo, "0.7.0", "2722e395a396dfedc12d300c900f65b216f7d7bf9d430c5dd0235690997878b7", [:mix], [{:httpoison, "~> 0.9", [hex: :httpoison, optional: false]}, {:plug, "~> 1.0", [hex: :plug, optional: false]}, {:poison, ">= 1.5.0", [hex: :poison, optional: false]}]},
"bamboo_smtp": {:hex, :bamboo_smtp, "1.2.1", "47181e338cbee9d028e94f2bc5829816b26d719d8213b07d0fa107d95b591947", [:mix], [{:bamboo, "~> 0.7.0", [hex: :bamboo, optional: false]}, {:gen_smtp, "~> 0.11.0", [hex: :gen_smtp, optional: false]}]},
"certifi": {:hex, :certifi, "1.0.0", "1c787a85b1855ba354f0b8920392c19aa1d06b0ee1362f9141279620a5be2039", [:rebar3], []},
"comeonin": {:hex, :comeonin, "2.6.0", "74c288338b33205f9ce97e2117bb9a2aaab103a1811d243443d76fdb62f904ac", [:make, :mix], []},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], []},
"cowboy": {:hex, :cowboy, "1.1.2", "61ac29ea970389a88eca5a65601460162d370a70018afe6f949a29dca91f3bb0", [:rebar3], [{:cowlib, "~> 1.0.2", [hex: :cowlib, optional: false]}, {:ranch, "~> 1.3.2", [hex: :ranch, optional: false]}]},
Expand All @@ -9,13 +11,17 @@
"excoveralls": {:hex, :excoveralls, "0.6.3", "894bf9254890a4aac1d1165da08145a72700ff42d8cb6ce8195a584cb2a4b374", [:mix], [{:exjsx, "~> 3.0", [hex: :exjsx, optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, optional: false]}]},
"exjsx": {:hex, :exjsx, "3.2.1", "1bc5bf1e4fd249104178f0885030bcd75a4526f4d2a1e976f4b428d347614f0f", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, optional: false]}]},
"fs": {:hex, :fs, "0.9.2", "ed17036c26c3f70ac49781ed9220a50c36775c6ca2cf8182d123b6566e49ec59", [:rebar], []},
"gen_smtp": {:hex, :gen_smtp, "0.11.0", "d90ff2f021fc86cb2a4259b1f2b177ab6e506676265e26454bf5755855adc956", [:rebar3], []},
"gettext": {:hex, :gettext, "0.13.1", "5e0daf4e7636d771c4c71ad5f3f53ba09a9ae5c250e1ab9c42ba9edccc476263", [:mix], []},
"hackney": {:hex, :hackney, "1.7.1", "e238c52c5df3c3b16ce613d3a51c7220a784d734879b1e231c9babd433ac1cb4", [:rebar3], [{:certifi, "1.0.0", [hex: :certifi, optional: false]}, {:idna, "4.0.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]}]},
"httpoison": {:hex, :httpoison, "0.11.1", "d06c571274c0e77b6cc50e548db3fd7779f611fbed6681fd60a331f66c143a0b", [:mix], [{:hackney, "~> 1.7.0", [hex: :hackney, optional: false]}]},
"idna": {:hex, :idna, "4.0.0", "10aaa9f79d0b12cf0def53038547855b91144f1bfcc0ec73494f38bb7b9c4961", [:rebar3], []},
"jsx": {:hex, :jsx, "2.8.2", "7acc7d785b5abe8a6e9adbde926a24e481f29956dd8b4df49e3e4e7bcc92a018", [:mix, :rebar3], []},
"meck": {:hex, :meck, "0.8.4", "59ca1cd971372aa223138efcf9b29475bde299e1953046a0c727184790ab1520", [:make, :rebar], []},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []},
"mime": {:hex, :mime, "1.1.0", "01c1d6f4083d8aa5c7b8c246ade95139620ef8effb009edde934e0ec3b28090a", [:mix], []},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []},
"mock": {:hex, :mock, "0.2.1", "bfdba786903e77f9c18772dee472d020ceb8ef000783e737725a4c8f54ad28ec", [:mix], [{:meck, "~> 0.8.2", [hex: :meck, optional: false]}]},
"phoenix": {:hex, :phoenix, "1.2.3", "b68dd6a7e6ff3eef38ad59771007d2f3f344988ea6e658e9b2c6ffb2ef494810", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, optional: false]}, {:plug, "~> 1.4 or ~> 1.3.3 or ~> 1.2.4 or ~> 1.1.8 or ~> 1.0.5", [hex: :plug, optional: false]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, optional: false]}]},
"phoenix_ecto": {:hex, :phoenix_ecto, "3.2.3", "450c749876ff1de4a78fdb305a142a76817c77a1cd79aeca29e5fc9a6c630b26", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, optional: true]}, {:plug, "~> 1.0", [hex: :plug, optional: false]}]},
"phoenix_html": {:hex, :phoenix_html, "2.9.3", "1b5a2122cbf743aa242f54dced8a4f1cc778b8bd304f4b4c0043a6250c58e258", [:mix], [{:plug, "~> 1.0", [hex: :plug, optional: false]}]},
Expand Down
37 changes: 32 additions & 5 deletions test/controllers/feedback_controller_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
defmodule Feedback.FeedbackControllerTest do
use Feedback.ConnCase, async: false
alias Feedback.{Email, Mailer}

import Mock

test "/feedback/new", %{conn: conn} do
conn = get conn, "/feedback/new"
Expand Down Expand Up @@ -54,18 +57,35 @@ defmodule Feedback.FeedbackControllerTest do
end

test "/feedback/:id update different request header", %{conn: conn} do
feedback = insert_feedback(%{submitter_email: "[email protected]"})
with_mock Mailer, [deliver_now: fn(_) -> nil end] do
conn =
conn
|> put_req_header("referer", "http://localhost:4000/feedback")
conn = put conn, feedback_path(conn, :update, feedback.id, %{"feedback" => %{"response" => "response"}})
assert redirected_to(conn, 302) =~ "/feedback/#{feedback.permalink_string}"
end
end

test "/feedback/:id update error email", %{conn: conn} do
feedback = insert_feedback()
conn = put conn, feedback_path(conn, :update, feedback.id, %{"feedback" => %{"submitter_email" => "invalid_email_format"}})
assert html_response(conn, 200) =~ "feedback"
end

test "/feedback/:id update error response", %{conn: conn} do
feedback = insert_feedback()
conn =
conn
|> put_req_header("referer", "http://localhost:4000/feedback")
conn = put conn, feedback_path(conn, :update, feedback.id, %{"feedback" => %{"response" => "response"}})
assert redirected_to(conn, 302) =~ "/feedback/#{feedback.permalink_string}"
conn = put conn, feedback_path(conn, :update, feedback.id, %{"feedback" => %{"response" => "a"}})
assert html_response(conn, 200) =~ "feedback"
end

test "/feedback/:id update error", %{conn: conn} do
test "/feedback/:id update email submit", %{conn: conn} do
feedback = insert_feedback()
conn = put conn, feedback_path(conn, :update, feedback.id, %{"feedback" => %{"submitter_email" => "invalid_email_format"}})
assert html_response(conn, 200) =~ "feedback"
conn = put conn, feedback_path(conn, :update, feedback.id, %{"feedback" => %{"submitter_email" => "[email protected]"}})
assert redirected_to(conn, 302) =~ "/feedback/#{feedback.permalink_string}"
end

test "/happy", %{conn: conn} do
Expand Down Expand Up @@ -122,4 +142,11 @@ defmodule Feedback.FeedbackControllerTest do
conn = get conn, feedback_path(conn, :angry)
assert html_response(conn, 200) =~ "angry"
end

test "strucuture of email is ok" do
email = Email.send_email("[email protected]", "Welcome", "Hello there")
assert email.to == "[email protected]"
assert email.subject == "Welcome"
assert email.text_body =~ "Hello there"
end
end
118 changes: 28 additions & 90 deletions web/controllers/feedback_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,34 @@ defmodule Feedback.FeedbackController do
def update(conn, %{"id" => id, "feedback" => feedback_params}) do
feedback = Repo.get!(Feedback, id)
changeset = Feedback.changeset(feedback, feedback_params)
case Repo.update(changeset) do
{:ok, feedback} ->
case get_referer(conn.req_headers) do
"forum" ->
conn
|> put_flash(:info, "Success!")
|> redirect(to: forum_path(conn, :forum_show, feedback.id))
_other ->
conn
|> put_flash(:info, "Success!")
|> redirect(to: feedback_path(conn, :show, feedback.permalink_string))
end

{:error, changeset} ->
render conn, "show.html", feedback: feedback, changeset: changeset
case Map.has_key?(feedback_params, "response") do
true ->
case Repo.update(changeset) do
{:ok, feedback} ->
case get_referer(conn.req_headers) do
"forum" ->
send_response_email_if_exists(feedback)
conn
|> put_flash(:info, "Response sent successfully!")
|> redirect(to: forum_path(conn, :forum_show, feedback.id))
_other ->
send_response_email_if_exists(feedback)
conn
|> put_flash(:info, "Response sent successfully!")
|> redirect(to: feedback_path(conn, :show, feedback.permalink_string))
end
{:error, changeset} ->
render conn, "show.html", feedback: feedback, changeset: changeset
end
false ->
case Repo.update(changeset) do
{:ok, _email} ->
conn
|> put_flash(:info, "Email submitted successfully!")
|> redirect(to: feedback_path(conn, :show, feedback.permalink_string))
{:error, changeset} ->
render conn, "show.html", feedback: feedback, changeset: changeset
end
end
end

Expand All @@ -81,27 +94,6 @@ defmodule Feedback.FeedbackController do
end
end

# def forum(conn, _params) do
# raw_feedback = Repo.all(Feedback)
# public_feedback =
# raw_feedback
# |> Enum.filter(fn item -> item.public end)
# |> sort_by_ascending_date()
# render conn, "forum.html", layout: {LayoutView, "forum.html"}, public_feedback: public_feedback
# end
#
# def forum_show(conn, %{"id" => permalink}) do
# case Repo.get_by(Feedback, permalink_string: permalink) do
# nil ->
# conn
# |> put_flash(:error, "That piece of feedback doesn't exist")
# |> redirect(to: page_path(conn, :index))
# feedback ->
# changeset = Feedback.changeset(feedback)
# render conn, "forum_show.html", layout: {LayoutView, "forum.html"}, feedback: feedback, changeset: changeset
# end
# end

def happy(conn, _params) do
feedback = get_feedback("happy")
responded_feedback = get_responded_feedback("happy")
Expand Down Expand Up @@ -138,58 +130,4 @@ defmodule Feedback.FeedbackController do
render conn, "angry.html", layout: {LayoutView, "nav.html"}, feedback: feedback, responded_feedback: responded_feedback
end


# defp generate_permalink_string(length) do
# :crypto.strong_rand_bytes(length) |> Base.url_encode64 |> binary_part(0, length)
# end
#
# def sort_by_ascending_date(enum) do
# enum |> Enum.sort(&(&1.inserted_at >= &2.inserted_at))
# end
#
# defp format_error(changeset) do
# errors = changeset.errors
# case length(errors) do
# 1 ->
# {key, _} = Enum.at(errors, 0)
# case key do
# :item ->
# "Make sure you write something in the feedback textbox"
# :mood ->
# "Make sure you select your mood"
# end
# 2 ->
# "To leave feedback, select your mood and write your thoughts in the
# textbox"
# end
# end
#
# defp get_feedback(emotion) do
# raw_feedback = Repo.all(Feedback)
# feedback =
# raw_feedback
# |> Enum.filter(fn item -> item.response == nil end)
# |> Enum.filter(fn item -> item.mood == emotion end)
# |> sort_by_ascending_date()
#
# feedback
# end
#
# defp get_responded_feedback(emotion) do
# raw_feedback = Repo.all(Feedback)
# responded_feedback =
# raw_feedback
# |> Enum.filter(fn item -> item.response != nil end)
# |> Enum.filter(fn item -> item.mood == emotion end)
# |> sort_by_ascending_date()
#
# responded_feedback
# end
#
# defp get_referer(headers) do
# [{_header, value}] = Enum.filter(headers, fn {header, _value} -> header == "referer" end)
# path = Enum.at(String.split(value, "/"), 3)
# path
# end

end
12 changes: 11 additions & 1 deletion web/controllers/helpers.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule Feedback.Controllers.Helpers do
alias Feedback.{Repo, Feedback}
alias Feedback.{Repo, Feedback, Email, Mailer}

def generate_permalink_string(length) do
:crypto.strong_rand_bytes(length) |> Base.url_encode64 |> binary_part(0, length)
Expand Down Expand Up @@ -54,4 +54,14 @@ defmodule Feedback.Controllers.Helpers do
path
end

def send_response_email_if_exists(feedback) do
link = "http://localhost:4000/feedback/#{feedback.permalink_string}"
subject = "Feedback Response"
message = "Hi there! There has been a response to your feedback. Follow this link #{link} to view it."
if feedback.submitter_email != nil do
Email.send_email(feedback.submitter_email, subject, message)
|> Mailer.deliver_now()
end
end

end
1 change: 1 addition & 0 deletions web/models/feedback.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ defmodule Feedback.Feedback do
:mood,
:public])
|> validate_format(:submitter_email, ~r/@/)
|> validate_length(:response, min: 2)
|> validate_required([:item, :permalink_string, :mood])
end

Expand Down

0 comments on commit 11f9e58

Please sign in to comment.