diff --git a/lib/factory.ex b/lib/factory.ex index 4355d78..7af0fe7 100644 --- a/lib/factory.ex +++ b/lib/factory.ex @@ -28,7 +28,7 @@ defmodule LaunchCart.Factory do %User{ email: Internet.email(), hashed_password: Bcrypt.hash_pwd_salt("password"), - active?: true + confirmed_at: DateTime.utc_now() } end diff --git a/lib/launch_cart/accounts.ex b/lib/launch_cart/accounts.ex index ebddeaf..10ea1bf 100644 --- a/lib/launch_cart/accounts.ex +++ b/lib/launch_cart/accounts.ex @@ -40,7 +40,7 @@ defmodule LaunchCart.Accounts do """ def get_user_by_email_and_password(email, password) when is_binary(email) and is_binary(password) do - user = Repo.get_by(User, email: email, active?: true) + user = Repo.get_by(User, email: email) if User.valid_password?(user, password), do: user end diff --git a/lib/launch_cart/accounts/user.ex b/lib/launch_cart/accounts/user.ex index 1613f49..6fb3293 100644 --- a/lib/launch_cart/accounts/user.ex +++ b/lib/launch_cart/accounts/user.ex @@ -34,8 +34,10 @@ defmodule LaunchCart.Accounts.User do """ def registration_changeset(user, attrs, opts \\ []) do user - |> cast(attrs, [:email, :notes]) + |> cast(attrs, [:email, :notes, :password]) |> validate_email() + |> validate_confirmation(:password, message: "does not match password") + |> validate_password(opts) end defp validate_email(changeset) do diff --git a/lib/launch_cart/accounts/user_notifier.ex b/lib/launch_cart/accounts/user_notifier.ex index 341c854..5d32c11 100644 --- a/lib/launch_cart/accounts/user_notifier.ex +++ b/lib/launch_cart/accounts/user_notifier.ex @@ -23,17 +23,15 @@ defmodule LaunchCart.Accounts.UserNotifier do def deliver_confirmation_instructions(user, url) do deliver(user.email, "Confirmation instructions", """ - ============================== - Hi #{user.email}, - You can confirm your account by visiting the URL below: + Thanks for signing for Launch Elements! You can confirm your account by visiting the URL below: #{url} If you didn't create an account with us, please ignore this. - ============================== + """) end @@ -43,8 +41,6 @@ defmodule LaunchCart.Accounts.UserNotifier do def deliver_reset_password_instructions(user, url) do deliver(user.email, "Reset password instructions", """ - ============================== - Hi #{user.email}, You can reset your password by visiting the URL below: @@ -52,8 +48,6 @@ defmodule LaunchCart.Accounts.UserNotifier do #{url} If you didn't request this change, please ignore this. - - ============================== """) end diff --git a/lib/launch_cart_web/controllers/user_registration_controller.ex b/lib/launch_cart_web/controllers/user_registration_controller.ex index 1619edd..095a936 100644 --- a/lib/launch_cart_web/controllers/user_registration_controller.ex +++ b/lib/launch_cart_web/controllers/user_registration_controller.ex @@ -3,7 +3,6 @@ defmodule LaunchCartWeb.UserRegistrationController do alias LaunchCart.Accounts alias LaunchCart.Accounts.User - alias LaunchCartWeb.UserAuth def new(conn, _params) do changeset = Accounts.change_user_registration(%User{}) @@ -11,9 +10,14 @@ defmodule LaunchCartWeb.UserRegistrationController do end def create(conn, %{"user" => user_params}) do - case Accounts.register_user(user_params) do - {:ok, user} -> render(conn, "thanks.html", user: user) - + with {:ok, user} <- Accounts.register_user(user_params), + {:ok, _} <- + Accounts.deliver_user_confirmation_instructions( + user, + &Routes.user_confirmation_url(conn, :edit, &1) + ) do + render(conn, "thanks.html", user: user) + else {:error, %Ecto.Changeset{} = changeset} -> render(conn, "new.html", changeset: changeset) end diff --git a/lib/launch_cart_web/controllers/user_session_controller.ex b/lib/launch_cart_web/controllers/user_session_controller.ex index fdd491d..eae2251 100644 --- a/lib/launch_cart_web/controllers/user_session_controller.ex +++ b/lib/launch_cart_web/controllers/user_session_controller.ex @@ -2,6 +2,7 @@ defmodule LaunchCartWeb.UserSessionController do use LaunchCartWeb, :controller alias LaunchCart.Accounts + alias LaunchCart.Accounts.User alias LaunchCartWeb.UserAuth def new(conn, _params) do @@ -11,11 +12,18 @@ defmodule LaunchCartWeb.UserSessionController do def create(conn, %{"user" => user_params}) do %{"email" => email, "password" => password} = user_params - if user = Accounts.get_user_by_email_and_password(email, password) do - UserAuth.log_in_user(conn, user, user_params) - else - # In order to prevent user enumeration attacks, don't disclose whether the email is registered. - render(conn, "new.html", error_message: "Invalid email or password") + case Accounts.get_user_by_email_and_password(email, password) do + %User{confirmed_at: nil} -> + render(conn, "new.html", + error_message: "Please check your email for confirmation instructions." + ) + + %User{} = user -> + UserAuth.log_in_user(conn, user, user_params) + + nil -> + # In order to prevent user enumeration attacks, don't disclose whether the email is registered + render(conn, "new.html", error_message: "Invalid email or password") end end diff --git a/lib/launch_cart_web/templates/user_registration/new.html.heex b/lib/launch_cart_web/templates/user_registration/new.html.heex index 7d3bb4d..5218ed2 100644 --- a/lib/launch_cart_web/templates/user_registration/new.html.heex +++ b/lib/launch_cart_web/templates/user_registration/new.html.heex @@ -1,7 +1,7 @@
-

