Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

open beta is open!! #65

Merged
merged 2 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion lib/factory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@ defmodule LaunchCart.Factory do
%User{
email: Internet.email(),
hashed_password: Bcrypt.hash_pwd_salt("password"),
active?: true
confirmed_at: DateTime.utc_now()
}
end

def unconfirmed_user_factory() do
%User{
email: Internet.email(),
hashed_password: Bcrypt.hash_pwd_salt("password")
}
end

Expand Down
2 changes: 1 addition & 1 deletion lib/launch_cart/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 3 additions & 1 deletion lib/launch_cart/accounts/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 2 additions & 8 deletions lib/launch_cart/accounts/user_notifier.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -43,17 +41,13 @@ 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:

#{url}

If you didn't request this change, please ignore this.

==============================
""")
end

Expand Down
12 changes: 8 additions & 4 deletions lib/launch_cart_web/controllers/user_registration_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ 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{})
render(conn, "new.html", changeset: changeset)
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
Expand Down
18 changes: 13 additions & 5 deletions lib/launch_cart_web/controllers/user_session_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
20 changes: 16 additions & 4 deletions lib/launch_cart_web/templates/user_registration/new.html.heex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="card card--contained u-centered u-push__top--xl">
<h1>Help us test Launch Elements!</h1>
<p>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!</p>
<h1>Launch Elements enters Open Beta</h1>
<p>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.</p>

<.form let={f} for={@changeset} action={Routes.user_registration_path(@conn, :create)}>
<%= if @changeset.action do %>
Expand All @@ -17,7 +17,19 @@
</div>

<div class="input-group">
<%= label f, :notes %>
<%= label f, :password, "Password" %>
<%= password_input f, :password, required: true %>
<%= error_tag f, :password %>
</div>

<div class="input-group">
<%= label f, :password_confirmation, "Confirm password" %>
<%= password_input f, :password_confirmation, required: true %>
<%= error_tag f, :password_confirmation %>
</div>

<div class="input-group">
<%= label f, "Anything you'd like to tell us about what you're building?" %>
<%= error_tag f, :notes %>
<%= textarea f, :notes %>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<section class="card">
<h1>Thanks!</h1>
<p>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.</p>
<p>You should receive an email shortly. Follow the confirmation instructions and you are ready to start using Launch Elements!</p>
<a class="button" href="/">Back to homepage</a>
</section>
3 changes: 2 additions & 1 deletion lib/launch_cart_web/templates/user_session/new.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
</.form>

<p class="u-push__top--lg">
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! <br/>
Need to confirm your email? <%= link "Resend confirmation instructions", to: Routes.user_confirmation_path(@conn, :new) %>
</p>
</div>
39 changes: 24 additions & 15 deletions test/launch_cart/accounts_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,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
Expand All @@ -55,22 +50,29 @@ 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

test "creates a disabled user and notifies a Launch Scout" 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/
Expand All @@ -81,14 +83,22 @@ 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",
password: "Password1234",
password_confirmation: "Password1234"
})

assert {:ok, %User{id: ^user_id, active?: true}} = Accounts.activate_user(user)
end

describe "change_user_registration/2" do
test "returns a changeset" do
assert %Ecto.Changeset{} = changeset = Accounts.change_user_registration(%User{})
assert changeset.required == [:email]
assert :password in changeset.required
assert :email in changeset.required
end

test "allows fields to be set" do
Expand All @@ -97,7 +107,7 @@ defmodule LaunchCart.AccountsTest do
changeset =
Accounts.change_user_registration(
%User{},
%{email: email}
%{email: email, password: "Password1234", password_confirmation: "Password1234"}
)

assert changeset.valid?
Expand Down Expand Up @@ -198,7 +208,6 @@ defmodule LaunchCart.AccountsTest do
assert changed_user.email != user.email
assert changed_user.email == email
assert changed_user.confirmed_at
assert changed_user.confirmed_at != user.confirmed_at
refute Repo.get_by(UserToken, user_id: user.id)
end

Expand Down Expand Up @@ -350,7 +359,7 @@ defmodule LaunchCart.AccountsTest do

describe "deliver_user_confirmation_instructions/2" do
setup do
%{user: insert(:user)}
%{user: insert(:unconfirmed_user)}
end

test "sends token through notification", %{user: user} do
Expand All @@ -369,7 +378,7 @@ defmodule LaunchCart.AccountsTest do

describe "confirm_user/1" do
setup do
user = insert(:user)
user = insert(:unconfirmed_user)

token =
extract_user_token(fn url ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule LaunchCartWeb.UserConfirmationControllerTest do
import LaunchCart.Factory

setup do
%{user: insert(:user)}
%{user: insert(:unconfirmed_user)}
end

describe "GET /users/confirm" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ 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

describe "GET /users/register" 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</a>"
assert response =~ "Register</a>"
PallyTest.here(conn)
Expand All @@ -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
Expand Down
13 changes: 13 additions & 0 deletions test/launch_cart_web/controllers/user_session_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =~ "<h1>Log in</h1>"
assert response =~ "Please check your email for confirmation instructions."
PallyTest.here(conn)
end
end

describe "DELETE /users/log_out" do
Expand Down
Loading