this repo has no description

Revert "super basic user scaffolding"

This reverts commit f9adacd5b6a13b80c5b7e0937a2679bebcca47a6.

-34
lib/tasty/accounts.ex
··· 1 - defmodule Tasty.Accounts do 2 - import Ecto.Query, warn: false 3 - alias Tasty.Repo 4 - alias Tasty.Accounts.User 5 - alias Bcrypt, as: Pbkdf 6 - 7 - def register_user(attrs) do 8 - %User{} 9 - |> User.registration_changeset(attrs) 10 - |> Repo.insert() 11 - end 12 - 13 - def authenticate_user(email, password) do 14 - user = Repo.get_by(User, email: email) 15 - {:ok, user} 16 - case Bcrypt.verify_pass(password, user.password_hash) do 17 - true -> 18 - {:ok, user} 19 - false -> 20 - {:error, :invalid_credentials} 21 - end 22 - 23 - # cond do 24 - # user && Pbkdf.verify_pass(password, user.password_hash) -> 25 - 26 - # {:ok, user} 27 - 28 - # true -> 29 - # {:error, :invalid_credentials} 30 - # end 31 - end 32 - 33 - def get_user(id), do: Repo.get(User, id) 34 - end
···
-33
lib/tasty/accounts/user.ex
··· 1 - defmodule Tasty.Accounts.User do 2 - use Ecto.Schema 3 - import Ecto.Changeset 4 - alias Bcrypt, as: Pbkdf 5 - 6 - schema "users" do 7 - field :email, :string 8 - field :password_hash, :string 9 - 10 - # Virtual fields are not stored in DB but used for password changes 11 - field :password, :string, virtual: true 12 - 13 - timestamps() 14 - end 15 - 16 - def registration_changeset(user, attrs) do 17 - user 18 - |> cast(attrs, [:email, :password]) 19 - |> validate_required([:email, :password]) 20 - |> unique_constraint(:email) 21 - |> hash_password() 22 - end 23 - 24 - defp hash_password(changeset) do 25 - case changeset do 26 - %Ecto.Changeset{valid?: true, changes: %{password: plain}} -> 27 - put_change(changeset, :password_hash, Pbkdf.hash_pwd_salt(plain)) 28 - 29 - _ -> 30 - changeset 31 - end 32 - end 33 - end
···
-1
lib/tasty_web.ex
··· 87 88 # HTML escaping functionality 89 import Phoenix.HTML 90 - import Phoenix.HTML.Form 91 # Core UI components 92 import TastyWeb.CoreComponents 93
··· 87 88 # HTML escaping functionality 89 import Phoenix.HTML 90 # Core UI components 91 import TastyWeb.CoreComponents 92
+3 -1
lib/tasty_web/controllers/page_controller.ex
··· 2 use TastyWeb, :controller 3 4 def home(conn, _params) do 5 - render(conn, :home) 6 end 7 end
··· 2 use TastyWeb, :controller 3 4 def home(conn, _params) do 5 + # The home page is often custom made, 6 + # so skip the default app layout. 7 + render(conn, :home, layout: false) 8 end 9 end
+1 -13
lib/tasty_web/controllers/page_html/home.html.heex
··· 60 </p> 61 <div class="flex"> 62 <div class="w-full sm:w-auto"> 63 - <div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-4"> 64 <a 65 href="https://hexdocs.pm/phoenix/overview.html" 66 class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-zinc-900 sm:py-6" ··· 215 Deploy your application 216 </a> 217 </div> 218 - </div> 219 - <div> 220 - <h1>Welcome!</h1> 221 - <p>This is your home page.</p> 222 - <p>Current user: <%= inspect @current_user %></p> 223 - <p> 224 - <.link navigate={~p"/register"}>Register</.link> 225 - | 226 - <.link navigate={~p"/log_in"}>Log In</.link> 227 - | 228 - <.link navigate={~p"/log_out"}>Log Out</.link> 229 - </p> 230 </div> 231 </div> 232 </div>
··· 60 </p> 61 <div class="flex"> 62 <div class="w-full sm:w-auto"> 63 + <div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-3"> 64 <a 65 href="https://hexdocs.pm/phoenix/overview.html" 66 class="group relative rounded-2xl px-6 py-4 text-sm font-semibold leading-6 text-zinc-900 sm:py-6" ··· 215 Deploy your application 216 </a> 217 </div> 218 </div> 219 </div> 220 </div>
-52
lib/tasty_web/live/user_login_live.ex
··· 1 - defmodule TastyWeb.UserLoginLive do 2 - use TastyWeb, :live_view 3 - 4 - alias Tasty.Accounts 5 - 6 - def mount(_params, _session, socket) do 7 - form = to_form(%{}, as: :user) 8 - {:ok, assign(socket, error: nil, form: form)} 9 - end 10 - 11 - def handle_event("login", %{"user" => %{"email" => email, "password" => pass}}, socket) do 12 - case Accounts.authenticate_user(email, pass) do 13 - {:ok, user} -> 14 - socket = 15 - socket 16 - |> put_flash(:info, "Logged in successfully.") 17 - |> assign(error: nil) 18 - |> then(fn s -> Phoenix.LiveView.redirect(s, to: ~p"/") end) 19 - 20 - {:noreply, store_user_in_session(socket, user.id)} 21 - 22 - {:error, :invalid_credentials} -> 23 - {:noreply, assign(socket, error: "Invalid credentials")} 24 - end 25 - end 26 - 27 - defp store_user_in_session(socket, user_id) do 28 - # We need to store user_id in the session for future requests. 29 - # Since this is purely LiveView, we can manipulate the session 30 - # by using the Phoenix.LiveView.redirect/2 and passing a session param, 31 - # or we can push an event. The simplest approach is to do: 32 - Phoenix.Component.update(socket, :conn, fn conn -> 33 - Plug.Conn.put_session(conn, :user_id, user_id) 34 - end) 35 - socket 36 - end 37 - 38 - def render(assigns) do 39 - ~H""" 40 - <h2>Log In</h2> 41 - <%= if @error do %> 42 - <p style="color:red;"><%= @error %></p> 43 - <% end %> 44 - 45 - <.form for={@form} phx-submit="login" :let={f}> 46 - <.input field={f[:email]} type="email" label="Email" placeholder="Enter Email" /> 47 - <.input field={f[:password]} type="password" label="Password" placeholder="Enter Password" /> 48 - <.button phx-disable-with="Authenticating...">Log In</.button> 49 - </.form> 50 - """ 51 - end 52 - end
···
-16
lib/tasty_web/live/user_logout_live.ex
··· 1 - defmodule TastyWeb.UserLogoutLive do 2 - use TastyWeb, :live_view 3 - 4 - def mount(_params, _session, socket) do 5 - # Wipe out session 6 - socket = 7 - Phoenix.Component.update(socket, :conn, fn conn -> 8 - conn 9 - |> Plug.Conn.configure_session(renew: true) 10 - |> Plug.Conn.clear_session() 11 - end) 12 - 13 - socket = put_flash(socket, :info, "Logged out!") 14 - {:ok, Phoenix.LiveView.redirect(socket, to: ~p"/")} 15 - end 16 - end
···
-58
lib/tasty_web/live/user_registration_live.ex
··· 1 - defmodule TastyWeb.UserRegistrationLive do 2 - use TastyWeb, :live_view 3 - 4 - alias Tasty.Accounts 5 - alias Tasty.Accounts.User 6 - 7 - def mount(_params, _session, socket) do 8 - changeset = User.registration_changeset(%User{}, %{}) 9 - form = to_form(changeset) 10 - {:ok, assign(socket, changeset: changeset, form: form, success: false)} 11 - end 12 - 13 - def handle_event("save", %{"user" => params}, socket) do 14 - case Accounts.register_user(params) do 15 - {:ok, _user} -> 16 - socket = 17 - socket 18 - |> put_flash(:info, "Registered!") 19 - |> push_navigate(to: ~p"/") 20 - 21 - {:noreply, socket} 22 - 23 - {:error, new_changeset} -> 24 - # Generate a fresh form from your updated changeset 25 - {:noreply, assign(socket, 26 - changeset: new_changeset, 27 - form: to_form(new_changeset) 28 - )} 29 - end 30 - end 31 - 32 - def render(assigns) do 33 - ~H""" 34 - <h2>Register</h2> 35 - <.form for={@form} phx-submit="save" :let={f}> 36 - <%= if @changeset.action == :insert do %> 37 - <p style="color:red;">Oops, something went wrong!</p> 38 - <% end %> 39 - 40 - <.input 41 - field={f[:email]} 42 - type="email" 43 - label="Email" 44 - placeholder="Enter Email" /> 45 - 46 - <.input 47 - field={f[:password]} 48 - type="password" 49 - label="Password" 50 - placeholder="Enter Password" /> 51 - 52 - <.button phx-disable-with="Saving..."> 53 - Register 54 - </.button> 55 - </.form> 56 - """ 57 - end 58 - end
···
-11
lib/tasty_web/router.ex
··· 8 plug :put_root_layout, html: {TastyWeb.Layouts, :root} 9 plug :protect_from_forgery 10 plug :put_secure_browser_headers 11 - plug :fetch_current_user 12 end 13 14 pipeline :api do ··· 17 18 scope "/", TastyWeb do 19 pipe_through :browser 20 - 21 - live "/register", UserRegistrationLive, :new 22 - live "/log_in", UserLoginLive, :new 23 - live "/log_out", UserLogoutLive, :index 24 25 get "/", PageController, :home 26 end ··· 45 live_dashboard "/dashboard", metrics: TastyWeb.Telemetry 46 forward "/mailbox", Plug.Swoosh.MailboxPreview 47 end 48 - end 49 - 50 - # A minimal plug to load current_user from the session 51 - defp fetch_current_user(conn, _opts) do 52 - conn 53 - |> assign(:current_user, get_session(conn, :user_id) && Tasty.Accounts.get_user(get_session(conn, :user_id))) 54 end 55 end
··· 8 plug :put_root_layout, html: {TastyWeb.Layouts, :root} 9 plug :protect_from_forgery 10 plug :put_secure_browser_headers 11 end 12 13 pipeline :api do ··· 16 17 scope "/", TastyWeb do 18 pipe_through :browser 19 20 get "/", PageController, :home 21 end ··· 40 live_dashboard "/dashboard", metrics: TastyWeb.Telemetry 41 forward "/mailbox", Plug.Swoosh.MailboxPreview 42 end 43 end 44 end
+1 -2
mix.exs
··· 57 {:gettext, "~> 0.26"}, 58 {:jason, "~> 1.2"}, 59 {:dns_cluster, "~> 0.1.1"}, 60 - {:bandit, "~> 1.5"}, 61 - {:bcrypt_elixir, "~> 3.0"} 62 ] 63 end 64
··· 57 {:gettext, "~> 0.26"}, 58 {:jason, "~> 1.2"}, 59 {:dns_cluster, "~> 0.1.1"}, 60 + {:bandit, "~> 1.5"} 61 ] 62 end 63
-3
mix.lock
··· 1 %{ 2 "bandit": {:hex, :bandit, "1.6.7", "42f30e37a1c89a2a12943c5dca76f731a2313e8a2e21c1a95dc8241893e922d1", [:mix], [{:hpax, "~> 1.0", [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", "551ba8ff5e4fc908cbeb8c9f0697775fb6813a96d9de5f7fe02e34e76fd7d184"}, 3 - "bcrypt_elixir": {:hex, :bcrypt_elixir, "3.2.1", "e361261a0401d82dadc1ab7b969f91d250bf7577283e933fe8c5b72f8f5b3c46", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "81170177d5c2e280d12141a0b9d9e299bf731535e2d959982bdcd4cfe3c82865"}, 4 "castore": {:hex, :castore, "1.0.12", "053f0e32700cbec356280c0e835df425a3be4bc1e0627b714330ad9d0f05497f", [:mix], [], "hexpm", "3dca286b2186055ba0c9449b4e95b97bf1b57b47c1f2644555879e659960c224"}, 5 - "comeonin": {:hex, :comeonin, "5.5.1", "5113e5f3800799787de08a6e0db307133850e635d34e9fab23c70b6501669510", [:mix], [], "hexpm", "65aac8f19938145377cee73973f192c5645873dcf550a8a6b18187d17c13ccdb"}, 6 "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, 7 "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, 8 "dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"}, 9 "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [: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", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, 10 "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 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", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, 11 - "elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"}, 12 "esbuild": {:hex, :esbuild, "0.9.0", "f043eeaca4932ca8e16e5429aebd90f7766f31ac160a25cbd9befe84f2bc068f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b415027f71d5ab57ef2be844b2a10d0c1b5a492d431727f43937adce22ba45ae"}, 13 "expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"}, 14 "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"},
··· 1 %{ 2 "bandit": {:hex, :bandit, "1.6.7", "42f30e37a1c89a2a12943c5dca76f731a2313e8a2e21c1a95dc8241893e922d1", [:mix], [{:hpax, "~> 1.0", [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", "551ba8ff5e4fc908cbeb8c9f0697775fb6813a96d9de5f7fe02e34e76fd7d184"}, 3 "castore": {:hex, :castore, "1.0.12", "053f0e32700cbec356280c0e835df425a3be4bc1e0627b714330ad9d0f05497f", [:mix], [], "hexpm", "3dca286b2186055ba0c9449b4e95b97bf1b57b47c1f2644555879e659960c224"}, 4 "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, 5 "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, 6 "dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"}, 7 "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [: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", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, 8 "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 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", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, 9 "esbuild": {:hex, :esbuild, "0.9.0", "f043eeaca4932ca8e16e5429aebd90f7766f31ac160a25cbd9befe84f2bc068f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b415027f71d5ab57ef2be844b2a10d0c1b5a492d431727f43937adce22ba45ae"}, 10 "expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"}, 11 "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"},
-15
priv/repo/migrations/20231005000000_create_users.exs
··· 1 - defmodule Tasty.Repo.Migrations.CreateUsers do 2 - use Ecto.Migration 3 - 4 - def change do 5 - create table(:users) do 6 - add :email, :string, null: false 7 - add :password_hash, :string, null: false 8 - # You can add more fields as needed, e.g., username, bio, etc. 9 - 10 - timestamps() 11 - end 12 - 13 - create unique_index(:users, [:email]) 14 - end 15 - end
···