Thanks again @t0t0 for your quick answer.
Well I’ve tried to keep going but now I have errors everywhere I’m gonna share my code and I hope do not bother you all with this challenge, btw I feel is becoming harder.
Thanks you all for your help
router.ex (most important part)
defmodule RumblWeb.Router do
use RumblWeb, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, html: {RumblWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
plug RumblWeb.Auth
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", RumblWeb do
pipe_through :browser
resources "/users", UserController, only: [:index, :show, :new, :create]
resources "/sessions", SessionController, only: [:new, :create, :delete]
get "/", PageController, :home
end
user_controller.ex
defmodule RumblWeb.UserController do
use RumblWeb, :controller
alias Rumbl.Accounts
alias Rumbl.Accounts.User
plug :authenticate when action in [:index, :show]
def index(conn, _params) do
users = Accounts.list_users()
render(conn, :index, users: users)
end
def show(conn, %{"id" => id}) do
user = Accounts.get_user(id)
render(conn, :show, user: user)
end
def new(conn, _params) do
changeset = Accounts.change_registration(%User{}, %{})
render(conn, :new, changeset: changeset)
end
def create(conn, %{"user" => user_params}) do
case Accounts.register_user(user_params) do
{:ok, user} ->
conn
|> RumblWeb.Auth.login(user)
|> put_flash(:info, "#{user.name} created!")
|> redirect(to: ~p"/users")
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, :new, changeset: changeset)
end
end
defp authenticate(conn, _opts) do
if conn.assigns.current_user do
conn
else
conn
|> put_flash(:error, "You must to be logged in to access that page")
|> redirect(to: ~p"/users")
|> halt()
end
end
end
session_controller.ex
defmodule RumblWeb.SessionController do
use RumblWeb, :controller
def new(conn, _) do
render(conn, :new)
end
def create(
conn,
%{"session" => %{"username" => username, "password" => pass}}
) do
case Rumbl.Accounts.authenticate_by_username_and_pass(username, pass) do
{:ok, user} ->
conn
|> RumblWeb.Auth.login(user)
|> put_flash(:info, "Welcome back!")
|> redirect(to: ~p"/")
{:error, _reason} -> conn
|> put_flash(:error, "Invalid username/password combination")
|> render(:new)
end
end
def delete(conn, _) do
conn
|> RumblWeb.Auth.logout()
|> redirect(to: ~p"/")
end
end
auth.ex
defmodule RumblWeb.Auth do
import Plug.Conn
def init(opts), do: opts
def call(conn, _opts) do
user_id = get_session(conn, :user_id)
user = user_id && Rumbl.Accounts.get_user(user_id)
assign(conn, :current_user, user)
end
def login(conn, user) do
conn
|> assign(:current_user, user)
|> put_session(:user_id, user.id)
|> configure_session(renew: true)
end
def logout(conn) do
configure_session(conn, drop: true)
end
end
session_html.ex
defmodule RumblWeb.SessionHTML do
use RumblWeb, :html
embed_templates "session_html/*"
end
user_html.ex
defmodule RumblWeb.UserHTML do
use RumblWeb, :html
embed_templates "user_html/*"
def first_name(name) do
name
|> String.split(" ")
|> Enum.at(0)
end
end
user_html/index.html.heex
<h1>Listing Users</h1>
<.table id="users" rows={@users}>
<:col :let={user} label="name"><%= first_name(user.name) %> (<%= user.id %>)</:col>
<:col :let={user} label="View"><.link href={~p"/users/#{user}"} class={[
"rounded-lg bg-zinc-900 hover:bg-zinc-700 py-2 px-3",
"text-sm font-semibold leading-6 text-white active:text-white/80"
]}>Show User</.link></:col>
</.table>
user_html/show.html.heex
<.header>
User
</.header>
<.list>
<:item title="ID"><%= @user.id %></:item>
<:item title="Name"><%= @user.name %></:item>
<:item title="Username"><%= @user.username %></:item>
</.list>
session_html/new.html.heex
<.header>
Login
</.header>
<.simple_form
:let={f}
for={@conn}
as={:session}
phx-change="validate"
action={~p"/sessions"}>
<.input field={f[:username]} label="Username" />
<.input field={f[:password]} label="Password" />
<:actions>
<.button>Log in</.button>
</:actions>
</.simple_form>
Apologize for adding so much text. My main errors right know are trying to access localhost:4000/users (list all users) or localhost:4000/users/1 (show an user) both cases without a session I got a ERR_TOO_MANY_REDIRECTS to me seems I’m having a kind of cycle issue.
The other error is trying to access localhost:4000/sessions/new (for logging in and using a new window incognito mode)
protocol Phoenix.HTML.FormData not implemented for %Plug.Conn{adapter: {Bandit.HTTP1.Adapter, :...}, assigns: %{layout: {RumblWeb.Layouts, "app"}, flash: %{}, current_user: nil}, body_params: %{}, cookies: %{}, halted: false, host: "localhost", method: "GET", owner: #PID<0.17659.0>, params: %{}, path_info: ["sessions", "new"], path_params: %{}, port: 4000, private: %{:phoenix_template => "new.html", :phoenix_view => %{"html" => RumblWeb.SessionHTML, "json" => RumblWeb.SessionJSON}, RumblWeb.Router => [], :phoenix_action => :new, :phoenix_layout => %{"html" => {RumblWeb.Layouts, :app}}, :phoenix_controller => RumblWeb.SessionController, :phoenix_endpoint => RumblWeb.Endpoint, :phoenix_format => "html", :phoenix_root_layout => %{"html" => {RumblWeb.Layouts, :root}}, :phoenix_router => RumblWeb.Router, :plug_session_fetch => :done, :plug_session => %{}, :before_send => [#Function<0.71811376/1 in Plug.CSRFProtection.call/2>, #Function<4.6073741/1 in Phoenix.Controller.fetch_flash/2>, #Function<0.76384852/1 in Plug.Session.before_send/2>, #Function<0.54455629/1 in Plug.Telemetry.call/2>, #Function<1.22806296/1 in Phoenix.LiveReloader.before_send_inject_reloader/3>], :phoenix_request_logger => {"request_logger", "request_logger"}}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %{}, req_headers: [{"accept-language", "es-ES,es;q=0.9"}, {"accept-encoding", "gzip, deflate, br, zstd"}, {"sec-fetch-dest", "document"}, {"sec-fetch-user", "?1"}, {"sec-fetch-mode", "navigate"}, {"sec-fetch-site", "none"}, {"accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"}, {"user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"}, {"upgrade-insecure-requests", "1"}, {"sec-ch-ua-platform", "\"macOS\""}, {"sec-ch-ua-mobile", "?0"}, {"sec-ch-ua", "\"Chromium\";v=\"122\", \"Not(A:Brand\";v=\"24\", \"Google Chrome\";v=\"122\""}, {"connection", "keep-alive"}, {"host", "localhost:4000"}], request_path: "/sessions/new", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "F7qNKGQBSv2pJN4AANdC"}, {"referrer-policy", "strict-origin-when-cross-origin"}, {"x-content-type-options", "nosniff"}, {"x-download-options", "noopen"}, {"x-frame-options", "SAMEORIGIN"}, {"x-permitted-cross-domain-policies", "none"}], scheme: :http, script_name: [], secret_key_base: :..., state: :unset, status: nil} of type Plug.Conn (a struct). This protocol is implemented for the following type(s): Ecto.Changeset, Map
Any help or idea to keep searching will be welcome.