Help us test Launch Elements!

-

We are currently in beta and looking for folks to help us test out our product. Interested? - Enter your email address and some info on what you are hoping to build, and we'll get right back to you!

+

Launch Elements enters Open Beta

+

We are currently in open beta testing from now until the end of November, 2023. Getting started is easy! + Fill out the form below, we'll confirm your email and you are on your way.

<.form let={f} for={@changeset} action={Routes.user_registration_path(@conn, :create)}> <%= if @changeset.action do %> @@ -17,7 +17,19 @@
- <%= label f, :notes %> + <%= label f, :password, "Password" %> + <%= password_input f, :password, required: true %> + <%= error_tag f, :password %> +
+ +
+ <%= label f, :password_confirmation, "Confirm password" %> + <%= password_input f, :password_confirmation, required: true %> + <%= error_tag f, :password_confirmation %> +
+ +
+ <%= label f, "Anything you'd like to tell us about what you're building?" %> <%= error_tag f, :notes %> <%= textarea f, :notes %>
diff --git a/lib/launch_cart_web/templates/user_registration/thanks.html.heex b/lib/launch_cart_web/templates/user_registration/thanks.html.heex index 8d0207f..0c64ff0 100644 --- a/lib/launch_cart_web/templates/user_registration/thanks.html.heex +++ b/lib/launch_cart_web/templates/user_registration/thanks.html.heex @@ -1,5 +1,5 @@

Thanks!

-

Thank you for your interest in testing our product. We know that getting real user feedback is the best way to build the right thing, so we can't thank you enough. We'll be in touch soon.

+

You should receive an email shortly. Follow the confirmation instructions and you are ready to start using Launch Elements!

Back to homepage
diff --git a/lib/launch_cart_web/templates/user_session/new.html.heex b/lib/launch_cart_web/templates/user_session/new.html.heex index 76d4616..0c3a9a0 100644 --- a/lib/launch_cart_web/templates/user_session/new.html.heex +++ b/lib/launch_cart_web/templates/user_session/new.html.heex @@ -31,6 +31,7 @@

- Don't have an account yet? <%= link "Register", to: Routes.user_registration_path(@conn, :new) %> for one now! + Don't have an account yet? <%= link "Register", to: Routes.user_registration_path(@conn, :new) %> for one now!
+ Need to confirm your email? <%= link "Resend confirmation instructions", to: Routes.user_confirmation_path(@conn, :new) %>

