232 lines
6.5 KiB
Elixir
232 lines
6.5 KiB
Elixir
|
defmodule BrightWeb.AuthController do
|
||
|
use BrightWeb, :controller
|
||
|
use BrightWeb, :verified_routes
|
||
|
|
||
|
alias Bright.Users
|
||
|
alias Bright.Users.User
|
||
|
|
||
|
alias Bright.Repo
|
||
|
require Logger
|
||
|
plug Ueberauth
|
||
|
|
||
|
|
||
|
import Plug.Conn
|
||
|
import Phoenix.Controller
|
||
|
|
||
|
alias Phoenix.LiveView
|
||
|
|
||
|
|
||
|
def delete(conn, _params) do
|
||
|
conn
|
||
|
|> clear_session()
|
||
|
|> redirect(to: ~p"/")
|
||
|
end
|
||
|
|
||
|
|
||
|
def callback(conn = %{assigns: %{ueberauth_auth: auth}}, _params) do
|
||
|
Logger.debug "callback() with ueberauth_auth defined. Let's get a User!"
|
||
|
Logger.debug inspect auth
|
||
|
if user = Users.get_by_ueberauth(auth) do
|
||
|
Logger.debug ">>>>>> user has been here before"
|
||
|
Logger.debug "user=#{inspect(user)}"
|
||
|
Logger.debug "auth=#{inspect(auth)}"
|
||
|
|
||
|
## @todo here we need to update the user's patron_tier
|
||
|
attrs = params_from_ueberauth(auth)
|
||
|
case Users.update_user(user, attrs) do
|
||
|
{:ok, user} ->
|
||
|
conn
|
||
|
|> sign_in_and_redirect(user, ~p"/profile")
|
||
|
{:error, reason} ->
|
||
|
Logger.error("error while updating the user's patron_tier. #{inspect(reason)}")
|
||
|
conn
|
||
|
|> put_flash(:error, "Patreon tier synchronization failed. Please try again.")
|
||
|
|> redirect(to: ~p"/")
|
||
|
end
|
||
|
|
||
|
|
||
|
else
|
||
|
Logger.debug ">>>>>> it's user's first time here."
|
||
|
attrs = params_from_ueberauth(auth)
|
||
|
|
||
|
|
||
|
case Users.register_user(attrs) do
|
||
|
{:ok, user} ->
|
||
|
Logger.debug "user=#{inspect(user)}"
|
||
|
conn
|
||
|
|> put_flash(:success, "Welcome to Futureporn!")
|
||
|
|> sign_in_and_redirect(user, ~p"/profile")
|
||
|
{:error, reason} ->
|
||
|
Logger.error("failed Users.register_user for a first-time user. reason=#{reason}")
|
||
|
conn
|
||
|
|> put_flash(:error, "Something went wrong. Please try again.")
|
||
|
|> redirect(to: ~p"/")
|
||
|
end
|
||
|
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def callback(conn = %{assigns: %{ueberauth_failure: fails}}, _params) do
|
||
|
Logger.error(inspect(fails))
|
||
|
conn
|
||
|
|> put_flash(:error, "Something went wrong; please try again.")
|
||
|
|> render("new.html", user: nil)
|
||
|
end
|
||
|
|
||
|
defp params_from_ueberauth(%{provider: :github, info: info, uid: uid}) do
|
||
|
%{name: info.name, handle: info.nickname, github_handle: info.nickname, github_id: uid}
|
||
|
end
|
||
|
|
||
|
defp params_from_ueberauth(%{provider: :patreon, info: info, uid: uid, extra: %{raw_info: %{user: user}}}) do
|
||
|
Logger.debug("getting params_from_ueberauth provider: :patreon. info=#{inspect(info)}, uid=#{inspect(uid)}, user=#{inspect(user)}")
|
||
|
|
||
|
currently_entitled_tiers = Bright.PatreonEntitlements.extract_tiers(user)
|
||
|
Logger.debug("currently_entitled_tiers=#{currently_entitled_tiers}")
|
||
|
patron_tier = Bright.TierMapper.largest_tier_for_platform("patreon", currently_entitled_tiers)
|
||
|
|
||
|
%{
|
||
|
name: info.name,
|
||
|
handle: info.nickname,
|
||
|
patreon_handle: info.nickname,
|
||
|
patreon_id: uid,
|
||
|
patron_tier: patron_tier
|
||
|
}
|
||
|
end
|
||
|
|
||
|
|
||
|
defp sign_in_and_redirect(conn, user, route) do
|
||
|
Logger.debug "sign_in_and_redirect with user=#{inspect(user)} route=#{route}"
|
||
|
user |> User.sign_in_changes() |> Repo.update()
|
||
|
|
||
|
conn
|
||
|
# |> tap(fn c -> Logger.debug("Before: #{inspect(c.assigns)}") end)
|
||
|
|> assign(:current_user, user)
|
||
|
# |> tap(fn c -> Logger.debug("After: #{inspect(c.assigns)}") end)
|
||
|
|> put_flash(:success, "Authenticated! teehee.")
|
||
|
|> put_session("id", user.id)
|
||
|
|> configure_session(renew: true)
|
||
|
|> redirect(to: route)
|
||
|
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
|
||
|
|
||
|
|
||
|
|
||
|
@doc """
|
||
|
Authenticates the user by looking into the session.
|
||
|
"""
|
||
|
def fetch_current_user(conn, _opts) do
|
||
|
user_id = get_session(conn, :id)
|
||
|
user = user_id && Users.get_user!(user_id)
|
||
|
Logger.debug("fetch_current_user attempting to get user. user_id=#{user_id} user=#{inspect(user)}")
|
||
|
assign(conn, :current_user, user)
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
def on_mount(:current_user, _params, session, socket) do
|
||
|
Logger.debug("~~~~ on_mount with :current_user=#{inspect(:current_user)}")
|
||
|
case session do
|
||
|
%{"id" => id} ->
|
||
|
{:cont,
|
||
|
Phoenix.Component.assign_new(socket, :current_user, fn -> Users.get_user(id) end)}
|
||
|
|
||
|
{:cont, assign(socket, :page_title, "DemoWeb")}
|
||
|
|
||
|
%{} ->
|
||
|
{:cont, Phoenix.Component.assign(socket, :current_user, nil)}
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def on_mount(:ensure_authenticated, _params, session, socket) do
|
||
|
Logger.debug("on_mount with session=#{inspect(session)}")
|
||
|
case session do
|
||
|
%{"id" => id} ->
|
||
|
Logger.debug("~~~~ on_mount with :ensure_authenticated=#{inspect(:ensure_authenticated)}. user id=#{id}")
|
||
|
new_socket =
|
||
|
Phoenix.Component.assign_new(socket, :current_user, fn ->
|
||
|
Users.get_user!(id)
|
||
|
end)
|
||
|
|
||
|
Logger.debug("new_socket=#{inspect(new_socket)}")
|
||
|
%Users.User{} = new_socket.assigns.current_user
|
||
|
{:cont, new_socket}
|
||
|
|
||
|
%{} ->
|
||
|
Logger.debug("~~~~ on_mount with ensure_authenticated... user id was FALSY! (bad)")
|
||
|
{:halt, redirect_require_login(socket)}
|
||
|
end
|
||
|
rescue
|
||
|
Ecto.NoResultsError -> {:halt, redirect_require_login(socket)}
|
||
|
end
|
||
|
|
||
|
def on_mount(:ensure_admin, _params, session, socket) do
|
||
|
Logger.debug("~~~~ on_mount with :ensure_admin=#{inspect(:ensure_admin)}")
|
||
|
case session do
|
||
|
%{"id" => id} ->
|
||
|
user = Users.get_user!(id)
|
||
|
|
||
|
if Users.admin?(user) do
|
||
|
{:cont, socket}
|
||
|
else
|
||
|
{:halt, LiveView.redirect(socket, to: ~p"/status/404")}
|
||
|
end
|
||
|
|
||
|
%{} ->
|
||
|
{:halt, redirect_require_login(socket)}
|
||
|
end
|
||
|
rescue
|
||
|
Ecto.NoResultsError -> {:halt, redirect_require_login(socket)}
|
||
|
end
|
||
|
|
||
|
|
||
|
@doc """
|
||
|
Used for routes that require the user to be authenticated.
|
||
|
"""
|
||
|
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"/auth/patreon")
|
||
|
|> halt()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
@doc """
|
||
|
Used for routes that require the user to have admin privs.
|
||
|
"""
|
||
|
def require_admin_user(conn, _opts) do
|
||
|
case conn.assigns[:current_user] do
|
||
|
%{id: 1} -> conn
|
||
|
_ ->
|
||
|
conn
|
||
|
|> put_flash(:error, "Only admins can do that.")
|
||
|
|> maybe_store_return_to()
|
||
|
|> redirect(to: ~p"/")
|
||
|
|> halt()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
defp redirect_require_login(socket) do
|
||
|
socket
|
||
|
|> LiveView.put_flash(:error, "Please sign in")
|
||
|
|> LiveView.redirect(to: ~p"/auth/patreon")
|
||
|
end
|
||
|
|
||
|
defp signed_in_path(_conn), do: ~p"/"
|
||
|
|
||
|
|
||
|
end
|