Merge auth links into main nav and lower password min to 8
- Register/Log in (or callsign/Settings/Log out) now live next to the Map/Path/Rover links in the main header instead of a separate top menu bar - Add on_mount in UserAuth to assign current_scope on LiveView mount, and pass current_scope through to Layouts.app from every LiveView - Drop the old top <ul> from root.html.heex - Password minimum lowered from 12 to 8 characters
This commit is contained in:
parent
adaa17719a
commit
a8995bb43b
13 changed files with 50 additions and 34 deletions
|
|
@ -131,7 +131,7 @@ defmodule Microwaveprop.Accounts.User do
|
||||||
defp validate_password(changeset, opts) do
|
defp validate_password(changeset, opts) do
|
||||||
changeset
|
changeset
|
||||||
|> validate_required([:password])
|
|> validate_required([:password])
|
||||||
|> validate_length(:password, min: 12, max: 72)
|
|> validate_length(:password, min: 8, max: 72)
|
||||||
# Examples of additional password validation:
|
# Examples of additional password validation:
|
||||||
# |> validate_format(:password, ~r/[a-z]/, message: "at least one lower case character")
|
# |> validate_format(:password, ~r/[a-z]/, message: "at least one lower case character")
|
||||||
# |> validate_format(:password, ~r/[A-Z]/, message: "at least one upper case character")
|
# |> validate_format(:password, ~r/[A-Z]/, message: "at least one upper case character")
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,8 @@ defmodule MicrowavepropWeb do
|
||||||
quote do
|
quote do
|
||||||
use Phoenix.LiveView
|
use Phoenix.LiveView
|
||||||
|
|
||||||
|
on_mount MicrowavepropWeb.UserAuth
|
||||||
|
|
||||||
unquote(html_helpers())
|
unquote(html_helpers())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,18 @@ defmodule MicrowavepropWeb.Layouts do
|
||||||
<.link navigate="/contacts/map" class="btn btn-ghost btn-sm">Contact Map</.link>
|
<.link navigate="/contacts/map" class="btn btn-ghost btn-sm">Contact Map</.link>
|
||||||
<.link navigate="/contacts" class="btn btn-ghost btn-sm">Contacts</.link>
|
<.link navigate="/contacts" class="btn btn-ghost btn-sm">Contacts</.link>
|
||||||
<.link navigate="/submit" class="btn btn-ghost btn-sm">Submit</.link>
|
<.link navigate="/submit" class="btn btn-ghost btn-sm">Submit</.link>
|
||||||
|
<%= if @current_scope && @current_scope.user do %>
|
||||||
|
<span class="btn btn-ghost btn-sm pointer-events-none opacity-70">
|
||||||
|
{@current_scope.user.callsign}
|
||||||
|
</span>
|
||||||
|
<.link href={~p"/users/settings"} class="btn btn-ghost btn-sm">Settings</.link>
|
||||||
|
<.link href={~p"/users/log-out"} method="delete" class="btn btn-ghost btn-sm">
|
||||||
|
Log out
|
||||||
|
</.link>
|
||||||
|
<% else %>
|
||||||
|
<.link href={~p"/users/register"} class="btn btn-ghost btn-sm">Register</.link>
|
||||||
|
<.link href={~p"/users/log-in"} class="btn btn-ghost btn-sm">Log in</.link>
|
||||||
|
<% end %>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-none">
|
<div class="flex-none">
|
||||||
|
|
|
||||||
|
|
@ -37,26 +37,6 @@
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<ul class="menu menu-horizontal w-full relative z-10 flex items-center gap-4 px-4 sm:px-6 lg:px-8 justify-end">
|
|
||||||
<%= if @current_scope do %>
|
|
||||||
<li>
|
|
||||||
{@current_scope.user.email}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<.link href={~p"/users/settings"}>Settings</.link>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<.link href={~p"/users/log-out"} method="delete">Log out</.link>
|
|
||||||
</li>
|
|
||||||
<% else %>
|
|
||||||
<li>
|
|
||||||
<.link href={~p"/users/register"}>Register</.link>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<.link href={~p"/users/log-in"}>Log in</.link>
|
|
||||||
</li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
{@inner_content}
|
{@inner_content}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ defmodule MicrowavepropWeb.AlgoLive do
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<Layouts.app flash={@flash}>
|
<Layouts.app flash={@flash} current_scope={@current_scope}>
|
||||||
<div class="markdown-content">
|
<div class="markdown-content">
|
||||||
{raw(@content)}
|
{raw(@content)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -311,7 +311,7 @@ defmodule MicrowavepropWeb.BackfillLive do
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<Layouts.app flash={@flash}>
|
<Layouts.app flash={@flash} current_scope={@current_scope}>
|
||||||
<.header>
|
<.header>
|
||||||
Backfill Dashboard
|
Backfill Dashboard
|
||||||
<:subtitle>Enqueue and monitor contact enrichment jobs</:subtitle>
|
<:subtitle>Enqueue and monitor contact enrichment jobs</:subtitle>
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ defmodule MicrowavepropWeb.ContactLive.Index do
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<Layouts.app flash={@flash} max_width="max-w-7xl">
|
<Layouts.app flash={@flash} current_scope={@current_scope} max_width="max-w-7xl">
|
||||||
<.header>
|
<.header>
|
||||||
Contacts
|
Contacts
|
||||||
<:subtitle>{@total_entries} contacts</:subtitle>
|
<:subtitle>{@total_entries} contacts</:subtitle>
|
||||||
|
|
|
||||||
|
|
@ -435,7 +435,7 @@ defmodule MicrowavepropWeb.ContactLive.Show do
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<Layouts.app flash={@flash}>
|
<Layouts.app flash={@flash} current_scope={@current_scope}>
|
||||||
<.header>
|
<.header>
|
||||||
<span class={[@contact.flagged_invalid && "line-through opacity-50"]}>
|
<span class={[@contact.flagged_invalid && "line-through opacity-50"]}>
|
||||||
{@contact.station1} / {@contact.station2}
|
{@contact.station1} / {@contact.station2}
|
||||||
|
|
|
||||||
|
|
@ -466,7 +466,7 @@ defmodule MicrowavepropWeb.PathLive do
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<Layouts.app flash={@flash} max_width="max-w-6xl">
|
<Layouts.app flash={@flash} current_scope={@current_scope} max_width="max-w-6xl">
|
||||||
<.header>
|
<.header>
|
||||||
Path Calculator
|
Path Calculator
|
||||||
<:subtitle>Analyze microwave propagation between two points</:subtitle>
|
<:subtitle>Analyze microwave propagation between two points</:subtitle>
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ defmodule MicrowavepropWeb.SubmitLive do
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<Layouts.app flash={@flash}>
|
<Layouts.app flash={@flash} current_scope={@current_scope}>
|
||||||
<.header>
|
<.header>
|
||||||
Submit Contact
|
Submit Contact
|
||||||
<:subtitle>Help us build a better propagation model</:subtitle>
|
<:subtitle>Help us build a better propagation model</:subtitle>
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,28 @@ defmodule MicrowavepropWeb.UserAuth do
|
||||||
same_site: "Lax"
|
same_site: "Lax"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
LiveView `on_mount` callback that assigns `:current_scope` from the
|
||||||
|
session token so LiveView templates can show auth-aware navigation.
|
||||||
|
"""
|
||||||
|
def on_mount(:default, _params, session, socket) do
|
||||||
|
{:cont, mount_current_scope(socket, session)}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp mount_current_scope(socket, session) do
|
||||||
|
Phoenix.Component.assign_new(socket, :current_scope, fn ->
|
||||||
|
user =
|
||||||
|
with token when is_binary(token) <- session["user_token"],
|
||||||
|
{user, _inserted_at} <- Accounts.get_user_by_session_token(token) do
|
||||||
|
user
|
||||||
|
else
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
|
||||||
|
Scope.for_user(user)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
# How old the session token should be before a new one is issued. When a request is made
|
# How old the session token should be before a new one is issued. When a request is made
|
||||||
# with a session token older than this value, then a new session token will be created
|
# with a session token older than this value, then a new session token will be created
|
||||||
# and the session and remember-me cookies (if set) will be updated with the new token.
|
# and the session and remember-me cookies (if set) will be updated with the new token.
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ defmodule Microwaveprop.AccountsTest do
|
||||||
{:error, changeset} =
|
{:error, changeset} =
|
||||||
Accounts.register_user(valid_user_attributes(password: "short"))
|
Accounts.register_user(valid_user_attributes(password: "short"))
|
||||||
|
|
||||||
assert "should be at least 12 character(s)" in errors_on(changeset).password
|
assert "should be at least 8 character(s)" in errors_on(changeset).password
|
||||||
end
|
end
|
||||||
|
|
||||||
test "registers a valid user but leaves them unconfirmed" do
|
test "registers a valid user but leaves them unconfirmed" do
|
||||||
|
|
@ -323,12 +323,12 @@ defmodule Microwaveprop.AccountsTest do
|
||||||
test "validates password", %{user: user} do
|
test "validates password", %{user: user} do
|
||||||
{:error, changeset} =
|
{:error, changeset} =
|
||||||
Accounts.update_user_password(user, %{
|
Accounts.update_user_password(user, %{
|
||||||
password: "not valid",
|
password: "short",
|
||||||
password_confirmation: "another"
|
password_confirmation: "other"
|
||||||
})
|
})
|
||||||
|
|
||||||
assert %{
|
assert %{
|
||||||
password: ["should be at least 12 character(s)"],
|
password: ["should be at least 8 character(s)"],
|
||||||
password_confirmation: ["does not match password"]
|
password_confirmation: ["does not match password"]
|
||||||
} = errors_on(changeset)
|
} = errors_on(changeset)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -56,14 +56,14 @@ defmodule MicrowavepropWeb.UserSettingsControllerTest do
|
||||||
put(conn, ~p"/users/settings", %{
|
put(conn, ~p"/users/settings", %{
|
||||||
"action" => "update_password",
|
"action" => "update_password",
|
||||||
"user" => %{
|
"user" => %{
|
||||||
"password" => "too short",
|
"password" => "short",
|
||||||
"password_confirmation" => "does not match"
|
"password_confirmation" => "nope"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
response = html_response(old_password_conn, 200)
|
response = html_response(old_password_conn, 200)
|
||||||
assert response =~ "Settings"
|
assert response =~ "Settings"
|
||||||
assert response =~ "should be at least 12 character(s)"
|
assert response =~ "should be at least 8 character(s)"
|
||||||
assert response =~ "does not match password"
|
assert response =~ "does not match password"
|
||||||
|
|
||||||
assert get_session(old_password_conn, :user_token) == get_session(conn, :user_token)
|
assert get_session(old_password_conn, :user_token) == get_session(conn, :user_token)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue