From fe0d748a53a46723fd18b6a764c3516188c7a585 Mon Sep 17 00:00:00 2001 From: Ryan Pandya Date: Sat, 5 Nov 2022 18:12:02 -0700 Subject: [PATCH] Added addresses. Cleaning routes. Flow. --- friends/lib/friends/friend.ex | 57 ++++++---- ...nd_controller.ex => friends_controller.ex} | 5 +- .../controllers/page_controller.ex | 7 +- .../lib/friends_web/controllers/user_auth.ex | 19 ++-- .../friends_web/live/components/components.ex | 51 ++++++--- friends/lib/friends_web/live/friend.ex | 83 +------------- friends/lib/friends_web/live/friend_live.ex | 3 - friends/lib/friends_web/live/friends_live.ex | 3 + friends/lib/friends_web/live/show.ex | 51 +++++---- friends/lib/friends_web/live/show.html.heex | 10 +- friends/lib/friends_web/router.ex | 79 +++++++------ .../{friend => friends}/index.html.heex | 4 +- .../templates/page/index.html.heex | 6 +- .../views/{friend_view.ex => friends_view.ex} | 3 +- friends/lib/friends_web/views/live_helpers.ex | 22 +++- friends/lib/friends_web/views/page_view.ex | 35 +++--- ...0221105233742_add_addresses_to_friends.exs | 9 ++ friends/test/friends/friends_test.exs | 106 +++++++++--------- ...r_test.exs => friends_controller_test.exs} | 15 ++- .../controllers/friends_live_test.exs | 18 +++ .../controllers/page_controller_test.exs | 18 ++- 21 files changed, 318 insertions(+), 286 deletions(-) rename friends/lib/friends_web/controllers/{friend_controller.ex => friends_controller.ex} (69%) delete mode 100644 friends/lib/friends_web/live/friend_live.ex create mode 100644 friends/lib/friends_web/live/friends_live.ex rename friends/lib/friends_web/templates/{friend => friends}/index.html.heex (63%) rename friends/lib/friends_web/views/{friend_view.ex => friends_view.ex} (66%) create mode 100644 friends/priv/repo/migrations/20221105233742_add_addresses_to_friends.exs rename friends/test/friends_web/controllers/{friend_controller_test.exs => friends_controller_test.exs} (60%) create mode 100644 friends/test/friends_web/controllers/friends_live_test.exs diff --git a/friends/lib/friends/friend.ex b/friends/lib/friends/friend.ex index 69fe5e3..e88f868 100644 --- a/friends/lib/friends/friend.ex +++ b/friends/lib/friends/friend.ex @@ -12,6 +12,7 @@ defmodule Friends.Friend do field(:nickname, :string) field(:born, :date) field(:phone, :string) + field(:address, :string) field(:email, :string) field(:slug, :string) field(:memories, {:array, :string}) @@ -89,15 +90,15 @@ defmodule Friends.Friend do def create(params) do %Friend{} - |> Friend.changeset(%{params | id: nil}) - |> Map.put(:action, :insert) + |> Friend.changeset(%{params | id: nil}) + |> Map.put(:action, :insert) end def update(params) do - {:ok, Friend.get_by_id(params.id |> String.to_integer()) - |> Friend.changeset(params) - |> Map.put(:action, :update) - } + {:ok, + Friend.get_by_id(params.id |> String.to_integer()) + |> Friend.changeset(params) + |> Map.put(:action, :update)} end def commit(changeset) do @@ -107,18 +108,19 @@ defmodule Friends.Friend do |> load_preloads end - def generate_slug(%Ecto.Changeset{} = changeset) do slug = changeset.changes.name |> to_slug - changeset |> changeset(%{ + changeset + |> changeset(%{ slug: slug }) end def generate_slug(%Friend{} = friend) do %{ - friend | slug: friend.name |> to_slug + friend + | slug: friend.name |> to_slug } end @@ -128,11 +130,12 @@ defmodule Friends.Friend do params |> create() |> commit() + _number -> params |> update() |> commit() - end + end end def get_relationships(friend) do @@ -154,15 +157,16 @@ defmodule Friends.Friend do end def can_be_edited_by(friend, user) do - friend.id == user.profile.id + if user |> is_nil(), do: false, else: friend.id == user.profile.id end def assign_user(%Friend{} = friend) do - case friend.email |> Friends.Accounts.get_user_by_email do + case friend.email |> Friends.Accounts.get_user_by_email() do nil -> nil + user -> - user |> Friends.Accounts.assign_profile + user |> Friends.Accounts.assign_profile() end end @@ -170,24 +174,31 @@ defmodule Friends.Friend do model |> @repo.preload(:user) end + def load_user(%Friends.Friend{} = friend), do: friend - def load_relationships(%Friends.Friend{ - relationships: %Ecto.Association.NotLoaded{}, - reverse_relationships: %Ecto.Association.NotLoaded{} - } = model) do + def load_relationships( + %Friends.Friend{ + relationships: %Ecto.Association.NotLoaded{}, + reverse_relationships: %Ecto.Association.NotLoaded{} + } = model + ) do model |> @repo.preload([:relationships, :reverse_relationships]) end + def load_relationships(%Friends.Friend{} = friend), do: friend - def load_preloads(%Friends.Friend{ - relationships: %Ecto.Association.NotLoaded{}, - reverse_relationships: %Ecto.Association.NotLoaded{}, - user: %Ecto.Association.NotLoaded{}} = model) do + def load_preloads( + %Friends.Friend{ + relationships: %Ecto.Association.NotLoaded{}, + reverse_relationships: %Ecto.Association.NotLoaded{}, + user: %Ecto.Association.NotLoaded{} + } = model + ) do model - |> @repo.preload([:user,:relationships, :reverse_relationships]) + |> @repo.preload([:user, :relationships, :reverse_relationships]) end - def load_preloads(%Friends.Friend{} = friend), do: friend + def load_preloads(%Friends.Friend{} = friend), do: friend end diff --git a/friends/lib/friends_web/controllers/friend_controller.ex b/friends/lib/friends_web/controllers/friends_controller.ex similarity index 69% rename from friends/lib/friends_web/controllers/friend_controller.ex rename to friends/lib/friends_web/controllers/friends_controller.ex index 8709ee7..8ed8cdf 100644 --- a/friends/lib/friends_web/controllers/friend_controller.ex +++ b/friends/lib/friends_web/controllers/friends_controller.ex @@ -1,13 +1,12 @@ -defmodule FriendsWeb.FriendController do +defmodule FriendsWeb.FriendsController do use FriendsWeb, :controller alias Friends.{Friend, Relationship} alias Friends.Accounts.User import Helpers def index(conn, _params) do - conn - |> assign(:all_friends, Friend.all) + |> assign(:all_friends, Friend.all()) |> render("index.html") end end diff --git a/friends/lib/friends_web/controllers/page_controller.ex b/friends/lib/friends_web/controllers/page_controller.ex index d24f1da..8bcd260 100644 --- a/friends/lib/friends_web/controllers/page_controller.ex +++ b/friends/lib/friends_web/controllers/page_controller.ex @@ -7,15 +7,14 @@ defmodule FriendsWeb.PageController do def index(conn, _params) do new_friend = Friend.new() |> Friend.changeset() - if(conn|> get_session(:linked)) do + if(conn |> get_session(:linked)) do # If logged in and linked, redirect to friend_path :index - conn |> redirect(to: FriendsWeb.Router.Helpers.friend_path(conn, :index)) + conn |> redirect(to: FriendsWeb.Router.Helpers.friends_path(conn, :index)) else # Otherwise, show the landing page conn |> assign(:new_friend, new_friend) - |> assign(:all_friends, Friend.all()) - |> assign(:users, User |> Repo.all()) + |> assign(:friends, Friend.all()) |> render("index.html") end end diff --git a/friends/lib/friends_web/controllers/user_auth.ex b/friends/lib/friends_web/controllers/user_auth.ex index 3965abb..4da5ac7 100644 --- a/friends/lib/friends_web/controllers/user_auth.ex +++ b/friends/lib/friends_web/controllers/user_auth.ex @@ -128,18 +128,21 @@ defmodule FriendsWeb.UserAuth do end @doc """ - Used when a user is signed in and should therefore have a profile linked. + Used to detect or link a profile to a user. """ def capture_profile(conn, _opts) do current_user = conn.assigns[:current_user] + if current_user do # There's a user, but is there a profile? profile = current_user |> Map.get(:profile) + case profile do nil -> # No profile linked conn |> create_or_link_profile(current_user) + _profile -> # Profile already linked conn |> put_session(:linked, true) @@ -151,31 +154,31 @@ defmodule FriendsWeb.UserAuth do end defp create_or_link_profile(conn, user) do - case user.email |> Friends.Friend.get_by_email do + case user.email |> Friends.Friend.get_by_email() do # Find a profile and link it nil -> conn - |> redirect(to: Routes.profile_form_path(conn, :new)) + |> put_flash(:info, "You're logged in but we still need to make you a profile!") + |> redirect(to: Routes.friends_edit_path(conn, :overview, :new)) |> halt() + # Or make a new one - profile -> + _profile -> user - |> Friends.Accounts.assign_profile + |> Friends.Accounts.assign_profile() conn |> put_session(:linked, true) - 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 + def require_authenticated_user(conn, _opts \\ nil) do if conn.assigns[:current_user] do conn else diff --git a/friends/lib/friends_web/live/components/components.ex b/friends/lib/friends_web/live/components/components.ex index ce9a01a..ce896b9 100644 --- a/friends/lib/friends_web/live/components/components.ex +++ b/friends/lib/friends_web/live/components/components.ex @@ -4,7 +4,30 @@ defmodule FriendsWeb.FriendsLive.Components do import Helpers alias Friends.Friend - def show_page("overview", assigns) do + def header(assigns) do + ~H""" +
+

<%= @friend.name %>

+
+ """ + end + + def menu(assigns) do + ~H""" + + """ + end + + def show_page(:main, assigns), do: show_page(:overview, %{assigns | live_action: :overview}) + + def show_page(:overview, assigns) do ~H""" - <%= if @friend |> Friend.can_be_edited_by(@current_user) do %> -
- <.link patch={"/friend/#{@friend.slug}/#{@page_view}/edit"} class="btn btn-block md:btn-wide text-white">edit -
- <% end %> """ end - def show_page("calendar", assigns) do + def show_page(:timeline, assigns) do ~H""" -
+
<%= for event <- @friend |> Friends.Friend.get_events do %>
  • @@ -58,7 +80,7 @@ defmodule FriendsWeb.FriendsLive.Components do """ end - def show_page("relationships", assigns) do + def show_page(:relationships, assigns) do ~H"""
    <%= for relation <- @friend |> relations do %> @@ -80,15 +102,12 @@ defmodule FriendsWeb.FriendsLive.Components do
    No relationships on record yet.
    <% end %>
    -
    - <.link patch={"/friend/#{@friend.slug}/update?page=relationships"} class="btn btn-block md:btn-wide text-white">edit -
    """ end ### - def form_page("overview", assigns) do + def edit_page(:overview, assigns) do ~H""" <.form for={@changeset} @@ -140,7 +159,7 @@ defmodule FriendsWeb.FriendsLive.Components do
    - <.link patch={"/friend/#{@friend.slug}"} class="btn btn-block btn-outline">back + <.link patch={Routes.friends_show_path(FriendsWeb.Endpoint, :overview, @friend.slug)} class="btn btn-block btn-outline">back
    <%= if @changeset.valid? do %> @@ -159,9 +178,9 @@ defmodule FriendsWeb.FriendsLive.Components do """ end - def form_page("relationships", assigns) do + def edit_page(:relationships, assigns) do ~H""" - <%= FriendsWeb.FriendLive.Friend.header(assigns) %> + <%= Components.header(assigns) %> """ end end diff --git a/friends/lib/friends_web/live/friend.ex b/friends/lib/friends_web/live/friend.ex index d789cff..2bceeca 100644 --- a/friends/lib/friends_web/live/friend.ex +++ b/friends/lib/friends_web/live/friend.ex @@ -1,7 +1,7 @@ defmodule FriendsWeb.FriendsLive.Friend do use FriendsWeb, :live_view - alias FriendsWeb.FriendLive.Components + alias FriendsWeb.FriendsLive.Components alias FriendsWeb.Router.Helpers, as: Routes alias Friends.Friend @@ -18,32 +18,6 @@ defmodule FriendsWeb.FriendsLive.Friend do |> assign(:changeset, %Friend{} |> Friend.changeset())} end - # Show Friend - def handle_params(%{"slug" => slug} = attrs, _url, socket) do - friend = Friend.get_by_slug(slug) - - page = - if (attrs |> Map.get("page")) in ["overview", "calendar", "relationships"] do - attrs["page"] - else - "redir" - end - - if page == "redir" do - {:noreply, - socket - |> push_patch(to: "/friend/#{slug}/overview")} - else - {:noreply, - socket - |> title(friend.name <> " - " <> (page |> :string.titlecase())) - |> assign_friend(friend) - |> page_view(page) - |> assign(:current_user, nil) - |> assign(:action, Routes.friend_path(socket, :update, friend.id))} - end - end - # New Friend def handle_params(_attrs, _token, socket) do friend = Friend.new() @@ -52,8 +26,7 @@ defmodule FriendsWeb.FriendsLive.Friend do socket |> title("New Friend") |> assign_friend(friend) - |> page_view("overview") - |> assign(:action, Routes.friend_path(socket, :create))} + |> assign(:action, Routes.friends_path(socket, :create))} end # Handle form validation @@ -134,57 +107,5 @@ defmodule FriendsWeb.FriendsLive.Friend do |> push_navigate(to: "/")} end - # Set variables on page: friend, changeset, relationships - def assign_friend(socket, friend) do - socket - |> assign(:friend, friend) - |> assign(:changeset, friend |> Friend.changeset()) - |> assign(:relationships, friend.relationships) - end - - # Same thing, but this time we have a changeset we want to keep - def assign_friend(socket, friend, changeset) do - socket - |> assign(:friend, friend) - |> assign(:changeset, changeset) - |> assign(:relationships, friend.relationships) - end - # Route to the right sub-template in Components/Components.ex - def content(assigns) do - ~H""" - <%= if @live_action != :new do %> - <%= FriendsWeb.FriendsLive.Friend.menu(assigns) %> - <% end %> - <%= cond do %> - <% @live_action == :show -> %> - <%= header(assigns) %> - <%= @page_view |> Components.show_page(assigns) %> - <% @live_action in [:edit, :new] -> %> - <%= @page_view |> Components.form_page(assigns) %> - <% end %> - """ - end - - def header(assigns) do - ~H""" -
    -

    <%= @friend.name %>

    -
    - """ - end - - def menu(assigns) do - ~H""" - - - """ - end end diff --git a/friends/lib/friends_web/live/friend_live.ex b/friends/lib/friends_web/live/friend_live.ex deleted file mode 100644 index edfef0a..0000000 --- a/friends/lib/friends_web/live/friend_live.ex +++ /dev/null @@ -1,3 +0,0 @@ -defmodule FriendsWeb.FriendLive do - use FriendsWeb, :live_view -end diff --git a/friends/lib/friends_web/live/friends_live.ex b/friends/lib/friends_web/live/friends_live.ex new file mode 100644 index 0000000..6ab079b --- /dev/null +++ b/friends/lib/friends_web/live/friends_live.ex @@ -0,0 +1,3 @@ +defmodule FriendsWeb.FriendsLive do + use FriendsWeb, :live_view +end diff --git a/friends/lib/friends_web/live/show.ex b/friends/lib/friends_web/live/show.ex index c2fb39a..af77f2c 100644 --- a/friends/lib/friends_web/live/show.ex +++ b/friends/lib/friends_web/live/show.ex @@ -1,31 +1,40 @@ -""" -defmodule FriendsWeb.FriendLive.Show do +defmodule FriendsWeb.FriendsLive.Show do use FriendsWeb, :live_view + import FriendsWeb.LiveHelpers alias Friends.Friend + alias FriendsWeb.FriendsLive.Components - def handle_params(attrs, token, socket) do - FriendsWeb.FriendLive.Friend.handle_params(attrs, token, socket) + def mount(%{"slug" => slug} = _attrs, token, socket) do + live_action = socket.assigns.live_action || false + + friend = Friend.get_by_slug(slug) + editable = friend |> Friend.can_be_edited_by(socket.assigns[:current_user]) + + if(live_action) do + {:ok, + socket + |> assign(:live_action, live_action) + |> assign_current_user(token |> Map.get("user_token")) + |> assign(:friend, friend) + |> title(friend.name <> " - " <> (live_action |> titlecase)) + |> assign(:changeset, %Friend{} |> Friend.changeset()) + |> assign(:action, editable)} + else + {:ok, socket |> redirect(to: Routes.friends_show_path(socket, :overview, friend.slug))} + end end - def mount(%{"slug" => slug} = attrs, token, socket) do - friend = slug |> Friends.Friend.get_by_slug() + def handle_params(%{"slug" => slug} = attrs, _url, socket) do + live_action = socket.assigns.live_action || false - page = - if (attrs |> Map.get("page")) in ["overview", "calendar", "relationships"] do - attrs["page"] - else - "overview" - end + friend = Friend.get_by_slug(slug) + editable = friend |> Friend.can_be_edited_by(socket.assigns[:current_user]) - {:ok, + {:noreply, socket - |> title(friend.name <> " - " <> (page |> :string.titlecase())) - |> page_view(page) - |> assign_current_user(token |> Map.get("user_token")) - |> assign(:friend, friend) - |> assign(:changeset, %Friend{} |> Friend.changeset()) - |> assign(:action, Routes.friend_path(socket, :update, friend.id))} + |> assign_friend(friend) + |> assign(:live_action, live_action) + |> title(friend.name <> " - " <> (live_action |> titlecase)) + |> assign(:editable, editable)} end end - -""" diff --git a/friends/lib/friends_web/live/show.html.heex b/friends/lib/friends_web/live/show.html.heex index 39e6945..4b76ca2 100644 --- a/friends/lib/friends_web/live/show.html.heex +++ b/friends/lib/friends_web/live/show.html.heex @@ -1,5 +1,13 @@
    - + <%= Components.menu(assigns) %> + <%= Components.header(assigns) %> + <%= Components.show_page(@live_action, assigns) %> + + <%= if @editable do %> +
    + <.link patch={Routes.friends_edit_path(FriendsWeb.Endpoint, :overview, @friend.slug)} class="btn btn-block md:btn-wide text-white">edit +
    + <% end %>
    diff --git a/friends/lib/friends_web/router.ex b/friends/lib/friends_web/router.ex index 7226300..ba0962d 100644 --- a/friends/lib/friends_web/router.ex +++ b/friends/lib/friends_web/router.ex @@ -52,54 +52,63 @@ defmodule FriendsWeb.Router do end ## Authentication routes - - scope "/", FriendsWeb do + # Routes that only work if user not authenticated + scope "/users", FriendsWeb do pipe_through [:browser, :redirect_if_user_is_authenticated] - # Requires the user NOT be authenticated: - - get "/users/register", UserRegistrationController, :new - post "/users/register", UserRegistrationController, :create - get "/users/log_in", UserSessionController, :new - post "/users/log_in", UserSessionController, :create - get "/users/reset_password", UserResetPasswordController, :new - post "/users/reset_password", UserResetPasswordController, :create - get "/users/reset_password/:token", UserResetPasswordController, :edit - put "/users/reset_password/:token", UserResetPasswordController, :update + get "/register", UserRegistrationController, :new + post "/register", UserRegistrationController, :create + get "/log_in", UserSessionController, :new + post "/log_in", UserSessionController, :create + get "/reset_password", UserResetPasswordController, :new + post "/reset_password", UserResetPasswordController, :create + get "/reset_password/:token", UserResetPasswordController, :edit + put "/reset_password/:token", UserResetPasswordController, :update end - scope "/", FriendsWeb do - pipe_through [:browser, :require_authenticated_user] - # Requires the user DO be authenticated: - - live "/profile/new", ProfileLive.Form, :new - - get "/users/settings", UserSettingsController, :edit - put "/users/settings", UserSettingsController, :update - get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email - end - - scope "/", FriendsWeb do + # Confirmation and logout + scope "/users", FriendsWeb do pipe_through [:browser] - - delete "/users/log_out", UserSessionController, :delete - get "/users/confirm", UserConfirmationController, :new - post "/users/confirm", UserConfirmationController, :create - get "/users/confirm/:token", UserConfirmationController, :edit - post "/users/confirm/:token", UserConfirmationController, :update + delete "/log_out", UserSessionController, :delete + get "/confirm", UserConfirmationController, :new + post "/confirm", UserConfirmationController, :create + get "/confirm/:token", UserConfirmationController, :edit + post "/confirm/:token", UserConfirmationController, :update end + # Routes that require the user be authenticated: + scope "/users/settings", FriendsWeb do + pipe_through [:browser, :require_authenticated_user] + get "/", UserSettingsController, :edit + put "/", UserSettingsController, :update + get "/confirm_email/:token", UserSettingsController, :confirm_email + end # THE ACTUAL GUTS OF THE APP scope "/", FriendsWeb do pipe_through [:browser, :capture_profile] - get "/", PageController, :index - get "/friends", FriendController, :index - - live "/friend/:slug", FriendLive.Show - live "/friend/:slug/edit", FriendLive.Edit end + # View-only modes (don't require being logged in and having a profile) + scope "/friends", FriendsWeb do + pipe_through [:browser] + get "/", FriendsController, :index + live "/:slug", FriendsLive.Show + live "/:slug/overview", FriendsLive.Show, :overview + live "/:slug/timeline", FriendsLive.Show, :timeline + live "/:slug/relationships", FriendsLive.Show, :relationships + end + + # Edit modes (require being logged in and having a profile) + scope "/update/", FriendsWeb do + pipe_through [:browser, :require_authenticated_user, :capture_profile] + + live "/:slug/overview", FriendsLive.Edit, :overview + live "/:slug/timeline", FriendsLive.Edit, :timeline + live "/:slug/relationships", FriendsLive.Edit, :relationships + + post "/:slug/update", FriendsController, :update + end end diff --git a/friends/lib/friends_web/templates/friend/index.html.heex b/friends/lib/friends_web/templates/friends/index.html.heex similarity index 63% rename from friends/lib/friends_web/templates/friend/index.html.heex rename to friends/lib/friends_web/templates/friends/index.html.heex index 171a8b8..c89c1e8 100644 --- a/friends/lib/friends_web/templates/friend/index.html.heex +++ b/friends/lib/friends_web/templates/friends/index.html.heex @@ -3,7 +3,7 @@
      <%= for f <- @all_friends do %>
    • - <.link href={"/friend/#{f.slug}"}><%= f.name %> + <.link href={Routes.friends_show_path(@conn, :overview, f.slug)}><%= f.name %> <%= if @current_user do %> <%= if f.id == @current_user.profile.id do %> (you) @@ -14,6 +14,6 @@ <%= if @current_user do %>
      - <.link href="/friends/new" class="btn btn-primary">Add Friend + <.link href={Routes.friends_edit_path(@conn, :overview, :new)}>Add Friend
      <% end %> \ No newline at end of file diff --git a/friends/lib/friends_web/templates/page/index.html.heex b/friends/lib/friends_web/templates/page/index.html.heex index d63ea4f..943fdc2 100644 --- a/friends/lib/friends_web/templates/page/index.html.heex +++ b/friends/lib/friends_web/templates/page/index.html.heex @@ -9,7 +9,7 @@ and basically go back to the 2011 Facebook we all miss.

    @@ -20,7 +20,7 @@ <.sign_up new_friend={@new_friend} />
    -
    - <.db_stats all_friends={@all_friends} users={@users} /> +
    + <.friends_list friends={@friends} />
    \ No newline at end of file diff --git a/friends/lib/friends_web/views/friend_view.ex b/friends/lib/friends_web/views/friends_view.ex similarity index 66% rename from friends/lib/friends_web/views/friend_view.ex rename to friends/lib/friends_web/views/friends_view.ex index 25950cc..b613979 100644 --- a/friends/lib/friends_web/views/friend_view.ex +++ b/friends/lib/friends_web/views/friends_view.ex @@ -1,6 +1,5 @@ -defmodule FriendsWeb.FriendView do +defmodule FriendsWeb.FriendsView do use FriendsWeb, :view import Phoenix.Component import Helpers - end diff --git a/friends/lib/friends_web/views/live_helpers.ex b/friends/lib/friends_web/views/live_helpers.ex index c214372..5c7fbca 100644 --- a/friends/lib/friends_web/views/live_helpers.ex +++ b/friends/lib/friends_web/views/live_helpers.ex @@ -1,5 +1,10 @@ defmodule FriendsWeb.LiveHelpers do use FriendsWeb, :live_component + alias Friends.Friend + + def titlecase(atom) do + atom |> to_string |> :string.titlecase() + end def assign_current_user(socket, user_token) do user = @@ -26,8 +31,19 @@ defmodule FriendsWeb.LiveHelpers do |> assign(:page_title, title) end - # Set page_view variable - def page_view(socket, page) do - socket |> assign(:page_view, page) + # Set variables on page: friend, changeset, relationships + def assign_friend(socket, friend) do + socket + |> assign(:friend, friend) + |> assign(:changeset, friend |> Friend.changeset()) + |> assign(:relationships, friend.relationships) + end + + # Same thing, but this time we have a changeset we want to keep + def assign_friend(socket, friend, changeset) do + socket + |> assign(:friend, friend) + |> assign(:changeset, changeset) + |> assign(:relationships, friend.relationships) end end diff --git a/friends/lib/friends_web/views/page_view.ex b/friends/lib/friends_web/views/page_view.ex index b8ca1b2..b993a6d 100644 --- a/friends/lib/friends_web/views/page_view.ex +++ b/friends/lib/friends_web/views/page_view.ex @@ -6,24 +6,25 @@ defmodule FriendsWeb.PageView do alias FriendsWeb.Components.SignUp, as: SignUp def sign_up(assigns), do: SignUp.sign_up_form(assigns) - def db_stats(assigns) do + + def friends_list(assigns) do ~H"""

    - Database stats -

    -
      -
    • - <.link patch="/friends" class=""> - <%= pluralize(@all_friends |> length, "friend") %> - -
    • -
    • - <.link patch="/users" class=""> - <%= pluralize(@users |> length, "user") %> - -
    • -
    - """ + All Friends + +
      + <%= for friend <- @friends do %> +
    • +
      +
      +

      + <.link href={Routes.live_path(FriendsWeb.Endpoint, FriendsWeb.FriendsLive.Show, friend.slug)}><%= friend.name %> +

      +
      +
      +
    • + <% end %> +
    + """ end - end diff --git a/friends/priv/repo/migrations/20221105233742_add_addresses_to_friends.exs b/friends/priv/repo/migrations/20221105233742_add_addresses_to_friends.exs new file mode 100644 index 0000000..49c763f --- /dev/null +++ b/friends/priv/repo/migrations/20221105233742_add_addresses_to_friends.exs @@ -0,0 +1,9 @@ +defmodule Friends.Repo.Migrations.AddAddressesToFriends do + use Ecto.Migration + + def change do + alter table(:friends) do + add :address, :string + end + end +end diff --git a/friends/test/friends/friends_test.exs b/friends/test/friends/friends_test.exs index c8c76fc..51127f3 100644 --- a/friends/test/friends/friends_test.exs +++ b/friends/test/friends/friends_test.exs @@ -3,20 +3,22 @@ defmodule Friends.FriendsTest do alias Friends.Friend - import Friends.{AccountsFixtures,FriendsFixtures} - # alias Friends.Accounts.{User, UserToken} + import Friends.{AccountsFixtures, FriendsFixtures} + # alias Friends.Accounts.{User, UserToken} describe "new/1" do test "no params" do f = Friend.new() assert f.id == :new end + test "with params" do attrs = valid_friend_attributes() f = attrs |> Friend.new() assert f.id == :new assert f.name == attrs |> Map.get(:name) end + test "has no loaded preloads" do f = Friend.new() assert %Ecto.Association.NotLoaded{} = f.user @@ -27,19 +29,22 @@ defmodule Friends.FriendsTest do describe "commit/1" do test "changes id" do - f = valid_friend_attributes() - |> Friend.create() - |> Friend.commit() + f = + valid_friend_attributes() + |> Friend.create() + |> Friend.commit() assert f.id != :new end - test "generates slug" do - f = valid_friend_attributes() - |> Friend.create() - |> Friend.commit() - assert f.slug != :nil - assert f.slug == f.name |> Helpers.to_slug + test "generates slug" do + f = + valid_friend_attributes() + |> Friend.create() + |> Friend.commit() + + assert f.slug != nil + assert f.slug == f.name |> Helpers.to_slug() end end @@ -48,38 +53,41 @@ defmodule Friends.FriendsTest do f = valid_friend_attributes() |> Friend.new() assert f.slug == nil end + test "generate_slug generates a slug, returns a friend" do - f = valid_friend_attributes() |> Friend.new() |> Friend.generate_slug - assert f.slug == f.name |> Helpers.to_slug + f = valid_friend_attributes() |> Friend.new() |> Friend.generate_slug() + assert f.slug == f.name |> Helpers.to_slug() end + test "generate_slug generates a slug, returns a changeset" do - c = valid_friend_attributes() |> Friend.create() |> Friend.generate_slug + c = valid_friend_attributes() |> Friend.create() |> Friend.generate_slug() f = c.data - assert f.slug == f.name |> Helpers.to_slug + assert f.slug == f.name |> Helpers.to_slug() end end - describe "assign_user/1" do - setup do - friend = friend_fixture() - %{ - friend: friend, - user: user_fixture(%{email: friend.email}) - } - end - test "links a user to a friend", %{user: user, friend: friend} do - assert user.profile == nil - assert friend.user == nil + describe "assign_user/1" do + setup do + friend = friend_fixture() - %{ - friend: new_friend, - user: new_user - } = friend |> Friends.Friend.assign_user + %{ + friend: friend, + user: user_fixture(%{email: friend.email}) + } + end - assert new_user.profile.id == friend.id - assert new_friend.user.id == user.id + test "links a user to a friend", %{user: user, friend: friend} do + assert user.profile == nil + assert friend.user == nil - end + %{ + friend: new_friend, + user: new_user + } = friend |> Friends.Friend.assign_user() + + assert new_user.profile.id == friend.id + assert new_friend.user.id == user.id + end end describe "preloads" do @@ -89,32 +97,30 @@ defmodule Friends.FriendsTest do test "default nothing loaded", %{friend: friend} do f = friend - refute f.user |> Ecto.assoc_loaded? - refute f.relationships |> Ecto.assoc_loaded? - refute f.reverse_relationships |> Ecto.assoc_loaded? + refute f.user |> Ecto.assoc_loaded?() + refute f.relationships |> Ecto.assoc_loaded?() + refute f.reverse_relationships |> Ecto.assoc_loaded?() end test "load user", %{friend: friend} do - f = friend |> Friend.load_user - assert f.user |> Ecto.assoc_loaded? - refute f.relationships |> Ecto.assoc_loaded? - refute f.reverse_relationships |> Ecto.assoc_loaded? + f = friend |> Friend.load_user() + assert f.user |> Ecto.assoc_loaded?() + refute f.relationships |> Ecto.assoc_loaded?() + refute f.reverse_relationships |> Ecto.assoc_loaded?() end test "load relationships", %{friend: friend} do - f = friend |> Friend.load_relationships - refute f.user |> Ecto.assoc_loaded? - assert f.relationships |> Ecto.assoc_loaded? - assert f.reverse_relationships |> Ecto.assoc_loaded? + f = friend |> Friend.load_relationships() + refute f.user |> Ecto.assoc_loaded?() + assert f.relationships |> Ecto.assoc_loaded?() + assert f.reverse_relationships |> Ecto.assoc_loaded?() end test "load all", %{friend: friend} do - f = friend |> Friend.load_preloads - assert f.user |> Ecto.assoc_loaded? - assert f.relationships |> Ecto.assoc_loaded? - assert f.reverse_relationships |> Ecto.assoc_loaded? + f = friend |> Friend.load_preloads() + assert f.user |> Ecto.assoc_loaded?() + assert f.relationships |> Ecto.assoc_loaded?() + assert f.reverse_relationships |> Ecto.assoc_loaded?() end - end - end diff --git a/friends/test/friends_web/controllers/friend_controller_test.exs b/friends/test/friends_web/controllers/friends_controller_test.exs similarity index 60% rename from friends/test/friends_web/controllers/friend_controller_test.exs rename to friends/test/friends_web/controllers/friends_controller_test.exs index 3696061..a800657 100644 --- a/friends/test/friends_web/controllers/friend_controller_test.exs +++ b/friends/test/friends_web/controllers/friends_controller_test.exs @@ -1,19 +1,15 @@ -defmodule FriendsWeb.FriendControllerTest do +defmodule FriendsWeb.FriendsControllerTest do use FriendsWeb.ConnCase, async: true - import Friends.{AccountsFixtures,FriendsFixtures} + import Friends.{AccountsFixtures, FriendsFixtures} setup do %{ user: _user, friend: _friend - } = - friend_fixture( - %{email: user_fixture().email} - ) |> Friends.Friend.assign_user + } = friend_fixture(%{email: user_fixture().email}) |> Friends.Friend.assign_user() end describe "GET '/friends'" do - test "shows the friends dashboard", %{conn: conn, friend: friend} do conn = get(conn, "/friends") assert html_response(conn, 200) =~ friend.name @@ -27,6 +23,9 @@ defmodule FriendsWeb.FriendControllerTest do assert html_response(conn, 200) =~ "Log out" end + test "shows option to add friend if logged in", %{conn: conn, friend: friend, user: user} do + conn = conn |> log_in_user(user) |> get("/friends") + assert html_response(conn, 200) =~ Routes.friends_edit_path(conn, :overview, :new) + end end - end diff --git a/friends/test/friends_web/controllers/friends_live_test.exs b/friends/test/friends_web/controllers/friends_live_test.exs new file mode 100644 index 0000000..966a857 --- /dev/null +++ b/friends/test/friends_web/controllers/friends_live_test.exs @@ -0,0 +1,18 @@ +defmodule FriendsWeb.FriendsLiveTest do + use FriendsWeb.ConnCase, async: true + import Friends.{AccountsFixtures, FriendsFixtures} + + setup do + %{ + user: _user, + friend: _friend + } = friend_fixture(%{email: user_fixture().email}) |> Friends.Friend.assign_user() + end + + describe "GET '/friends/:slug'" do + test "shows the friend overview", %{conn: conn, friend: friend} do + conn = conn |> get("/friends/#{friend.slug}") + assert html_response(conn, 200) =~ friend.name + end + end +end diff --git a/friends/test/friends_web/controllers/page_controller_test.exs b/friends/test/friends_web/controllers/page_controller_test.exs index d85c125..5b2bb6f 100644 --- a/friends/test/friends_web/controllers/page_controller_test.exs +++ b/friends/test/friends_web/controllers/page_controller_test.exs @@ -1,6 +1,6 @@ defmodule FriendsWeb.PageControllerTest do use FriendsWeb.ConnCase, async: true - import Friends.{AccountsFixtures,FriendsFixtures} + import Friends.{AccountsFixtures, FriendsFixtures} alias FriendsWeb.Router.Helpers, as: Routes @@ -16,17 +16,23 @@ defmodule FriendsWeb.PageControllerTest do assert html_response(conn, 200) =~ "Register" end - test "redirects to the new profile flow if logged in but has no profile", %{conn: conn, user: user} do + test "redirects to the new profile flow if logged in but has no profile", %{ + conn: conn, + user: user + } do _friend = friend_fixture(%{email: "random_email@invalid.biz"}) conn = conn |> log_in_user(user) |> get("/") - assert redirected_to(conn) == Routes.profile_form_path(conn, :new) + assert redirected_to(conn) == Routes.friends_edit_path(conn, :overview, :new) + assert get_flash(conn, :info) =~ "profile!" end - test "redirects to the friends dashboard if logged in & has a profile", %{conn: conn, user: user} do + test "redirects to the friends dashboard if logged in & has a profile", %{ + conn: conn, + user: user + } do _friend = friend_fixture(%{email: user.email}) conn = conn |> log_in_user(user) |> get("/") - assert redirected_to(conn) == Routes.friend_path(conn, :index) + assert redirected_to(conn) == Routes.friends_path(conn, :index) end - end end