- <.flash kind={:info} title="Success!" flash={@flash} />
- <.flash kind={:error} title="Error!" flash={@flash} />
- <.flash
- id="disconnected"
- kind={:error}
- title="We can't find the internet"
- close={false}
- autoshow={false}
- phx-disconnected={show("#disconnected")}
- phx-connected={hide("#disconnected")}
- >
- Attempting to reconnect
-
+
+ <.flash_group flash={@flash} />
<%= @inner_content %>
diff --git a/lib/something_erlang_web/components/layouts/root.html.heex b/lib/something_erlang_web/components/layouts/root.html.heex
index f858d56..add12ce 100644
--- a/lib/something_erlang_web/components/layouts/root.html.heex
+++ b/lib/something_erlang_web/components/layouts/root.html.heex
@@ -1,5 +1,5 @@
-
+
@@ -11,28 +11,7 @@
-
-
- <%= if @current_user do %>
-
- <%= @current_user.bbuserid %>
-
-
- <.link href={~p"/users/settings"}>Settings
-
-
- <.link href={~p"/users/log_out"} method="delete">Log out
-
- <% else %>
-
- <.link href={~p"/users/register"}>Register
-
-
- <.link href={~p"/users/log_in"}>Log in
-
- <% end %>
-
-
+
<%= @inner_content %>
diff --git a/lib/something_erlang_web/controllers/error_html.ex b/lib/something_erlang_web/controllers/error_html.ex
index f50105b..947d818 100644
--- a/lib/something_erlang_web/controllers/error_html.ex
+++ b/lib/something_erlang_web/controllers/error_html.ex
@@ -1,4 +1,9 @@
defmodule SomethingErlangWeb.ErrorHTML do
+ @moduledoc """
+ This module is invoked by your endpoint in case of errors on HTML requests.
+
+ See config/config.exs.
+ """
use SomethingErlangWeb, :html
# If you want to customize your error pages,
diff --git a/lib/something_erlang_web/controllers/error_json.ex b/lib/something_erlang_web/controllers/error_json.ex
index 60ddadc..d8756f7 100644
--- a/lib/something_erlang_web/controllers/error_json.ex
+++ b/lib/something_erlang_web/controllers/error_json.ex
@@ -1,4 +1,10 @@
defmodule SomethingErlangWeb.ErrorJSON do
+ @moduledoc """
+ This module is invoked by your endpoint in case of errors on JSON requests.
+
+ See config/config.exs.
+ """
+
# If you want to customize a particular status code,
# you may add your own clauses, such as:
#
diff --git a/lib/something_erlang_web/controllers/page_controller.ex b/lib/something_erlang_web/controllers/page_controller.ex
index f41f5ce..8a93aee 100644
--- a/lib/something_erlang_web/controllers/page_controller.ex
+++ b/lib/something_erlang_web/controllers/page_controller.ex
@@ -1,33 +1,9 @@
defmodule SomethingErlangWeb.PageController do
use SomethingErlangWeb, :controller
- def home(conn, params) do
+ def home(conn, _params) do
# The home page is often custom made,
# so skip the default app layout.
- conn = assign(conn, :params, params)
- render(conn, :home)
- end
-
- def to_forum_path(conn, %{"forum_path" => path} = _params) do
- {redirect_good, thread, page} =
- case {
- Regex.run(~r{threadid=(\d+)}, path),
- Regex.run(~r{pagenumber=(\d+)}, path)
- } do
- {[_, thread], nil} -> {:ok, thread, 1}
- {[_, thread], [_, page]} -> {:ok, thread, page}
- _ -> {:error, nil, nil}
- end
-
- if redirect_good == :ok do
- redirect(conn, to: ~p"/thread/#{thread}?page=#{page}")
- else
- put_flash(conn, :error, "Could not resolve URL")
- render(conn, :home)
- end
- end
-
- def to_forum_path(conn, _params) do
- render(conn, :home)
+ render(conn, :home, layout: false)
end
end
diff --git a/lib/something_erlang_web/controllers/page_html.ex b/lib/something_erlang_web/controllers/page_html.ex
index 2d01b91..faf055d 100644
--- a/lib/something_erlang_web/controllers/page_html.ex
+++ b/lib/something_erlang_web/controllers/page_html.ex
@@ -1,4 +1,9 @@
defmodule SomethingErlangWeb.PageHTML do
+ @moduledoc """
+ This module contains pages rendered by PageController.
+
+ See the `page_html` directory for all templates available.
+ """
use SomethingErlangWeb, :html
embed_templates "page_html/*"
diff --git a/lib/something_erlang_web/controllers/page_html/default.html.heex b/lib/something_erlang_web/controllers/page_html/default.html.heex
deleted file mode 100644
index 619f097..0000000
--- a/lib/something_erlang_web/controllers/page_html/default.html.heex
+++ /dev/null
@@ -1,236 +0,0 @@
-
-
-
-
-
-
-
- Phoenix Framework
-
- v1.7
-
-
-
- Peace of mind from prototype to production.
-
-
- Build rich, interactive web applications quickly, with less code and fewer moving parts. Join our growing community of developers using Phoenix to craft APIs, HTML5 apps and more, for fun or at scale.
-
-
-
-
diff --git a/lib/something_erlang_web/controllers/page_html/home.html.heex b/lib/something_erlang_web/controllers/page_html/home.html.heex
index c65e960..dc1820b 100644
--- a/lib/something_erlang_web/controllers/page_html/home.html.heex
+++ b/lib/something_erlang_web/controllers/page_html/home.html.heex
@@ -1,9 +1,222 @@
-<.form :let={f} for={@conn} action={~p"/"}>
-
-
-
-
-
- <%= inspect(@current_user) %>
- <%= inspect(@conn.cookies) %>
-
+<.flash_group flash={@flash} />
+
+
+
+
+
+
+
+ Phoenix Framework
+
+ v<%= Application.spec(:phoenix, :vsn) %>
+
+
+
+ Peace of mind from prototype to production.
+
+
+ Build rich, interactive web applications quickly, with less code and fewer moving parts. Join our growing community of developers using Phoenix to craft APIs, HTML5 apps and more, for fun or at scale.
+
+
+
+
diff --git a/lib/something_erlang_web/controllers/user_session_controller.ex b/lib/something_erlang_web/controllers/user_session_controller.ex
deleted file mode 100644
index 8086df9..0000000
--- a/lib/something_erlang_web/controllers/user_session_controller.ex
+++ /dev/null
@@ -1,42 +0,0 @@
-defmodule SomethingErlangWeb.UserSessionController do
- use SomethingErlangWeb, :controller
-
- alias SomethingErlang.Accounts
- alias SomethingErlangWeb.UserAuth
-
- def create(conn, %{"_action" => "registered"} = params) do
- create(conn, params, "Account created successfully!")
- end
-
- def create(conn, %{"_action" => "password_updated"} = params) do
- conn
- |> put_session(:user_return_to, ~p"/users/settings")
- |> create(params, "Password updated successfully!")
- end
-
- def create(conn, params) do
- create(conn, params, "Welcome back!")
- end
-
- defp create(conn, %{"user" => user_params}, info) do
- %{"username" => username, "password" => password} = user_params
-
- if user = Accounts.login_sa_user_and_get_cookies(username, password) do
- conn
- |> put_flash(:info, info)
- |> put_session(:bbpassword, user.bbpassword)
- |> UserAuth.log_in_user(user, user_params)
- else
- conn
- |> put_flash(:error, "Login failed!")
- |> put_flash(:email, String.slice(username, 0, 160))
- |> redirect(to: ~p"/users/log_in")
- end
- end
-
- def delete(conn, _params) do
- conn
- |> put_flash(:info, "Logged out successfully.")
- |> UserAuth.log_out_user()
- end
-end
diff --git a/lib/something_erlang_web/endpoint.ex b/lib/something_erlang_web/endpoint.ex
index 294eec2..c34e0d6 100644
--- a/lib/something_erlang_web/endpoint.ex
+++ b/lib/something_erlang_web/endpoint.ex
@@ -7,11 +7,13 @@ defmodule SomethingErlangWeb.Endpoint do
@session_options [
store: :cookie,
key: "_something_erlang_key",
- signing_salt: "0z4XWrxF",
+ signing_salt: "23G6hSX1",
same_site: "Lax"
]
- socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]
+ socket "/live", Phoenix.LiveView.Socket,
+ websocket: [connect_info: [session: @session_options]],
+ longpoll: [connect_info: [session: @session_options]]
# Serve at "/" the static files from "priv/static" directory.
#
diff --git a/lib/something_erlang_web/live/thread_live.ex b/lib/something_erlang_web/live/thread_live.ex
deleted file mode 100644
index fe56d57..0000000
--- a/lib/something_erlang_web/live/thread_live.ex
+++ /dev/null
@@ -1,163 +0,0 @@
-defmodule SomethingErlangWeb.ThreadLive do
- use SomethingErlangWeb, :live_view
-
- alias SomethingErlang.Grover
-
- def render(%{thread: _} = assigns) do
- ~H"""
-
- <%= raw(@thread.title) %>
-
-
-
- <.pagination thread={@thread} />
-
- <%= for %{userinfo: author, postdate: date, postbody: article} <- @thread.posts do %>
- <.post author={author} date={date}>
- <%= raw(article) %>
-
- <% end %>
-
- <.pagination thread={@thread} />
-
- """
- end
-
- def render(assigns) do
- ~H"""
-
- Threads!
-
-
- <%= inspect(@current_user) %>
-
- """
- end
-
- def post(assigns) do
- ~H"""
-
- <.user info={@author} />
-
- <%= render_slot(@inner_block) %>
-
- <.toolbar date={@date} />
-
- """
- end
-
- def user(assigns) do
- ~H"""
-
- """
- end
-
- def toolbar(assigns) do
- ~H"""
-
- <%= @date |> Calendar.strftime("%A, %b %d %Y @ %H:%M") %>
-
- """
- end
-
- def pagination(assigns) do
- ~H"""
-
- """
- end
-
- defp label_button(%{label: "«", page: page} = assigns),
- do: ~H"""
-
<%= page %>
- """
-
- defp label_button(%{label: "‹", page: page} = assigns),
- do: ~H"""
-
<%= page %>
- """
-
- defp label_button(%{label: "›", page: page} = assigns),
- do: ~H"""
- <%= page %>
- """
-
- defp label_button(%{label: "»", page: page} = assigns),
- do: ~H"""
- <%= page %>
- """
-
- defp label_button(%{page: page} = assigns),
- do: ~H"""
- <%= page %>
- """
-
- defp buttons(thread) do
- %{page: page_number, page_count: page_count} = thread
-
- first_page_disabled_button = if page_number == 1, do: " btn-disabled", else: ""
- last_page_disabled_button = if page_number == page_count, do: " btn-disabled", else: ""
- active_page_button = " btn-active"
-
- prev_button_target = if page_number > 1, do: page_number - 1, else: 1
- next_button_target = if page_number < page_count, do: page_number + 1, else: page_count
-
- [
- %{label: "«", page: 1, special: "" <> first_page_disabled_button},
- %{label: "‹", page: prev_button_target, special: "" <> first_page_disabled_button},
- %{label: "#{page_number}", page: page_number, special: active_page_button},
- %{label: "›", page: next_button_target, special: "" <> last_page_disabled_button},
- %{label: "»", page: page_count, special: "" <> last_page_disabled_button}
- ]
- end
-
- def mount(_params, session, socket) do
- user =
- socket.assigns.current_user
- |> Map.put(:bbpassword, session["bbpassword"])
-
- Grover.mount(user)
-
- {:ok, socket}
- end
-
- def handle_params(%{"id" => id, "page" => page}, _, socket) do
- thread = Grover.get_thread!(id, page |> String.to_integer())
-
- {:noreply,
- socket
- |> assign(:page_title, thread.title)
- |> assign(:thread, thread)}
- end
-
- def handle_params(%{"id" => id}, _, socket) do
- params = %{page: 1}
-
- {:noreply,
- push_patch(
- socket,
- to: ~p"/thread/#{id}?#{params}",
- replace: true
- )}
- end
-
- def handle_params(%{}, _, socket) do
- {:noreply, socket}
- end
-end
diff --git a/lib/something_erlang_web/live/user_login_live.ex b/lib/something_erlang_web/live/user_login_live.ex
deleted file mode 100644
index 7ea83ef..0000000
--- a/lib/something_erlang_web/live/user_login_live.ex
+++ /dev/null
@@ -1,43 +0,0 @@
-defmodule SomethingErlangWeb.UserLoginLive do
- use SomethingErlangWeb, :live_view
-
- def render(assigns) do
- ~H"""
-
- <.header class="text-center text-neutral-content">
- Sign in to account
- <:subtitle>
- Don't have an account?
- <.link navigate={~p"/users/register"} class="font-semibold text-brand hover:underline">
- Sign up
-
- for an account now.
-
-
-
- <.simple_form for={@form} id="login_form" action={~p"/users/log_in"} phx-update="ignore">
- <.input field={@form[:username]} type="text" label="Username" required />
- <.input field={@form[:password]} type="password" label="Password" required />
-
- <:actions>
- <.input field={@form[:remember_me]} type="checkbox" label="Keep me logged in" />
- <.link href={~p"/users/reset_password"} class="text-sm font-semibold">
- Forgot your password?
-
-
- <:actions>
- <.button phx-disable-with="Signing in..." class="w-full">
- Sign in →
-
-
-
-
- """
- end
-
- def mount(_params, _session, socket) do
- email = live_flash(socket.assigns.flash, :email)
- form = to_form(%{"email" => email}, as: "user")
- {:ok, assign(socket, form: form), temporary_assigns: [form: form]}
- end
-end
diff --git a/lib/something_erlang_web/router.ex b/lib/something_erlang_web/router.ex
index c06aa13..d577c02 100644
--- a/lib/something_erlang_web/router.ex
+++ b/lib/something_erlang_web/router.ex
@@ -1,17 +1,13 @@
defmodule SomethingErlangWeb.Router do
use SomethingErlangWeb, :router
- import SomethingErlangWeb.UserAuth
-
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
- plug :put_root_layout, {SomethingErlangWeb.Layouts, :root}
+ plug :put_root_layout, html: {SomethingErlangWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
- plug :fetch_current_user
- plug :load_bbcookie
end
pipeline :api do
@@ -19,36 +15,15 @@ defmodule SomethingErlangWeb.Router do
end
scope "/", SomethingErlangWeb do
- pipe_through [:browser]
+ pipe_through :browser
get "/", PageController, :home
- post "/", PageController, :to_forum_path
-
- live_session :user_browsing,
- on_mount: [{SomethingErlangWeb.UserAuth, :ensure_authenticated}] do
- live "/thread", ThreadLive
- live "/thread/:id", ThreadLive
- end
end
- ## Authentication routes
-
- scope "/", SomethingErlangWeb do
- pipe_through [:browser, :redirect_if_user_is_authenticated]
-
- live_session :redirect_if_user_is_authenticated,
- on_mount: [{SomethingErlangWeb.UserAuth, :redirect_if_user_is_authenticated}] do
- live "/users/log_in", UserLoginLive, :new
- end
-
- post "/users/log_in", UserSessionController, :create
- end
-
- scope "/", SomethingErlangWeb do
- pipe_through [:browser]
-
- delete "/users/log_out", UserSessionController, :delete
- end
+ # Other scopes may use custom stacks.
+ # scope "/api", SomethingErlangWeb do
+ # pipe_through :api
+ # end
# Enable LiveDashboard and Swoosh mailbox preview in development
if Application.compile_env(:something_erlang, :dev_routes) do
@@ -62,10 +37,7 @@ defmodule SomethingErlangWeb.Router do
scope "/dev" do
pipe_through :browser
- live_dashboard "/dashboard",
- ecto_repos: [SomethingErlang.Repo],
- metrics: SomethingErlangWeb.Telemetry
-
+ live_dashboard "/dashboard", metrics: SomethingErlangWeb.Telemetry
forward "/mailbox", Plug.Swoosh.MailboxPreview
end
end
diff --git a/lib/something_erlang_web/telemetry.ex b/lib/something_erlang_web/telemetry.ex
index ba506cb..9914ad3 100644
--- a/lib/something_erlang_web/telemetry.ex
+++ b/lib/something_erlang_web/telemetry.ex
@@ -43,7 +43,7 @@ defmodule SomethingErlangWeb.Telemetry do
summary("phoenix.socket_connected.duration",
unit: {:native, :millisecond}
),
- summary("phoenix.channel_join.duration",
+ summary("phoenix.channel_joined.duration",
unit: {:native, :millisecond}
),
summary("phoenix.channel_handled_in.duration",
diff --git a/lib/something_erlang_web/user_auth.ex b/lib/something_erlang_web/user_auth.ex
deleted file mode 100644
index c1cf867..0000000
--- a/lib/something_erlang_web/user_auth.ex
+++ /dev/null
@@ -1,242 +0,0 @@
-defmodule SomethingErlangWeb.UserAuth do
- use SomethingErlangWeb, :verified_routes
-
- import Plug.Conn
- import Phoenix.Controller
-
- alias SomethingErlang.Accounts
-
- # Make the remember me cookie valid for 60 days.
- # If you want bump or reduce this value, also change
- # the token expiry itself in UserToken.
- @max_age 60 * 60 * 24 * 60
- @remember_me_cookie "_something_erlang_web_user_remember_me"
- @remember_me_options [sign: true, max_age: @max_age, same_site: "Lax"]
-
- @doc """
- Logs the user in.
-
- It renews the session ID and clears the whole session
- to avoid fixation attacks. See the renew_session
- function to customize this behaviour.
-
- It also sets a `:live_socket_id` key in the session,
- so LiveView sessions are identified and automatically
- disconnected on log out. The line can be safely removed
- if you are not using LiveView.
- """
- def log_in_user(conn, user, params \\ %{}) do
- token = Accounts.generate_user_session_token(user)
- user_return_to = get_session(conn, :user_return_to)
-
- conn
- |> renew_session()
- |> put_hashcookie_in_session(user.bbpassword)
- |> put_token_in_session(token)
- |> maybe_write_remember_me_cookie(token, params)
- |> redirect(to: user_return_to || signed_in_path(conn))
- end
-
- defp put_hashcookie_in_session(conn, bbpassword) do
- put_resp_cookie(conn, "bbpassword", bbpassword)
- end
-
- defp maybe_write_remember_me_cookie(conn, token, %{"remember_me" => "true"}) do
- put_resp_cookie(conn, @remember_me_cookie, token, @remember_me_options)
- end
-
- defp maybe_write_remember_me_cookie(conn, _token, _params) do
- conn
- end
-
- # This function renews the session ID and erases the whole
- # session to avoid fixation attacks. If there is any data
- # in the session you may want to preserve after log in/log out,
- # you must explicitly fetch the session data before clearing
- # and then immediately set it after clearing, for example:
- #
- # defp renew_session(conn) do
- # preferred_locale = get_session(conn, :preferred_locale)
- #
- # conn
- # |> configure_session(renew: true)
- # |> clear_session()
- # |> put_session(:preferred_locale, preferred_locale)
- # end
- #
- defp renew_session(conn) do
- conn
- |> configure_session(renew: true)
- |> clear_session()
- end
-
- @doc """
- Logs the user out.
-
- It clears all session data for safety. See renew_session.
- """
- def log_out_user(conn) do
- user_token = get_session(conn, :user_token)
- user_token && Accounts.delete_user_session_token(user_token)
-
- if live_socket_id = get_session(conn, :live_socket_id) do
- SomethingErlangWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{})
- end
-
- conn
- |> renew_session()
- |> delete_resp_cookie(@remember_me_cookie)
- |> redirect(to: "/")
- end
-
- def load_bbcookie(conn, _opts) do
- conn
- |> put_session(:bbpassword, conn.cookies["bbpassword"])
- end
-
- @doc """
- Authenticates the user by looking into the session
- and remember me token.
- """
- def fetch_current_user(conn, _opts) do
- {user_token, conn} = ensure_user_token(conn)
- user = user_token && Accounts.get_user_by_session_token(user_token)
-
- assign(conn, :current_user, user)
- end
-
- defp ensure_user_token(conn) do
- if token = get_session(conn, :user_token) do
- {token, conn}
- else
- conn = fetch_cookies(conn, signed: [@remember_me_cookie])
-
- if token = conn.cookies[@remember_me_cookie] do
- {token, put_token_in_session(conn, token)}
- else
- {nil, conn}
- end
- end
- end
-
- @doc """
- Handles mounting and authenticating the current_user in LiveViews.
-
- ## `on_mount` arguments
-
- * `:mount_current_user` - Assigns current_user
- to socket assigns based on user_token, or nil if
- there's no user_token or no matching user.
-
- * `:ensure_authenticated` - Authenticates the user from the session,
- and assigns the current_user to socket assigns based
- on user_token.
- Redirects to login page if there's no logged user.
-
- * `:redirect_if_user_is_authenticated` - Authenticates the user from the session.
- Redirects to signed_in_path if there's a logged user.
-
- ## Examples
-
- Use the `on_mount` lifecycle macro in LiveViews to mount or authenticate
- the current_user:
-
- defmodule SomethingErlangWeb.PageLive do
- use SomethingErlangWeb, :live_view
-
- on_mount {SomethingErlangWeb.UserAuth, :mount_current_user}
- ...
- end
-
- Or use the `live_session` of your router to invoke the on_mount callback:
-
- live_session :authenticated, on_mount: [{SomethingErlangWeb.UserAuth, :ensure_authenticated}] do
- live "/profile", ProfileLive, :index
- end
- """
- def on_mount(:mount_current_user, _params, session, socket) do
- {:cont, mount_current_user(session, socket)}
- end
-
- def on_mount(:ensure_authenticated, _params, session, socket) do
- socket = mount_current_user(session, socket)
-
- if socket.assigns.current_user do
- {:cont, socket}
- else
- socket =
- socket
- |> Phoenix.LiveView.put_flash(:error, "You must log in to access this page.")
- |> Phoenix.LiveView.redirect(to: ~p"/users/log_in")
-
- {:halt, socket}
- end
- end
-
- def on_mount(:redirect_if_user_is_authenticated, _params, session, socket) do
- socket = mount_current_user(session, socket)
-
- if socket.assigns.current_user do
- {:halt, Phoenix.LiveView.redirect(socket, to: signed_in_path(socket))}
- else
- {:cont, socket}
- end
- end
-
- defp mount_current_user(session, socket) do
- case session do
- %{"user_token" => user_token} ->
- Phoenix.Component.assign_new(socket, :current_user, fn ->
- Accounts.get_user_by_session_token(user_token)
- end)
-
- %{} ->
- Phoenix.Component.assign_new(socket, :current_user, fn -> nil end)
- end
- end
-
- @doc """
- Used for routes that require the user to not be authenticated.
- """
- def redirect_if_user_is_authenticated(conn, _opts) do
- if conn.assigns[:current_user] do
- conn
- |> redirect(to: signed_in_path(conn))
- |> halt()
- else
- conn
- end
- end
-
- @doc """
- Used for routes that require the user to be authenticated.
-
- If you want to enforce the user email is confirmed before
- they use the application at all, here would be a good place.
- """
- def require_authenticated_user(conn, _opts) do
- if conn.assigns[:current_user] do
- conn
- else
- conn
- |> put_flash(:error, "You must log in to access this page.")
- |> maybe_store_return_to()
- |> redirect(to: ~p"/users/log_in")
- |> halt()
- end
- end
-
- defp put_token_in_session(conn, token) do
- conn
- |> put_session(:user_token, token)
- |> put_session(:live_socket_id, "users_sessions:#{Base.url_encode64(token)}")
- end
-
- defp maybe_store_return_to(%{method: "GET"} = conn) do
- put_session(conn, :user_return_to, current_path(conn))
- end
-
- defp maybe_store_return_to(conn), do: conn
-
- defp signed_in_path(_conn), do: ~p"/"
-end
diff --git a/mix.exs b/mix.exs
index 605456a..394c89f 100644
--- a/mix.exs
+++ b/mix.exs
@@ -19,7 +19,7 @@ defmodule SomethingErlang.MixProject do
def application do
[
mod: {SomethingErlang.Application, []},
- extra_applications: [:logger, :runtime_tools, :os_mon]
+ extra_applications: [:logger, :runtime_tools]
]
end
@@ -32,29 +32,32 @@ defmodule SomethingErlang.MixProject do
# Type `mix help deps` for examples and options.
defp deps do
[
- {:bcrypt_elixir, "~> 3.0"},
- {:phoenix, "~> 1.7.0-rc.2", override: true},
+ {:phoenix, "~> 1.7.12"},
{:phoenix_ecto, "~> 4.4"},
- {:ecto_sql, "~> 3.10"},
- {:ecto_psql_extras, "~> 0.6"},
+ {:ecto_sql, "~> 3.10"},
{:postgrex, ">= 0.0.0"},
- {:phoenix_html, "~> 3.0"},
+ {:phoenix_html, "~> 4.0"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
- {:phoenix_live_view, "~> 0.18.3"},
- {:heroicons, "~> 0.5"},
- {:floki, ">= 0.30.0"},
- {:phoenix_live_dashboard, "~> 0.7.2"},
- {:esbuild, "~> 0.5", runtime: Mix.env() == :dev},
- {:tailwind, "~> 0.1.8", runtime: Mix.env() == :dev},
- {:swoosh, "~> 1.3"},
+ {:phoenix_live_view, "~> 0.20.2"},
+ {:floki, ">= 0.30.0", only: :test},
+ {:phoenix_live_dashboard, "~> 0.8.3"},
+ {:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
+ {:tailwind, "~> 0.2", runtime: Mix.env() == :dev},
+ {:heroicons,
+ github: "tailwindlabs/heroicons",
+ tag: "v2.1.1",
+ sparse: "optimized",
+ app: false,
+ compile: false,
+ depth: 1},
+ {:swoosh, "~> 1.5"},
{:finch, "~> 0.13"},
- {:telemetry_metrics, "~> 0.6"},
+ {:telemetry_metrics, "~> 1.0"},
{:telemetry_poller, "~> 1.0"},
{:gettext, "~> 0.20"},
{:jason, "~> 1.2"},
- {:bandit, "~> 1.0"},
- {:credo, "~> 1.6", only: [:dev, :test], runtime: false},
- {:req, "~> 0.3"}
+ {:dns_cluster, "~> 0.1.1"},
+ {:bandit, "~> 1.2"}
]
end
@@ -66,12 +69,17 @@ defmodule SomethingErlang.MixProject do
# See the documentation for `Mix` for more info on aliases.
defp aliases do
[
- setup: ["deps.get", "ecto.setup", "assets.setup"],
+ setup: ["deps.get", "ecto.setup", "assets.setup", "assets.build"],
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
"assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
- "assets.deploy": ["tailwind default --minify", "esbuild default --minify", "phx.digest"]
+ "assets.build": ["tailwind something_erlang", "esbuild something_erlang"],
+ "assets.deploy": [
+ "tailwind something_erlang --minify",
+ "esbuild something_erlang --minify",
+ "phx.digest"
+ ]
]
end
end
diff --git a/mix.lock b/mix.lock
index ea50e02..c88b0e9 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,54 +1,40 @@
%{
- "bandit": {:hex, :bandit, "1.4.0", "fdf9c4b9e3a2d8579540ff90f74f514e5bec25f8cb1c7ede6fddd409509e5b4b", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "2d068334fe7a4ea17161b875aa112bfa7d62060e8eefb1a1117b2ab6a817e04f"},
- "bcrypt_elixir": {:hex, :bcrypt_elixir, "3.1.0", "0b110a9a6c619b19a7f73fa3004aa11d6e719a67e672d1633dc36b6b2290a0f7", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2ad2acb5a8bc049e8d5aa267802631912bb80d5f4110a178ae7999e69dca1bf7"},
- "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
- "castore": {:hex, :castore, "1.0.6", "ffc42f110ebfdafab0ea159cd43d31365fa0af0ce4a02ecebf1707ae619ee727", [:mix], [], "hexpm", "374c6e7ca752296be3d6780a6d5b922854ffcc74123da90f2f328996b962d33a"},
- "comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"},
- "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
- "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
- "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
- "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
- "credo": {:hex, :credo, "1.7.5", "643213503b1c766ec0496d828c90c424471ea54da77c8a168c725686377b9545", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f799e9b5cd1891577d8c773d245668aa74a2fcd15eb277f51a0131690ebfb3fd"},
+ "bandit": {:hex, :bandit, "1.5.2", "ed0a41c43a9e529c670d0fd48371db4027e7b80d43b1942893e17deb8bed0540", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "35ddbdce7e8a2a3c6b5093f7299d70832a43ed2f4a1852885a61d334cab1b4ad"},
+ "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"},
"db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
+ "dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"},
"ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
- "ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.15", "0fc29dbae0e444a29bd6abeee4cf3c4c037e692a272478a234a1cc765077dbb1", [:mix], [{:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1 or ~> 4.0.0", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "b6127f3a5c6fc3d84895e4768cc7c199f22b48b67d6c99b13fbf4a374e73f039"},
- "ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"},
- "elixir_make": {:hex, :elixir_make, "0.8.3", "d38d7ee1578d722d89b4d452a3e36bcfdc644c618f0d063b874661876e708683", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "5c99a18571a756d4af7a4d89ca75c28ac899e6103af6f223982f09ce44942cc9"},
+ "ecto_sql": {:hex, :ecto_sql, "3.11.2", "c7cc7f812af571e50b80294dc2e535821b3b795ce8008d07aa5f336591a185a8", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "73c07f995ac17dbf89d3cfaaf688fcefabcd18b7b004ac63b0dc4ef39499ed6b"},
"esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
"expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"},
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
"finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
- "floki": {:hex, :floki, "0.36.1", "712b7f2ba19a4d5a47dfe3e74d81876c95bbcbee44fe551f0af3d2a388abb3da", [:mix], [], "hexpm", "21ba57abb8204bcc70c439b423fc0dd9f0286de67dc82773a14b0200ada0995f"},
+ "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
"gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
- "heroicons": {:hex, :heroicons, "0.5.5", "c2bcb05a90f010df246a5a2a2b54cac15483b5de137b2ef0bead77fcdf06e21a", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:phoenix_live_view, ">= 0.18.2", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "2f4bf929440fecd5191ba9f40e5009b0f75dc993d765c0e4d068fcb7026d6da1"},
+ "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized"]},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
- "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"},
- "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
- "nimble_ownership": {:hex, :nimble_ownership, "0.3.1", "99d5244672fafdfac89bfad3d3ab8f0d367603ce1dc4855f86a1c75008bce56f", [:mix], [], "hexpm", "4bf510adedff0449a1d6e200e43e57a814794c8b5b6439071274d248d272a549"},
+ "mint": {:hex, :mint, "1.6.0", "88a4f91cd690508a04ff1c3e28952f322528934be541844d54e0ceb765f01d5e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "3c5ae85d90a5aca0a49c0d8b67360bbe407f3b54f1030a111047ff988e8fefaa"},
+ "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
- "phoenix": {:hex, :phoenix, "1.7.11", "1d88fc6b05ab0c735b250932c4e6e33bfa1c186f76dcf623d8dd52f07d6379c7", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "b1ec57f2e40316b306708fe59b92a16b9f6f4bf50ccfa41aa8c7feb79e0ec02a"},
- "phoenix_ecto": {:hex, :phoenix_ecto, "4.5.1", "6fdbc334ea53620e71655664df6f33f670747b3a7a6c4041cdda3e2c32df6257", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ebe43aa580db129e54408e719fb9659b7f9e0d52b965c5be26cdca416ecead28"},
- "phoenix_html": {:hex, :phoenix_html, "3.3.3", "380b8fb45912b5638d2f1d925a3771b4516b9a78587249cabe394e0a5d579dc9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "923ebe6fec6e2e3b3e569dfbdc6560de932cd54b000ada0208b5f45024bdd76c"},
- "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"},
- "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.2", "354460993a480656b71c3887f5565f612b3bdbdd8688c83f9e6f512307067dd4", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "2bb3722f327e14a7aa47b1acf27ed633c8cd27b167e18b8237954b9b4804af39"},
- "phoenix_live_view": {:hex, :phoenix_live_view, "0.18.18", "1f38fbd7c363723f19aad1a04b5490ff3a178e37daaf6999594d5f34796c47fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a5810d0472f3189ede6d2a95bda7f31c6113156b91784a3426cb0ab6a6d85214"},
+ "phoenix": {:hex, :phoenix, "1.7.12", "1cc589e0eab99f593a8aa38ec45f15d25297dd6187ee801c8de8947090b5a9d3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "d646192fbade9f485b01bc9920c139bfdd19d0f8df3d73fd8eaf2dfbe0d2837c"},
+ "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.1", "96798325fab2fed5a824ca204e877b81f9afd2e480f581e81f7b4b64a5a477f2", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.17", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "0ae544ff99f3c482b0807c5cec2c8289e810ecacabc04959d82c3337f4703391"},
+ "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"},
+ "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.3", "7ff51c9b6609470f681fbea20578dede0e548302b0c8bdf338b5a753a4f045bf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f9470a0a8bae4f56430a23d42f977b5a6205fdba6559d76f932b876bfaec652d"},
+ "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"},
+ "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.14", "70fa101aa0539e81bed4238777498f6215e9dda3461bdaa067cad6908110c364", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "82f6d006c5264f979ed5eb75593d808bbe39020f20df2e78426f4f2d570e2402"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
- "plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"},
- "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"},
- "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
- "postgrex": {:hex, :postgrex, "0.17.5", "0483d054938a8dc069b21bdd636bf56c487404c241ce6c319c1f43588246b281", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "50b8b11afbb2c4095a3ba675b4f055c416d0f3d7de6633a595fc131a828a67eb"},
- "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
- "req": {:hex, :req, "0.4.14", "103de133a076a31044e5458e0f850d5681eef23dfabf3ea34af63212e3b902e2", [:mix], [{:aws_signature, "~> 0.3.2", [hex: :aws_signature, repo: "hexpm", optional: true]}, {:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:nimble_ownership, "~> 0.2.0 or ~> 0.3.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "2ddd3d33f9ab714ced8d3c15fd03db40c14dbf129003c4a3eb80fac2cc0b1b08"},
- "swoosh": {:hex, :swoosh, "1.16.3", "4ab7dc429e84afaf8ffe1c7c06ce1acbc7ddde758d2cb9152dd2ac32289d5498", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.1.0", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ff70980087650a72951ebd109a286d83c270e2b6610aba447140562adff8cf0a"},
- "table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"},
- "tailwind": {:hex, :tailwind, "0.1.10", "21ed80ae1f411f747ee513470578acaaa1d0eb40170005350c5b0b6d07e2d624", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "e0fc474dfa8ed7a4573851ac69c5fd3ca70fbb0a5bada574d1d657ebc6f2f1f1"},
+ "plug": {:hex, :plug, "1.16.0", "1d07d50cb9bb05097fdf187b31cf087c7297aafc3fed8299aac79c128a707e47", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cbf53aa1f5c4d758a7559c0bd6d59e286c2be0c6a1fac8cc3eee2f638243b93e"},
+ "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
+ "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"},
+ "swoosh": {:hex, :swoosh, "1.16.9", "20c6a32ea49136a4c19f538e27739bb5070558c0fa76b8a95f4d5d5ca7d319a1", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.0", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "878b1a7a6c10ebbf725a3349363f48f79c5e3d792eb621643b0d276a38acc0a6"},
+ "tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
- "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"},
- "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
+ "telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"},
+ "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
"thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"},
diff --git a/priv/gettext/errors.pot b/priv/gettext/errors.pot
index ccf5c68..eef2de2 100644
--- a/priv/gettext/errors.pot
+++ b/priv/gettext/errors.pot
@@ -7,7 +7,6 @@
## Run `mix gettext.extract` to bring this file up to
## date. Leave `msgstr`s empty as changing them here has no
## effect: edit them in PO (`.po`) files instead.
-
## From Ecto.Changeset.cast/4
msgid "can't be blank"
msgstr ""
diff --git a/priv/repo/migrations/20230118110156_create_users_auth_tables.exs b/priv/repo/migrations/20230118110156_create_users_auth_tables.exs
deleted file mode 100644
index 0cb6c00..0000000
--- a/priv/repo/migrations/20230118110156_create_users_auth_tables.exs
+++ /dev/null
@@ -1,27 +0,0 @@
-defmodule SomethingErlang.Repo.Migrations.CreateUsersAuthTables do
- use Ecto.Migration
-
- def change do
- execute "CREATE EXTENSION IF NOT EXISTS citext", ""
-
- create table(:users) do
- add :email, :citext, null: false
- add :hashed_password, :string, null: false
- add :confirmed_at, :naive_datetime
- timestamps()
- end
-
- create unique_index(:users, [:email])
-
- create table(:users_tokens) do
- add :user_id, references(:users, on_delete: :delete_all), null: false
- add :token, :binary, null: false
- add :context, :string, null: false
- add :sent_to, :string
- timestamps(updated_at: false)
- end
-
- create index(:users_tokens, [:user_id])
- create unique_index(:users_tokens, [:context, :token])
- end
-end
diff --git a/priv/repo/migrations/20240329091549_add_bbuserid.exs b/priv/repo/migrations/20240329091549_add_bbuserid.exs
deleted file mode 100644
index 80265e1..0000000
--- a/priv/repo/migrations/20240329091549_add_bbuserid.exs
+++ /dev/null
@@ -1,15 +0,0 @@
-defmodule SomethingErlang.Repo.Migrations.AddBbuserid do
- use Ecto.Migration
-
- def change do
- alter table(:users) do
- remove :email
- remove :hashed_password
- remove :confirmed_at
- add :bbuserid, :citext
- end
-
- # drop index(:users, [:email])
- create unique_index(:users, [:bbuserid])
- end
-end
diff --git a/priv/static/favicon.ico b/priv/static/favicon.ico
index 73de524..7f372bf 100644
Binary files a/priv/static/favicon.ico and b/priv/static/favicon.ico differ
diff --git a/priv/static/images/logo.svg b/priv/static/images/logo.svg
new file mode 100644
index 0000000..9f26bab
--- /dev/null
+++ b/priv/static/images/logo.svg
@@ -0,0 +1,6 @@
+
+
+
diff --git a/rel/overlays/bin/migrate b/rel/overlays/bin/migrate
deleted file mode 100755
index 4f9bc3f..0000000
--- a/rel/overlays/bin/migrate
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-set -eu
-
-cd -P -- "$(dirname -- "$0")"
-exec ./something_erlang eval SomethingErlang.Release.migrate
diff --git a/rel/overlays/bin/migrate.bat b/rel/overlays/bin/migrate.bat
deleted file mode 100755
index 1e58f22..0000000
--- a/rel/overlays/bin/migrate.bat
+++ /dev/null
@@ -1 +0,0 @@
-call "%~dp0\something_erlang" eval SomethingErlang.Release.migrate
diff --git a/rel/overlays/bin/server b/rel/overlays/bin/server
deleted file mode 100755
index 06a872c..0000000
--- a/rel/overlays/bin/server
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-set -eu
-
-cd -P -- "$(dirname -- "$0")"
-PHX_SERVER=true exec ./something_erlang start
diff --git a/rel/overlays/bin/server.bat b/rel/overlays/bin/server.bat
deleted file mode 100755
index 32948fa..0000000
--- a/rel/overlays/bin/server.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-set PHX_SERVER=true
-call "%~dp0\something_erlang" start
diff --git a/test/something_erlang/accounts_test.exs b/test/something_erlang/accounts_test.exs
deleted file mode 100644
index 795be85..0000000
--- a/test/something_erlang/accounts_test.exs
+++ /dev/null
@@ -1,508 +0,0 @@
-defmodule SomethingErlang.AccountsTest do
- use SomethingErlang.DataCase
-
- alias SomethingErlang.Accounts
-
- import SomethingErlang.AccountsFixtures
- alias SomethingErlang.Accounts.{User, UserToken}
-
- describe "get_user_by_email/1" do
- test "does not return the user if the email does not exist" do
- refute Accounts.get_user_by_email("unknown@example.com")
- end
-
- test "returns the user if the email exists" do
- %{id: id} = user = user_fixture()
- assert %User{id: ^id} = Accounts.get_user_by_email(user.email)
- end
- end
-
- describe "get_user_by_email_and_password/2" do
- test "does not return the user if the email does not exist" do
- refute Accounts.get_user_by_email_and_password("unknown@example.com", "hello world!")
- end
-
- test "does not return the user if the password is not valid" do
- user = user_fixture()
- refute Accounts.get_user_by_email_and_password(user.email, "invalid")
- end
-
- test "returns the user if the email and password are valid" do
- %{id: id} = user = user_fixture()
-
- assert %User{id: ^id} =
- Accounts.get_user_by_email_and_password(user.email, valid_user_password())
- end
- end
-
- describe "get_user!/1" do
- test "raises if id is invalid" do
- assert_raise Ecto.NoResultsError, fn ->
- Accounts.get_user!(-1)
- end
- end
-
- test "returns the user with the given id" do
- %{id: id} = user = user_fixture()
- assert %User{id: ^id} = Accounts.get_user!(user.id)
- end
- end
-
- describe "register_user/1" do
- test "requires email and password to be set" do
- {:error, changeset} = Accounts.register_user(%{})
-
- assert %{
- password: ["can't be blank"],
- email: ["can't be blank"]
- } = errors_on(changeset)
- end
-
- test "validates email and password when given" do
- {:error, changeset} = Accounts.register_user(%{email: "not valid", password: "not valid"})
-
- assert %{
- email: ["must have the @ sign and no spaces"],
- password: ["should be at least 12 character(s)"]
- } = errors_on(changeset)
- end
-
- test "validates maximum values for email and password for security" do
- too_long = String.duplicate("db", 100)
- {:error, changeset} = Accounts.register_user(%{email: too_long, password: too_long})
- assert "should be at most 160 character(s)" in errors_on(changeset).email
- assert "should be at most 72 character(s)" in errors_on(changeset).password
- end
-
- test "validates email uniqueness" do
- %{email: email} = user_fixture()
- {:error, changeset} = Accounts.register_user(%{email: email})
- assert "has already been taken" in errors_on(changeset).email
-
- # Now try with the upper cased email too, to check that email case is ignored.
- {:error, changeset} = Accounts.register_user(%{email: String.upcase(email)})
- assert "has already been taken" in errors_on(changeset).email
- end
-
- test "registers users with a hashed password" do
- email = unique_user_email()
- {:ok, user} = Accounts.register_user(valid_user_attributes(email: email))
- assert user.email == email
- assert is_binary(user.hashed_password)
- assert is_nil(user.confirmed_at)
- assert is_nil(user.password)
- end
- end
-
- describe "change_user_registration/2" do
- test "returns a changeset" do
- assert %Ecto.Changeset{} = changeset = Accounts.change_user_registration(%User{})
- assert changeset.required == [:password, :email]
- end
-
- test "allows fields to be set" do
- email = unique_user_email()
- password = valid_user_password()
-
- changeset =
- Accounts.change_user_registration(
- %User{},
- valid_user_attributes(email: email, password: password)
- )
-
- assert changeset.valid?
- assert get_change(changeset, :email) == email
- assert get_change(changeset, :password) == password
- assert is_nil(get_change(changeset, :hashed_password))
- end
- end
-
- describe "change_user_email/2" do
- test "returns a user changeset" do
- assert %Ecto.Changeset{} = changeset = Accounts.change_user_email(%User{})
- assert changeset.required == [:email]
- end
- end
-
- describe "apply_user_email/3" do
- setup do
- %{user: user_fixture()}
- end
-
- test "requires email to change", %{user: user} do
- {:error, changeset} = Accounts.apply_user_email(user, valid_user_password(), %{})
- assert %{email: ["did not change"]} = errors_on(changeset)
- end
-
- test "validates email", %{user: user} do
- {:error, changeset} =
- Accounts.apply_user_email(user, valid_user_password(), %{email: "not valid"})
-
- assert %{email: ["must have the @ sign and no spaces"]} = errors_on(changeset)
- end
-
- test "validates maximum value for email for security", %{user: user} do
- too_long = String.duplicate("db", 100)
-
- {:error, changeset} =
- Accounts.apply_user_email(user, valid_user_password(), %{email: too_long})
-
- assert "should be at most 160 character(s)" in errors_on(changeset).email
- end
-
- test "validates email uniqueness", %{user: user} do
- %{email: email} = user_fixture()
- password = valid_user_password()
-
- {:error, changeset} = Accounts.apply_user_email(user, password, %{email: email})
-
- assert "has already been taken" in errors_on(changeset).email
- end
-
- test "validates current password", %{user: user} do
- {:error, changeset} =
- Accounts.apply_user_email(user, "invalid", %{email: unique_user_email()})
-
- assert %{current_password: ["is not valid"]} = errors_on(changeset)
- end
-
- test "applies the email without persisting it", %{user: user} do
- email = unique_user_email()
- {:ok, user} = Accounts.apply_user_email(user, valid_user_password(), %{email: email})
- assert user.email == email
- assert Accounts.get_user!(user.id).email != email
- end
- end
-
- describe "deliver_user_update_email_instructions/3" do
- setup do
- %{user: user_fixture()}
- end
-
- test "sends token through notification", %{user: user} do
- token =
- extract_user_token(fn url ->
- Accounts.deliver_user_update_email_instructions(user, "current@example.com", url)
- end)
-
- {:ok, token} = Base.url_decode64(token, padding: false)
- assert user_token = Repo.get_by(UserToken, token: :crypto.hash(:sha256, token))
- assert user_token.user_id == user.id
- assert user_token.sent_to == user.email
- assert user_token.context == "change:current@example.com"
- end
- end
-
- describe "update_user_email/2" do
- setup do
- user = user_fixture()
- email = unique_user_email()
-
- token =
- extract_user_token(fn url ->
- Accounts.deliver_user_update_email_instructions(%{user | email: email}, user.email, url)
- end)
-
- %{user: user, token: token, email: email}
- end
-
- test "updates the email with a valid token", %{user: user, token: token, email: email} do
- assert Accounts.update_user_email(user, token) == :ok
- changed_user = Repo.get!(User, user.id)
- 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
-
- test "does not update email with invalid token", %{user: user} do
- assert Accounts.update_user_email(user, "oops") == :error
- assert Repo.get!(User, user.id).email == user.email
- assert Repo.get_by(UserToken, user_id: user.id)
- end
-
- test "does not update email if user email changed", %{user: user, token: token} do
- assert Accounts.update_user_email(%{user | email: "current@example.com"}, token) == :error
- assert Repo.get!(User, user.id).email == user.email
- assert Repo.get_by(UserToken, user_id: user.id)
- end
-
- test "does not update email if token expired", %{user: user, token: token} do
- {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]])
- assert Accounts.update_user_email(user, token) == :error
- assert Repo.get!(User, user.id).email == user.email
- assert Repo.get_by(UserToken, user_id: user.id)
- end
- end
-
- describe "change_user_password/2" do
- test "returns a user changeset" do
- assert %Ecto.Changeset{} = changeset = Accounts.change_user_password(%User{})
- assert changeset.required == [:password]
- end
-
- test "allows fields to be set" do
- changeset =
- Accounts.change_user_password(%User{}, %{
- "password" => "new valid password"
- })
-
- assert changeset.valid?
- assert get_change(changeset, :password) == "new valid password"
- assert is_nil(get_change(changeset, :hashed_password))
- end
- end
-
- describe "update_user_password/3" do
- setup do
- %{user: user_fixture()}
- end
-
- test "validates password", %{user: user} do
- {:error, changeset} =
- Accounts.update_user_password(user, valid_user_password(), %{
- password: "not valid",
- password_confirmation: "another"
- })
-
- assert %{
- password: ["should be at least 12 character(s)"],
- password_confirmation: ["does not match password"]
- } = errors_on(changeset)
- end
-
- test "validates maximum values for password for security", %{user: user} do
- too_long = String.duplicate("db", 100)
-
- {:error, changeset} =
- Accounts.update_user_password(user, valid_user_password(), %{password: too_long})
-
- assert "should be at most 72 character(s)" in errors_on(changeset).password
- end
-
- test "validates current password", %{user: user} do
- {:error, changeset} =
- Accounts.update_user_password(user, "invalid", %{password: valid_user_password()})
-
- assert %{current_password: ["is not valid"]} = errors_on(changeset)
- end
-
- test "updates the password", %{user: user} do
- {:ok, user} =
- Accounts.update_user_password(user, valid_user_password(), %{
- password: "new valid password"
- })
-
- assert is_nil(user.password)
- assert Accounts.get_user_by_email_and_password(user.email, "new valid password")
- end
-
- test "deletes all tokens for the given user", %{user: user} do
- _ = Accounts.generate_user_session_token(user)
-
- {:ok, _} =
- Accounts.update_user_password(user, valid_user_password(), %{
- password: "new valid password"
- })
-
- refute Repo.get_by(UserToken, user_id: user.id)
- end
- end
-
- describe "generate_user_session_token/1" do
- setup do
- %{user: user_fixture()}
- end
-
- test "generates a token", %{user: user} do
- token = Accounts.generate_user_session_token(user)
- assert user_token = Repo.get_by(UserToken, token: token)
- assert user_token.context == "session"
-
- # Creating the same token for another user should fail
- assert_raise Ecto.ConstraintError, fn ->
- Repo.insert!(%UserToken{
- token: user_token.token,
- user_id: user_fixture().id,
- context: "session"
- })
- end
- end
- end
-
- describe "get_user_by_session_token/1" do
- setup do
- user = user_fixture()
- token = Accounts.generate_user_session_token(user)
- %{user: user, token: token}
- end
-
- test "returns user by token", %{user: user, token: token} do
- assert session_user = Accounts.get_user_by_session_token(token)
- assert session_user.id == user.id
- end
-
- test "does not return user for invalid token" do
- refute Accounts.get_user_by_session_token("oops")
- end
-
- test "does not return user for expired token", %{token: token} do
- {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]])
- refute Accounts.get_user_by_session_token(token)
- end
- end
-
- describe "delete_user_session_token/1" do
- test "deletes the token" do
- user = user_fixture()
- token = Accounts.generate_user_session_token(user)
- assert Accounts.delete_user_session_token(token) == :ok
- refute Accounts.get_user_by_session_token(token)
- end
- end
-
- describe "deliver_user_confirmation_instructions/2" do
- setup do
- %{user: user_fixture()}
- end
-
- test "sends token through notification", %{user: user} do
- token =
- extract_user_token(fn url ->
- Accounts.deliver_user_confirmation_instructions(user, url)
- end)
-
- {:ok, token} = Base.url_decode64(token, padding: false)
- assert user_token = Repo.get_by(UserToken, token: :crypto.hash(:sha256, token))
- assert user_token.user_id == user.id
- assert user_token.sent_to == user.email
- assert user_token.context == "confirm"
- end
- end
-
- describe "confirm_user/1" do
- setup do
- user = user_fixture()
-
- token =
- extract_user_token(fn url ->
- Accounts.deliver_user_confirmation_instructions(user, url)
- end)
-
- %{user: user, token: token}
- end
-
- test "confirms the email with a valid token", %{user: user, token: token} do
- assert {:ok, confirmed_user} = Accounts.confirm_user(token)
- assert confirmed_user.confirmed_at
- assert confirmed_user.confirmed_at != user.confirmed_at
- assert Repo.get!(User, user.id).confirmed_at
- refute Repo.get_by(UserToken, user_id: user.id)
- end
-
- test "does not confirm with invalid token", %{user: user} do
- assert Accounts.confirm_user("oops") == :error
- refute Repo.get!(User, user.id).confirmed_at
- assert Repo.get_by(UserToken, user_id: user.id)
- end
-
- test "does not confirm email if token expired", %{user: user, token: token} do
- {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]])
- assert Accounts.confirm_user(token) == :error
- refute Repo.get!(User, user.id).confirmed_at
- assert Repo.get_by(UserToken, user_id: user.id)
- end
- end
-
- describe "deliver_user_reset_password_instructions/2" do
- setup do
- %{user: user_fixture()}
- end
-
- test "sends token through notification", %{user: user} do
- token =
- extract_user_token(fn url ->
- Accounts.deliver_user_reset_password_instructions(user, url)
- end)
-
- {:ok, token} = Base.url_decode64(token, padding: false)
- assert user_token = Repo.get_by(UserToken, token: :crypto.hash(:sha256, token))
- assert user_token.user_id == user.id
- assert user_token.sent_to == user.email
- assert user_token.context == "reset_password"
- end
- end
-
- describe "get_user_by_reset_password_token/1" do
- setup do
- user = user_fixture()
-
- token =
- extract_user_token(fn url ->
- Accounts.deliver_user_reset_password_instructions(user, url)
- end)
-
- %{user: user, token: token}
- end
-
- test "returns the user with valid token", %{user: %{id: id}, token: token} do
- assert %User{id: ^id} = Accounts.get_user_by_reset_password_token(token)
- assert Repo.get_by(UserToken, user_id: id)
- end
-
- test "does not return the user with invalid token", %{user: user} do
- refute Accounts.get_user_by_reset_password_token("oops")
- assert Repo.get_by(UserToken, user_id: user.id)
- end
-
- test "does not return the user if token expired", %{user: user, token: token} do
- {1, nil} = Repo.update_all(UserToken, set: [inserted_at: ~N[2020-01-01 00:00:00]])
- refute Accounts.get_user_by_reset_password_token(token)
- assert Repo.get_by(UserToken, user_id: user.id)
- end
- end
-
- describe "reset_user_password/2" do
- setup do
- %{user: user_fixture()}
- end
-
- test "validates password", %{user: user} do
- {:error, changeset} =
- Accounts.reset_user_password(user, %{
- password: "not valid",
- password_confirmation: "another"
- })
-
- assert %{
- password: ["should be at least 12 character(s)"],
- password_confirmation: ["does not match password"]
- } = errors_on(changeset)
- end
-
- test "validates maximum values for password for security", %{user: user} do
- too_long = String.duplicate("db", 100)
- {:error, changeset} = Accounts.reset_user_password(user, %{password: too_long})
- assert "should be at most 72 character(s)" in errors_on(changeset).password
- end
-
- test "updates the password", %{user: user} do
- {:ok, updated_user} = Accounts.reset_user_password(user, %{password: "new valid password"})
- assert is_nil(updated_user.password)
- assert Accounts.get_user_by_email_and_password(user.email, "new valid password")
- end
-
- test "deletes all tokens for the given user", %{user: user} do
- _ = Accounts.generate_user_session_token(user)
- {:ok, _} = Accounts.reset_user_password(user, %{password: "new valid password"})
- refute Repo.get_by(UserToken, user_id: user.id)
- end
- end
-
- describe "inspect/2 for the User module" do
- test "does not include password" do
- refute inspect(%User{password: "123456"}) =~ "password: \"123456\""
- end
- end
-end
diff --git a/test/something_erlang_web/controllers/user_session_controller_test.exs b/test/something_erlang_web/controllers/user_session_controller_test.exs
deleted file mode 100644
index bafb576..0000000
--- a/test/something_erlang_web/controllers/user_session_controller_test.exs
+++ /dev/null
@@ -1,113 +0,0 @@
-defmodule SomethingErlangWeb.UserSessionControllerTest do
- use SomethingErlangWeb.ConnCase, async: true
-
- import SomethingErlang.AccountsFixtures
-
- setup do
- %{user: user_fixture()}
- end
-
- describe "POST /users/log_in" do
- test "logs the user in", %{conn: conn, user: user} do
- conn =
- post(conn, ~p"/users/log_in", %{
- "user" => %{"email" => user.email, "password" => valid_user_password()}
- })
-
- assert get_session(conn, :user_token)
- assert redirected_to(conn) == ~p"/"
-
- # Now do a logged in request and assert on the menu
- conn = get(conn, ~p"/")
- response = html_response(conn, 200)
- assert response =~ user.email
- assert response =~ "Settings"
- assert response =~ "Log out"
- end
-
- test "logs the user in with remember me", %{conn: conn, user: user} do
- conn =
- post(conn, ~p"/users/log_in", %{
- "user" => %{
- "email" => user.email,
- "password" => valid_user_password(),
- "remember_me" => "true"
- }
- })
-
- assert conn.resp_cookies["_something_erlang_web_user_remember_me"]
- assert redirected_to(conn) == ~p"/"
- end
-
- test "logs the user in with return to", %{conn: conn, user: user} do
- conn =
- conn
- |> init_test_session(user_return_to: "/foo/bar")
- |> post(~p"/users/log_in", %{
- "user" => %{
- "email" => user.email,
- "password" => valid_user_password()
- }
- })
-
- assert redirected_to(conn) == "/foo/bar"
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Welcome back!"
- end
-
- test "login following registration", %{conn: conn, user: user} do
- conn =
- conn
- |> post(~p"/users/log_in", %{
- "_action" => "registered",
- "user" => %{
- "email" => user.email,
- "password" => valid_user_password()
- }
- })
-
- assert redirected_to(conn) == ~p"/"
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Account created successfully"
- end
-
- test "login following password update", %{conn: conn, user: user} do
- conn =
- conn
- |> post(~p"/users/log_in", %{
- "_action" => "password_updated",
- "user" => %{
- "email" => user.email,
- "password" => valid_user_password()
- }
- })
-
- assert redirected_to(conn) == ~p"/users/settings"
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Password updated successfully"
- end
-
- test "redirects to login page with invalid credentials", %{conn: conn} do
- conn =
- post(conn, ~p"/users/log_in", %{
- "user" => %{"email" => "invalid@email.com", "password" => "invalid_password"}
- })
-
- assert Phoenix.Flash.get(conn.assigns.flash, :error) == "Invalid email or password"
- assert redirected_to(conn) == ~p"/users/log_in"
- end
- end
-
- describe "DELETE /users/log_out" do
- test "logs the user out", %{conn: conn, user: user} do
- conn = conn |> log_in_user(user) |> delete(~p"/users/log_out")
- assert redirected_to(conn) == ~p"/"
- refute get_session(conn, :user_token)
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Logged out successfully"
- end
-
- test "succeeds even if the user is not logged in", %{conn: conn} do
- conn = delete(conn, ~p"/users/log_out")
- assert redirected_to(conn) == ~p"/"
- refute get_session(conn, :user_token)
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Logged out successfully"
- end
- end
-end
diff --git a/test/something_erlang_web/live/user_confirmation_instructions_live_test.exs b/test/something_erlang_web/live/user_confirmation_instructions_live_test.exs
deleted file mode 100644
index 1b94a2d..0000000
--- a/test/something_erlang_web/live/user_confirmation_instructions_live_test.exs
+++ /dev/null
@@ -1,67 +0,0 @@
-defmodule SomethingErlangWeb.UserConfirmationInstructionsLiveTest do
- use SomethingErlangWeb.ConnCase
-
- import Phoenix.LiveViewTest
- import SomethingErlang.AccountsFixtures
-
- alias SomethingErlang.Accounts
- alias SomethingErlang.Repo
-
- setup do
- %{user: user_fixture()}
- end
-
- describe "Resend confirmation" do
- test "renders the resend confirmation page", %{conn: conn} do
- {:ok, _lv, html} = live(conn, ~p"/users/confirm")
- assert html =~ "Resend confirmation instructions"
- end
-
- test "sends a new confirmation token", %{conn: conn, user: user} do
- {:ok, lv, _html} = live(conn, ~p"/users/confirm")
-
- {:ok, conn} =
- lv
- |> form("#resend_confirmation_form", user: %{email: user.email})
- |> render_submit()
- |> follow_redirect(conn, ~p"/")
-
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~
- "If your email is in our system"
-
- assert Repo.get_by!(Accounts.UserToken, user_id: user.id).context == "confirm"
- end
-
- test "does not send confirmation token if user is confirmed", %{conn: conn, user: user} do
- Repo.update!(Accounts.User.confirm_changeset(user))
-
- {:ok, lv, _html} = live(conn, ~p"/users/confirm")
-
- {:ok, conn} =
- lv
- |> form("#resend_confirmation_form", user: %{email: user.email})
- |> render_submit()
- |> follow_redirect(conn, ~p"/")
-
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~
- "If your email is in our system"
-
- refute Repo.get_by(Accounts.UserToken, user_id: user.id)
- end
-
- test "does not send confirmation token if email is invalid", %{conn: conn} do
- {:ok, lv, _html} = live(conn, ~p"/users/confirm")
-
- {:ok, conn} =
- lv
- |> form("#resend_confirmation_form", user: %{email: "unknown@example.com"})
- |> render_submit()
- |> follow_redirect(conn, ~p"/")
-
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~
- "If your email is in our system"
-
- assert Repo.all(Accounts.UserToken) == []
- end
- end
-end
diff --git a/test/something_erlang_web/live/user_confirmation_live_test.exs b/test/something_erlang_web/live/user_confirmation_live_test.exs
deleted file mode 100644
index 59905a9..0000000
--- a/test/something_erlang_web/live/user_confirmation_live_test.exs
+++ /dev/null
@@ -1,88 +0,0 @@
-defmodule SomethingErlangWeb.UserConfirmationLiveTest do
- use SomethingErlangWeb.ConnCase
-
- import Phoenix.LiveViewTest
- import SomethingErlang.AccountsFixtures
-
- alias SomethingErlang.Accounts
- alias SomethingErlang.Repo
-
- setup do
- %{user: user_fixture()}
- end
-
- describe "Confirm user" do
- test "renders confirmation page", %{conn: conn} do
- {:ok, _lv, html} = live(conn, ~p"/users/confirm/some-token")
- assert html =~ "Confirm Account"
- end
-
- test "confirms the given token once", %{conn: conn, user: user} do
- token =
- extract_user_token(fn url ->
- Accounts.deliver_user_confirmation_instructions(user, url)
- end)
-
- {:ok, lv, _html} = live(conn, ~p"/users/confirm/#{token}")
-
- result =
- lv
- |> form("#confirmation_form")
- |> render_submit()
- |> follow_redirect(conn, "/")
-
- assert {:ok, conn} = result
-
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~
- "User confirmed successfully"
-
- assert Accounts.get_user!(user.id).confirmed_at
- refute get_session(conn, :user_token)
- assert Repo.all(Accounts.UserToken) == []
-
- # when not logged in
- {:ok, lv, _html} = live(conn, ~p"/users/confirm/#{token}")
-
- result =
- lv
- |> form("#confirmation_form")
- |> render_submit()
- |> follow_redirect(conn, "/")
-
- assert {:ok, conn} = result
-
- assert Phoenix.Flash.get(conn.assigns.flash, :error) =~
- "User confirmation link is invalid or it has expired"
-
- # when logged in
- {:ok, lv, _html} =
- build_conn()
- |> log_in_user(user)
- |> live(~p"/users/confirm/#{token}")
-
- result =
- lv
- |> form("#confirmation_form")
- |> render_submit()
- |> follow_redirect(conn, "/")
-
- assert {:ok, conn} = result
- refute Phoenix.Flash.get(conn.assigns.flash, :error)
- end
-
- test "does not confirm email with invalid token", %{conn: conn, user: user} do
- {:ok, lv, _html} = live(conn, ~p"/users/confirm/invalid-token")
-
- {:ok, conn} =
- lv
- |> form("#confirmation_form")
- |> render_submit()
- |> follow_redirect(conn, ~p"/")
-
- assert Phoenix.Flash.get(conn.assigns.flash, :error) =~
- "User confirmation link is invalid or it has expired"
-
- refute Accounts.get_user!(user.id).confirmed_at
- end
- end
-end
diff --git a/test/something_erlang_web/live/user_forgot_password_live_test.exs b/test/something_erlang_web/live/user_forgot_password_live_test.exs
deleted file mode 100644
index f103f20..0000000
--- a/test/something_erlang_web/live/user_forgot_password_live_test.exs
+++ /dev/null
@@ -1,63 +0,0 @@
-defmodule SomethingErlangWeb.UserForgotPasswordLiveTest do
- use SomethingErlangWeb.ConnCase
-
- import Phoenix.LiveViewTest
- import SomethingErlang.AccountsFixtures
-
- alias SomethingErlang.Accounts
- alias SomethingErlang.Repo
-
- describe "Forgot password page" do
- test "renders email page", %{conn: conn} do
- {:ok, _lv, html} = live(conn, ~p"/users/reset_password")
-
- assert html =~ "Forgot your password?"
- assert html =~ "Register"
- assert html =~ "Log in"
- end
-
- test "redirects if already logged in", %{conn: conn} do
- result =
- conn
- |> log_in_user(user_fixture())
- |> live(~p"/users/reset_password")
- |> follow_redirect(conn, ~p"/")
-
- assert {:ok, _conn} = result
- end
- end
-
- describe "Reset link" do
- setup do
- %{user: user_fixture()}
- end
-
- test "sends a new reset password token", %{conn: conn, user: user} do
- {:ok, lv, _html} = live(conn, ~p"/users/reset_password")
-
- {:ok, conn} =
- lv
- |> form("#reset_password_form", user: %{"email" => user.email})
- |> render_submit()
- |> follow_redirect(conn, "/")
-
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "If your email is in our system"
-
- assert Repo.get_by!(Accounts.UserToken, user_id: user.id).context ==
- "reset_password"
- end
-
- test "does not send reset password token if email is invalid", %{conn: conn} do
- {:ok, lv, _html} = live(conn, ~p"/users/reset_password")
-
- {:ok, conn} =
- lv
- |> form("#reset_password_form", user: %{"email" => "unknown@example.com"})
- |> render_submit()
- |> follow_redirect(conn, "/")
-
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "If your email is in our system"
- assert Repo.all(Accounts.UserToken) == []
- end
- end
-end
diff --git a/test/something_erlang_web/live/user_login_live_test.exs b/test/something_erlang_web/live/user_login_live_test.exs
deleted file mode 100644
index 9f8add6..0000000
--- a/test/something_erlang_web/live/user_login_live_test.exs
+++ /dev/null
@@ -1,87 +0,0 @@
-defmodule SomethingErlangWeb.UserLoginLiveTest do
- use SomethingErlangWeb.ConnCase
-
- import Phoenix.LiveViewTest
- import SomethingErlang.AccountsFixtures
-
- describe "Log in page" do
- test "renders log in page", %{conn: conn} do
- {:ok, _lv, html} = live(conn, ~p"/users/log_in")
-
- assert html =~ "Log in"
- assert html =~ "Register"
- assert html =~ "Forgot your password?"
- end
-
- test "redirects if already logged in", %{conn: conn} do
- result =
- conn
- |> log_in_user(user_fixture())
- |> live(~p"/users/log_in")
- |> follow_redirect(conn, "/")
-
- assert {:ok, _conn} = result
- end
- end
-
- describe "user login" do
- test "redirects if user login with valid credentials", %{conn: conn} do
- password = "123456789abcd"
- user = user_fixture(%{password: password})
-
- {:ok, lv, _html} = live(conn, ~p"/users/log_in")
-
- form =
- form(lv, "#login_form", user: %{email: user.email, password: password, remember_me: true})
-
- conn = submit_form(form, conn)
-
- assert redirected_to(conn) == ~p"/"
- end
-
- test "redirects to login page with a flash error if there are no valid credentials", %{
- conn: conn
- } do
- {:ok, lv, _html} = live(conn, ~p"/users/log_in")
-
- form =
- form(lv, "#login_form",
- user: %{email: "test@email.com", password: "123456", remember_me: true}
- )
-
- conn = submit_form(form, conn)
-
- assert Phoenix.Flash.get(conn.assigns.flash, :error) == "Invalid email or password"
-
- assert redirected_to(conn) == "/users/log_in"
- end
- end
-
- describe "login navigation" do
- test "redirects to registration page when the Register button is clicked", %{conn: conn} do
- {:ok, lv, _html} = live(conn, ~p"/users/log_in")
-
- {:ok, _login_live, login_html} =
- lv
- |> element(~s|a:fl-contains("Sign up")|)
- |> render_click()
- |> follow_redirect(conn, ~p"/users/register")
-
- assert login_html =~ "Register"
- end
-
- test "redirects to forgot password page when the Forgot Password button is clicked", %{
- conn: conn
- } do
- {:ok, lv, _html} = live(conn, ~p"/users/log_in")
-
- {:ok, conn} =
- lv
- |> element(~s{a:fl-contains('Forgot your password?')})
- |> render_click()
- |> follow_redirect(conn, ~p"/users/reset_password")
-
- assert conn.resp_body =~ "Forgot your password?"
- end
- end
-end
diff --git a/test/something_erlang_web/live/user_registration_live_test.exs b/test/something_erlang_web/live/user_registration_live_test.exs
deleted file mode 100644
index 2cdb902..0000000
--- a/test/something_erlang_web/live/user_registration_live_test.exs
+++ /dev/null
@@ -1,87 +0,0 @@
-defmodule SomethingErlangWeb.UserRegistrationLiveTest do
- use SomethingErlangWeb.ConnCase
-
- import Phoenix.LiveViewTest
- import SomethingErlang.AccountsFixtures
-
- describe "Registration page" do
- test "renders registration page", %{conn: conn} do
- {:ok, _lv, html} = live(conn, ~p"/users/register")
-
- assert html =~ "Register"
- assert html =~ "Log in"
- end
-
- test "redirects if already logged in", %{conn: conn} do
- result =
- conn
- |> log_in_user(user_fixture())
- |> live(~p"/users/register")
- |> follow_redirect(conn, "/")
-
- assert {:ok, _conn} = result
- end
-
- test "renders errors for invalid data", %{conn: conn} do
- {:ok, lv, _html} = live(conn, ~p"/users/register")
-
- result =
- lv
- |> element("#registration_form")
- |> render_change(user: %{"email" => "with spaces", "password" => "too short"})
-
- assert result =~ "Register"
- assert result =~ "must have the @ sign and no spaces"
- assert result =~ "should be at least 12 character"
- end
- end
-
- describe "register user" do
- test "creates account and logs the user in", %{conn: conn} do
- {:ok, lv, _html} = live(conn, ~p"/users/register")
-
- email = unique_user_email()
- form = form(lv, "#registration_form", user: valid_user_attributes(email: email))
- render_submit(form)
- conn = follow_trigger_action(form, conn)
-
- assert redirected_to(conn) == ~p"/"
-
- # Now do a logged in request and assert on the menu
- conn = get(conn, "/")
- response = html_response(conn, 200)
- assert response =~ email
- assert response =~ "Settings"
- assert response =~ "Log out"
- end
-
- test "renders errors for duplicated email", %{conn: conn} do
- {:ok, lv, _html} = live(conn, ~p"/users/register")
-
- user = user_fixture(%{email: "test@email.com"})
-
- result =
- lv
- |> form("#registration_form",
- user: %{"email" => user.email, "password" => "valid_password"}
- )
- |> render_submit()
-
- assert result =~ "has already been taken"
- end
- end
-
- describe "registration navigation" do
- test "redirects to login page when the Log in button is clicked", %{conn: conn} do
- {:ok, lv, _html} = live(conn, ~p"/users/register")
-
- {:ok, _login_live, login_html} =
- lv
- |> element(~s|main a:fl-contains("Sign in")|)
- |> render_click()
- |> follow_redirect(conn, ~p"/users/log_in")
-
- assert login_html =~ "Log in"
- end
- end
-end
diff --git a/test/something_erlang_web/live/user_reset_password_live_test.exs b/test/something_erlang_web/live/user_reset_password_live_test.exs
deleted file mode 100644
index 17fc8bd..0000000
--- a/test/something_erlang_web/live/user_reset_password_live_test.exs
+++ /dev/null
@@ -1,118 +0,0 @@
-defmodule SomethingErlangWeb.UserResetPasswordLiveTest do
- use SomethingErlangWeb.ConnCase
-
- import Phoenix.LiveViewTest
- import SomethingErlang.AccountsFixtures
-
- alias SomethingErlang.Accounts
-
- setup do
- user = user_fixture()
-
- token =
- extract_user_token(fn url ->
- Accounts.deliver_user_reset_password_instructions(user, url)
- end)
-
- %{token: token, user: user}
- end
-
- describe "Reset password page" do
- test "renders reset password with valid token", %{conn: conn, token: token} do
- {:ok, _lv, html} = live(conn, ~p"/users/reset_password/#{token}")
-
- assert html =~ "Reset Password"
- end
-
- test "does not render reset password with invalid token", %{conn: conn} do
- {:error, {:redirect, to}} = live(conn, ~p"/users/reset_password/invalid")
-
- assert to == %{
- flash: %{"error" => "Reset password link is invalid or it has expired."},
- to: ~p"/"
- }
- end
-
- test "renders errors for invalid data", %{conn: conn, token: token} do
- {:ok, lv, _html} = live(conn, ~p"/users/reset_password/#{token}")
-
- result =
- lv
- |> element("#reset_password_form")
- |> render_change(
- user: %{"password" => "secret12", "confirmation_password" => "secret123456"}
- )
-
- assert result =~ "should be at least 12 character"
- assert result =~ "does not match password"
- end
- end
-
- describe "Reset Password" do
- test "resets password once", %{conn: conn, token: token, user: user} do
- {:ok, lv, _html} = live(conn, ~p"/users/reset_password/#{token}")
-
- {:ok, conn} =
- lv
- |> form("#reset_password_form",
- user: %{
- "password" => "new valid password",
- "password_confirmation" => "new valid password"
- }
- )
- |> render_submit()
- |> follow_redirect(conn, ~p"/users/log_in")
-
- refute get_session(conn, :user_token)
- assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Password reset successfully"
- assert Accounts.get_user_by_email_and_password(user.email, "new valid password")
- end
-
- test "does not reset password on invalid data", %{conn: conn, token: token} do
- {:ok, lv, _html} = live(conn, ~p"/users/reset_password/#{token}")
-
- result =
- lv
- |> form("#reset_password_form",
- user: %{
- "password" => "too short",
- "password_confirmation" => "does not match"
- }
- )
- |> render_submit()
-
- assert result =~ "Reset Password"
- assert result =~ "should be at least 12 character(s)"
- assert result =~ "does not match password"
- end
- end
-
- describe "Reset password navigation" do
- test "redirects to login page when the Log in button is clicked", %{conn: conn, token: token} do
- {:ok, lv, _html} = live(conn, ~p"/users/reset_password/#{token}")
-
- {:ok, conn} =
- lv
- |> element(~s|main a:fl-contains("Log in")|)
- |> render_click()
- |> follow_redirect(conn, ~p"/users/log_in")
-
- assert conn.resp_body =~ "Log in"
- end
-
- test "redirects to password reset page when the Register button is clicked", %{
- conn: conn,
- token: token
- } do
- {:ok, lv, _html} = live(conn, ~p"/users/reset_password/#{token}")
-
- {:ok, conn} =
- lv
- |> element(~s|main a:fl-contains("Register")|)
- |> render_click()
- |> follow_redirect(conn, ~p"/users/register")
-
- assert conn.resp_body =~ "Register"
- end
- end
-end
diff --git a/test/something_erlang_web/live/user_settings_live_test.exs b/test/something_erlang_web/live/user_settings_live_test.exs
deleted file mode 100644
index e095de8..0000000
--- a/test/something_erlang_web/live/user_settings_live_test.exs
+++ /dev/null
@@ -1,210 +0,0 @@
-defmodule SomethingErlangWeb.UserSettingsLiveTest do
- use SomethingErlangWeb.ConnCase
-
- alias SomethingErlang.Accounts
- import Phoenix.LiveViewTest
- import SomethingErlang.AccountsFixtures
-
- describe "Settings page" do
- test "renders settings page", %{conn: conn} do
- {:ok, _lv, html} =
- conn
- |> log_in_user(user_fixture())
- |> live(~p"/users/settings")
-
- assert html =~ "Change Email"
- assert html =~ "Change Password"
- end
-
- test "redirects if user is not logged in", %{conn: conn} do
- assert {:error, redirect} = live(conn, ~p"/users/settings")
-
- assert {:redirect, %{to: path, flash: flash}} = redirect
- assert path == ~p"/users/log_in"
- assert %{"error" => "You must log in to access this page."} = flash
- end
- end
-
- describe "update email form" do
- setup %{conn: conn} do
- password = valid_user_password()
- user = user_fixture(%{password: password})
- %{conn: log_in_user(conn, user), user: user, password: password}
- end
-
- test "updates the user email", %{conn: conn, password: password, user: user} do
- new_email = unique_user_email()
-
- {:ok, lv, _html} = live(conn, ~p"/users/settings")
-
- result =
- lv
- |> form("#email_form", %{
- "current_password" => password,
- "user" => %{"email" => new_email}
- })
- |> render_submit()
-
- assert result =~ "A link to confirm your email"
- assert Accounts.get_user_by_email(user.email)
- end
-
- test "renders errors with invalid data (phx-change)", %{conn: conn} do
- {:ok, lv, _html} = live(conn, ~p"/users/settings")
-
- result =
- lv
- |> element("#email_form")
- |> render_change(%{
- "action" => "update_email",
- "current_password" => "invalid",
- "user" => %{"email" => "with spaces"}
- })
-
- assert result =~ "Change Email"
- assert result =~ "must have the @ sign and no spaces"
- end
-
- test "renders errors with invalid data (phx-submit)", %{conn: conn, user: user} do
- {:ok, lv, _html} = live(conn, ~p"/users/settings")
-
- result =
- lv
- |> form("#email_form", %{
- "current_password" => "invalid",
- "user" => %{"email" => user.email}
- })
- |> render_submit()
-
- assert result =~ "Change Email"
- assert result =~ "did not change"
- assert result =~ "is not valid"
- end
- end
-
- describe "update password form" do
- setup %{conn: conn} do
- password = valid_user_password()
- user = user_fixture(%{password: password})
- %{conn: log_in_user(conn, user), user: user, password: password}
- end
-
- test "updates the user password", %{conn: conn, user: user, password: password} do
- new_password = valid_user_password()
-
- {:ok, lv, _html} = live(conn, ~p"/users/settings")
-
- form =
- form(lv, "#password_form", %{
- "current_password" => password,
- "user" => %{
- "email" => user.email,
- "password" => new_password,
- "password_confirmation" => new_password
- }
- })
-
- render_submit(form)
-
- new_password_conn = follow_trigger_action(form, conn)
-
- assert redirected_to(new_password_conn) == ~p"/users/settings"
-
- assert get_session(new_password_conn, :user_token) != get_session(conn, :user_token)
-
- assert Phoenix.Flash.get(new_password_conn.assigns.flash, :info) =~
- "Password updated successfully"
-
- assert Accounts.get_user_by_email_and_password(user.email, new_password)
- end
-
- test "renders errors with invalid data (phx-change)", %{conn: conn} do
- {:ok, lv, _html} = live(conn, ~p"/users/settings")
-
- result =
- lv
- |> element("#password_form")
- |> render_change(%{
- "current_password" => "invalid",
- "user" => %{
- "password" => "too short",
- "password_confirmation" => "does not match"
- }
- })
-
- assert result =~ "Change Password"
- assert result =~ "should be at least 12 character(s)"
- assert result =~ "does not match password"
- end
-
- test "renders errors with invalid data (phx-submit)", %{conn: conn} do
- {:ok, lv, _html} = live(conn, ~p"/users/settings")
-
- result =
- lv
- |> form("#password_form", %{
- "current_password" => "invalid",
- "user" => %{
- "password" => "too short",
- "password_confirmation" => "does not match"
- }
- })
- |> render_submit()
-
- assert result =~ "Change Password"
- assert result =~ "should be at least 12 character(s)"
- assert result =~ "does not match password"
- assert result =~ "is not valid"
- end
- end
-
- describe "confirm email" do
- setup %{conn: conn} do
- user = user_fixture()
- email = unique_user_email()
-
- token =
- extract_user_token(fn url ->
- Accounts.deliver_user_update_email_instructions(%{user | email: email}, user.email, url)
- end)
-
- %{conn: log_in_user(conn, user), token: token, email: email, user: user}
- end
-
- test "updates the user email once", %{conn: conn, user: user, token: token, email: email} do
- {:error, redirect} = live(conn, ~p"/users/settings/confirm_email/#{token}")
-
- assert {:live_redirect, %{to: path, flash: flash}} = redirect
- assert path == ~p"/users/settings"
- assert %{"info" => message} = flash
- assert message == "Email changed successfully."
- refute Accounts.get_user_by_email(user.email)
- assert Accounts.get_user_by_email(email)
-
- # use confirm token again
- {:error, redirect} = live(conn, ~p"/users/settings/confirm_email/#{token}")
- assert {:live_redirect, %{to: path, flash: flash}} = redirect
- assert path == ~p"/users/settings"
- assert %{"error" => message} = flash
- assert message == "Email change link is invalid or it has expired."
- end
-
- test "does not update email with invalid token", %{conn: conn, user: user} do
- {:error, redirect} = live(conn, ~p"/users/settings/confirm_email/oops")
- assert {:live_redirect, %{to: path, flash: flash}} = redirect
- assert path == ~p"/users/settings"
- assert %{"error" => message} = flash
- assert message == "Email change link is invalid or it has expired."
- assert Accounts.get_user_by_email(user.email)
- end
-
- test "redirects if user is not logged in", %{token: token} do
- conn = build_conn()
- {:error, redirect} = live(conn, ~p"/users/settings/confirm_email/#{token}")
- assert {:redirect, %{to: path, flash: flash}} = redirect
- assert path == ~p"/users/log_in"
- assert %{"error" => message} = flash
- assert message == "You must log in to access this page."
- end
- end
-end
diff --git a/test/something_erlang_web/user_auth_test.exs b/test/something_erlang_web/user_auth_test.exs
deleted file mode 100644
index 817e0cb..0000000
--- a/test/something_erlang_web/user_auth_test.exs
+++ /dev/null
@@ -1,272 +0,0 @@
-defmodule SomethingErlangWeb.UserAuthTest do
- use SomethingErlangWeb.ConnCase, async: true
-
- alias Phoenix.LiveView
- alias SomethingErlang.Accounts
- alias SomethingErlangWeb.UserAuth
- import SomethingErlang.AccountsFixtures
-
- @remember_me_cookie "_something_erlang_web_user_remember_me"
-
- setup %{conn: conn} do
- conn =
- conn
- |> Map.replace!(:secret_key_base, SomethingErlangWeb.Endpoint.config(:secret_key_base))
- |> init_test_session(%{})
-
- %{user: user_fixture(), conn: conn}
- end
-
- describe "log_in_user/3" do
- test "stores the user token in the session", %{conn: conn, user: user} do
- conn = UserAuth.log_in_user(conn, user)
- assert token = get_session(conn, :user_token)
- assert get_session(conn, :live_socket_id) == "users_sessions:#{Base.url_encode64(token)}"
- assert redirected_to(conn) == ~p"/"
- assert Accounts.get_user_by_session_token(token)
- end
-
- test "clears everything previously stored in the session", %{conn: conn, user: user} do
- conn = conn |> put_session(:to_be_removed, "value") |> UserAuth.log_in_user(user)
- refute get_session(conn, :to_be_removed)
- end
-
- test "redirects to the configured path", %{conn: conn, user: user} do
- conn = conn |> put_session(:user_return_to, "/hello") |> UserAuth.log_in_user(user)
- assert redirected_to(conn) == "/hello"
- end
-
- test "writes a cookie if remember_me is configured", %{conn: conn, user: user} do
- conn = conn |> fetch_cookies() |> UserAuth.log_in_user(user, %{"remember_me" => "true"})
- assert get_session(conn, :user_token) == conn.cookies[@remember_me_cookie]
-
- assert %{value: signed_token, max_age: max_age} = conn.resp_cookies[@remember_me_cookie]
- assert signed_token != get_session(conn, :user_token)
- assert max_age == 5_184_000
- end
- end
-
- describe "logout_user/1" do
- test "erases session and cookies", %{conn: conn, user: user} do
- user_token = Accounts.generate_user_session_token(user)
-
- conn =
- conn
- |> put_session(:user_token, user_token)
- |> put_req_cookie(@remember_me_cookie, user_token)
- |> fetch_cookies()
- |> UserAuth.log_out_user()
-
- refute get_session(conn, :user_token)
- refute conn.cookies[@remember_me_cookie]
- assert %{max_age: 0} = conn.resp_cookies[@remember_me_cookie]
- assert redirected_to(conn) == ~p"/"
- refute Accounts.get_user_by_session_token(user_token)
- end
-
- test "broadcasts to the given live_socket_id", %{conn: conn} do
- live_socket_id = "users_sessions:abcdef-token"
- SomethingErlangWeb.Endpoint.subscribe(live_socket_id)
-
- conn
- |> put_session(:live_socket_id, live_socket_id)
- |> UserAuth.log_out_user()
-
- assert_receive %Phoenix.Socket.Broadcast{event: "disconnect", topic: ^live_socket_id}
- end
-
- test "works even if user is already logged out", %{conn: conn} do
- conn = conn |> fetch_cookies() |> UserAuth.log_out_user()
- refute get_session(conn, :user_token)
- assert %{max_age: 0} = conn.resp_cookies[@remember_me_cookie]
- assert redirected_to(conn) == ~p"/"
- end
- end
-
- describe "fetch_current_user/2" do
- test "authenticates user from session", %{conn: conn, user: user} do
- user_token = Accounts.generate_user_session_token(user)
- conn = conn |> put_session(:user_token, user_token) |> UserAuth.fetch_current_user([])
- assert conn.assigns.current_user.id == user.id
- end
-
- test "authenticates user from cookies", %{conn: conn, user: user} do
- logged_in_conn =
- conn |> fetch_cookies() |> UserAuth.log_in_user(user, %{"remember_me" => "true"})
-
- user_token = logged_in_conn.cookies[@remember_me_cookie]
- %{value: signed_token} = logged_in_conn.resp_cookies[@remember_me_cookie]
-
- conn =
- conn
- |> put_req_cookie(@remember_me_cookie, signed_token)
- |> UserAuth.fetch_current_user([])
-
- assert conn.assigns.current_user.id == user.id
- assert get_session(conn, :user_token) == user_token
-
- assert get_session(conn, :live_socket_id) ==
- "users_sessions:#{Base.url_encode64(user_token)}"
- end
-
- test "does not authenticate if data is missing", %{conn: conn, user: user} do
- _ = Accounts.generate_user_session_token(user)
- conn = UserAuth.fetch_current_user(conn, [])
- refute get_session(conn, :user_token)
- refute conn.assigns.current_user
- end
- end
-
- describe "on_mount: mount_current_user" do
- test "assigns current_user based on a valid user_token ", %{conn: conn, user: user} do
- user_token = Accounts.generate_user_session_token(user)
- session = conn |> put_session(:user_token, user_token) |> get_session()
-
- {:cont, updated_socket} =
- UserAuth.on_mount(:mount_current_user, %{}, session, %LiveView.Socket{})
-
- assert updated_socket.assigns.current_user.id == user.id
- end
-
- test "assigns nil to current_user assign if there isn't a valid user_token ", %{conn: conn} do
- user_token = "invalid_token"
- session = conn |> put_session(:user_token, user_token) |> get_session()
-
- {:cont, updated_socket} =
- UserAuth.on_mount(:mount_current_user, %{}, session, %LiveView.Socket{})
-
- assert updated_socket.assigns.current_user == nil
- end
-
- test "assigns nil to current_user assign if there isn't a user_token", %{conn: conn} do
- session = conn |> get_session()
-
- {:cont, updated_socket} =
- UserAuth.on_mount(:mount_current_user, %{}, session, %LiveView.Socket{})
-
- assert updated_socket.assigns.current_user == nil
- end
- end
-
- describe "on_mount: ensure_authenticated" do
- test "authenticates current_user based on a valid user_token ", %{conn: conn, user: user} do
- user_token = Accounts.generate_user_session_token(user)
- session = conn |> put_session(:user_token, user_token) |> get_session()
-
- {:cont, updated_socket} =
- UserAuth.on_mount(:ensure_authenticated, %{}, session, %LiveView.Socket{})
-
- assert updated_socket.assigns.current_user.id == user.id
- end
-
- test "redirects to login page if there isn't a valid user_token ", %{conn: conn} do
- user_token = "invalid_token"
- session = conn |> put_session(:user_token, user_token) |> get_session()
-
- socket = %LiveView.Socket{
- endpoint: SomethingErlangWeb.Endpoint,
- assigns: %{__changed__: %{}, flash: %{}}
- }
-
- {:halt, updated_socket} = UserAuth.on_mount(:ensure_authenticated, %{}, session, socket)
- assert updated_socket.assigns.current_user == nil
- end
-
- test "redirects to login page if there isn't a user_token ", %{conn: conn} do
- session = conn |> get_session()
-
- socket = %LiveView.Socket{
- endpoint: SomethingErlangWeb.Endpoint,
- assigns: %{__changed__: %{}, flash: %{}}
- }
-
- {:halt, updated_socket} = UserAuth.on_mount(:ensure_authenticated, %{}, session, socket)
- assert updated_socket.assigns.current_user == nil
- end
- end
-
- describe "on_mount: :redirect_if_user_is_authenticated" do
- test "redirects if there is an authenticated user ", %{conn: conn, user: user} do
- user_token = Accounts.generate_user_session_token(user)
- session = conn |> put_session(:user_token, user_token) |> get_session()
-
- assert {:halt, _updated_socket} =
- UserAuth.on_mount(
- :redirect_if_user_is_authenticated,
- %{},
- session,
- %LiveView.Socket{}
- )
- end
-
- test "Don't redirect is there is no authenticated user", %{conn: conn} do
- session = conn |> get_session()
-
- assert {:cont, _updated_socket} =
- UserAuth.on_mount(
- :redirect_if_user_is_authenticated,
- %{},
- session,
- %LiveView.Socket{}
- )
- end
- end
-
- describe "redirect_if_user_is_authenticated/2" do
- test "redirects if user is authenticated", %{conn: conn, user: user} do
- conn = conn |> assign(:current_user, user) |> UserAuth.redirect_if_user_is_authenticated([])
- assert conn.halted
- assert redirected_to(conn) == ~p"/"
- end
-
- test "does not redirect if user is not authenticated", %{conn: conn} do
- conn = UserAuth.redirect_if_user_is_authenticated(conn, [])
- refute conn.halted
- refute conn.status
- end
- end
-
- describe "require_authenticated_user/2" do
- test "redirects if user is not authenticated", %{conn: conn} do
- conn = conn |> fetch_flash() |> UserAuth.require_authenticated_user([])
- assert conn.halted
-
- assert redirected_to(conn) == ~p"/users/log_in"
-
- assert Phoenix.Flash.get(conn.assigns.flash, :error) ==
- "You must log in to access this page."
- end
-
- test "stores the path to redirect to on GET", %{conn: conn} do
- halted_conn =
- %{conn | path_info: ["foo"], query_string: ""}
- |> fetch_flash()
- |> UserAuth.require_authenticated_user([])
-
- assert halted_conn.halted
- assert get_session(halted_conn, :user_return_to) == "/foo"
-
- halted_conn =
- %{conn | path_info: ["foo"], query_string: "bar=baz"}
- |> fetch_flash()
- |> UserAuth.require_authenticated_user([])
-
- assert halted_conn.halted
- assert get_session(halted_conn, :user_return_to) == "/foo?bar=baz"
-
- halted_conn =
- %{conn | path_info: ["foo"], query_string: "bar", method: "POST"}
- |> fetch_flash()
- |> UserAuth.require_authenticated_user([])
-
- assert halted_conn.halted
- refute get_session(halted_conn, :user_return_to)
- end
-
- test "does not redirect if user is authenticated", %{conn: conn, user: user} do
- conn = conn |> assign(:current_user, user) |> UserAuth.require_authenticated_user([])
- refute conn.halted
- refute conn.status
- end
- end
-end
diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex
index 5c19c5c..579afcc 100644
--- a/test/support/conn_case.ex
+++ b/test/support/conn_case.ex
@@ -35,30 +35,4 @@ defmodule SomethingErlangWeb.ConnCase do
SomethingErlang.DataCase.setup_sandbox(tags)
{:ok, conn: Phoenix.ConnTest.build_conn()}
end
-
- @doc """
- Setup helper that registers and logs in users.
-
- setup :register_and_log_in_user
-
- It stores an updated connection and a registered user in the
- test context.
- """
- def register_and_log_in_user(%{conn: conn}) do
- user = SomethingErlang.AccountsFixtures.user_fixture()
- %{conn: log_in_user(conn, user), user: user}
- end
-
- @doc """
- Logs the given `user` into the `conn`.
-
- It returns an updated `conn`.
- """
- def log_in_user(conn, user) do
- token = SomethingErlang.Accounts.generate_user_session_token(user)
-
- conn
- |> Phoenix.ConnTest.init_test_session(%{})
- |> Plug.Conn.put_session(:user_token, token)
- end
end
diff --git a/test/support/fixtures/accounts_fixtures.ex b/test/support/fixtures/accounts_fixtures.ex
deleted file mode 100644
index 6bd9f67..0000000
--- a/test/support/fixtures/accounts_fixtures.ex
+++ /dev/null
@@ -1,31 +0,0 @@
-defmodule SomethingErlang.AccountsFixtures do
- @moduledoc """
- This module defines test helpers for creating
- entities via the `SomethingErlang.Accounts` context.
- """
-
- def unique_user_email, do: "user#{System.unique_integer()}@example.com"
- def valid_user_password, do: "hello world!"
-
- def valid_user_attributes(attrs \\ %{}) do
- Enum.into(attrs, %{
- email: unique_user_email(),
- password: valid_user_password()
- })
- end
-
- def user_fixture(attrs \\ %{}) do
- {:ok, user} =
- attrs
- |> valid_user_attributes()
- |> SomethingErlang.Accounts.register_user()
-
- user
- end
-
- def extract_user_token(fun) do
- {:ok, captured_email} = fun.(&"[TOKEN]#{&1}[TOKEN]")
- [_, token | _] = String.split(captured_email.text_body, "[TOKEN]")
- token
- end
-end