\ No newline at end of file diff --git a/test/launch_cart/accounts_test.exs b/test/launch_cart/accounts_test.exs index d865715..74c7808 100644 --- a/test/launch_cart/accounts_test.exs +++ b/test/launch_cart/accounts_test.exs @@ -35,10 +35,6 @@ defmodule LaunchCart.AccountsTest do assert %User{id: ^id} = Accounts.get_user_by_email_and_password(user.email, "password") end - test "does not return the user if they are not active" do - user = insert(:user, active?: false) - refute Accounts.get_user_by_email_and_password(user.email, "password") - end end describe "get_user!/1" do @@ -55,11 +51,12 @@ defmodule LaunchCart.AccountsTest do end describe "register_user/1" do - test "requires email" do + test "requires email and password" do {:error, changeset} = Accounts.register_user(%{}) assert %{ - email: ["can't be blank"] + email: ["can't be blank"], + password: ["can't be blank"] } = errors_on(changeset) end @@ -67,10 +64,16 @@ defmodule LaunchCart.AccountsTest do email = unique_user_email() {:ok, user} = - Accounts.register_user(%{email: email, notes: "I want to build something cool"}) + Accounts.register_user(%{ + email: email, + notes: "I want to build something cool", + password: "Password1234", + password_confirmation: "Password1234" + }) assert user.notes =~ ~r/cool/ - refute user.active? + refute user.confirmed_at + assert user.hashed_password assert_email_sent(fn %{to: [{_name, email_address}]} -> assert email_address =~ ~r/launchscout/ @@ -81,7 +84,9 @@ defmodule LaunchCart.AccountsTest do test "activate_user" do email = unique_user_email() - {:ok, %User{id: user_id} = user} = Accounts.register_user(%{email: email, notes: "I want to build something cool"}) + {:ok, %User{id: user_id} = user} = + Accounts.register_user(%{email: email, notes: "I want to build something cool"}) + assert {:ok, %User{id: ^user_id, active?: true}} = Accounts.activate_user(user) end diff --git a/test/launch_cart_web/controllers/user_registration_controller_test.exs b/test/launch_cart_web/controllers/user_registration_controller_test.exs index 96e1943..6f438ee 100644 --- a/test/launch_cart_web/controllers/user_registration_controller_test.exs +++ b/test/launch_cart_web/controllers/user_registration_controller_test.exs @@ -2,6 +2,9 @@ defmodule LaunchCartWeb.UserRegistrationControllerTest do alias ExDoc.Language use LaunchCartWeb.ConnCase, async: true + alias LaunchCart.Repo + alias LaunchCart.Accounts.{User, UserToken} + import LaunchCart.AccountsFixtures import LaunchCart.Factory @@ -9,7 +12,7 @@ defmodule LaunchCartWeb.UserRegistrationControllerTest do test "renders registration page", %{conn: conn} do conn = get(conn, Routes.user_registration_path(conn, :new)) response = html_response(conn, 200) - assert response =~ "Help us test Launch Elements!" + assert response =~ "Launch Elements enters Open Beta" assert response =~ "Log in" assert response =~ "Register" PallyTest.here(conn) @@ -23,16 +26,20 @@ defmodule LaunchCartWeb.UserRegistrationControllerTest do describe "POST /users/register" do @tag :capture_log - test "thanks the user", %{conn: conn} do + test "thanks the user and sends confirmation email", %{conn: conn} do email = unique_user_email() conn = post(conn, Routes.user_registration_path(conn, :create), %{ - "user" => %{email: email} + "user" => %{email: email, password: "Password1235", password_confirmation: "Password1235"} }) response = html_response(conn, 200) assert response =~ "Thanks" + + assert user = Repo.get_by!(User, email: email) + assert Repo.get_by!(UserToken, user_id: user.id).context == "confirm" + PallyTest.here(conn) end end diff --git a/test/launch_cart_web/controllers/user_session_controller_test.exs b/test/launch_cart_web/controllers/user_session_controller_test.exs index 44e06c5..e3d300e 100644 --- a/test/launch_cart_web/controllers/user_session_controller_test.exs +++ b/test/launch_cart_web/controllers/user_session_controller_test.exs @@ -82,6 +82,19 @@ defmodule LaunchCartWeb.UserSessionControllerTest do assert response =~ "Invalid email or password" PallyTest.here(conn) end + + test "Gives confirmation reminder for unconfirmed user", %{conn: conn} do + unconfirmed_user = insert(:user, confirmed_at: nil) + conn = + post(conn, Routes.user_session_path(conn, :create), %{ + "user" => %{"email" => unconfirmed_user.email, "password" => "password"} + }) + + response = html_response(conn, 200) + assert response =~ "

Log in

" + assert response =~ "Please check your email for confirmation instructions." + PallyTest.here(conn) + end end describe "DELETE /users/log_out" do