diff --git a/extensions/confirmable/lib/confirmable.ex b/extensions/confirmable/lib/confirmable.ex index 96d3021..251e96e 100644 --- a/extensions/confirmable/lib/confirmable.ex +++ b/extensions/confirmable/lib/confirmable.ex @@ -2,6 +2,7 @@ defmodule Confirmable do def send_confirmation?, do: config(:send_confirmation, true) def mailer, do: config(:mailer, Confirmable.Mailer) def email_view, do: config(:email_view, Confirmable.EmailView) + def ttl, do: config(:confirmation_ttl_in_days, 30) @doc false defp config(key), do: config_entry(key) diff --git a/extensions/confirmable/lib/confirmable/resource.ex b/extensions/confirmable/lib/confirmable/resource.ex index a642f67..511207c 100644 --- a/extensions/confirmable/lib/confirmable/resource.ex +++ b/extensions/confirmable/lib/confirmable/resource.ex @@ -18,11 +18,32 @@ defmodule Confirmable.Resource do true -> {:ok, resource} false -> {:ok, datetime} = Ecto.DateTime.cast(:calendar.universal_time()) - Ecto.Changeset.change(resource, %{confirmed_at: datetime}) - |> Concierge.repo.update + case confirmation_expired?(resource) do + true -> {:error, "Expired confirmation token!"} + false -> + Ecto.Changeset.change(resource, %{confirmed_at: datetime}) + |> Concierge.repo.update + end end end + @doc """ + Verifies if confirmation has been expired or not + """ + def confirmation_expired?(resource) do + {:ok, datetime} = Ecto.DateTime.cast(:calendar.universal_time()) + {:ok, send_at} = Ecto.DateTime.cast(resource.confirmation_sent_at) + greater_than_ttl_days?(Ecto.DateTime.to_erl(send_at), Ecto.DateTime.to_erl(datetime), Confirmable.ttl) + end + + @doc """ + Verifies if date A is greater than date B by TTL days or not + """ + def greater_than_ttl_days?(a, b, ttl) do + min = ttl * 24 * 60 * 60 + (:calendar.datetime_to_gregorian_seconds(b) - :calendar.datetime_to_gregorian_seconds(a)) >= min + end + @doc """ Verifies whether a resource is confirmed or not """ diff --git a/extensions/confirmable/test/controller/confirmation_controller_test.exs b/extensions/confirmable/test/controller/confirmation_controller_test.exs index 2a00e72..5b2ad6d 100644 --- a/extensions/confirmable/test/controller/confirmation_controller_test.exs +++ b/extensions/confirmable/test/controller/confirmation_controller_test.exs @@ -38,7 +38,7 @@ defmodule Confirmable.ConfirmationControllerTest do conn = get(conn, Concierge.route_helpers.confirmation_path(conn, :show), [email: user.email, confirmation_token: "invalid_token"]) - assert conn.status == 422 + assert get_flash(conn, "error") == "Confirmation token is invalid" user = Confirmable.TestRepo.get(Confirmable.TestUser, user.id) refute Confirmable.Resource.confirmed?(user) @@ -54,9 +54,28 @@ defmodule Confirmable.ConfirmationControllerTest do conn = get(conn, Concierge.route_helpers.confirmation_path(conn, :show), [email: user.email]) - assert conn.status == 422 + assert get_flash(conn, "error") == "Invalid parameters" user = Confirmable.TestRepo.get(Confirmable.TestUser, user.id) refute Confirmable.Resource.confirmed?(user) end + + test "shows error when registration token has been expired" do + {:ok, user = %Confirmable.TestUser{}} = Concierge.Resource.Registration.create(%{ + "email" => "concierge@test.com", + "password" => "123456789", + "password_confirmation" => "123456789", + }) + + user = Confirmable.TestRepo.get(Confirmable.TestUser, user.id) + {:ok, expired} = Ecto.DateTime.cast("2015-05-05 12:27:33") + user = Ecto.Changeset.change user, confirmation_sent_at: expired + Confirmable.TestRepo.update user + + conn = get(conn, Concierge.route_helpers.confirmation_path(conn, :show), + [email: user.email, confirmation_token: user.confirmation_token]) + + assert get_flash(conn, "error") == "Expired confirmation token!" + + end end diff --git a/extensions/confirmable/web/controllers/confirmation_controller.ex b/extensions/confirmable/web/controllers/confirmation_controller.ex index 92f0cbb..d4e1c17 100644 --- a/extensions/confirmable/web/controllers/confirmation_controller.ex +++ b/extensions/confirmable/web/controllers/confirmation_controller.ex @@ -4,6 +4,7 @@ defmodule Concierge.Confirmable.ConfirmationController do def show(conn, %{"email" => email, "confirmation_token" => confirmation_token}) do case Confirmable.Resource.confirm!(email, confirmation_token) do {:ok, resource} -> sign_in_and_redirect(conn, resource) + {:error, message} -> error!(conn, message) {:error} -> error!(conn, "Confirmation token is invalid") end end @@ -15,7 +16,6 @@ defmodule Concierge.Confirmable.ConfirmationController do defp error!(conn, message) do conn |> put_flash(:error, message) - |> put_status(:unprocessable_entity) |> redirect(to: "/") end end \ No newline at end of file