Added addresses. Cleaning routes. Flow.
This commit is contained in:
parent
bb6d7e1e2d
commit
fe0d748a53
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"""
|
||||
<div class="border-b-4 flex flex-row justify-between">
|
||||
<h1 class="mb-0 pl-2" style="height:48px; text-indent:5px"><%= @friend.name %></h1>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
def menu(assigns) do
|
||||
~H"""
|
||||
<div class="hidden sm:tabs sm:mb-8">
|
||||
<%= for page <- [:overview, :timeline, :relationships] do %>
|
||||
<% is_active = if(page == @live_action) do "tab-active" end %>
|
||||
<.link patch={Routes.friends_show_path(FriendsWeb.Endpoint, page, @friend.slug)} class={"font-bold sm:tab-lg flex-grow no-underline tab tab-lifted #{is_active}"}>
|
||||
<%= page |> to_string |> :string.titlecase() %>
|
||||
</.link>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
def show_page(:main, assigns), do: show_page(:overview, %{assigns | live_action: :overview})
|
||||
|
||||
def show_page(:overview, assigns) do
|
||||
~H"""
|
||||
<ul class="py-4 pl-0 md:text-xl h-1/2">
|
||||
<li class="flex flex-row mb-8 gap-6">
|
||||
@ -32,18 +55,17 @@ defmodule FriendsWeb.FriendsLive.Components do
|
||||
<strong class="w-28 text-right">Phone:</strong>
|
||||
<div class=""><%= @friend.phone %></div>
|
||||
</li>
|
||||
<li class="flex flex-row mb-8 gap-6">
|
||||
<strong class="w-28 text-right">Address:</strong>
|
||||
<div class=""><%= @friend.address %></div>
|
||||
</li>
|
||||
</ul>
|
||||
<%= if @friend |> Friend.can_be_edited_by(@current_user) do %>
|
||||
<div class="form-control flex flex-row mb-4">
|
||||
<.link patch={"/friend/#{@friend.slug}/#{@page_view}/edit"} class="btn btn-block md:btn-wide text-white">edit</.link>
|
||||
</div>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
||||
def show_page("calendar", assigns) do
|
||||
def show_page(:timeline, assigns) do
|
||||
~H"""
|
||||
<div id="calendar" class="flex md:flex-row flex-col gap-8 p-8">
|
||||
<div id="timeline" class="flex md:flex-row flex-col gap-8 p-8">
|
||||
<%= for event <- @friend |> Friends.Friend.get_events do %>
|
||||
<ul>
|
||||
<li>
|
||||
@ -58,7 +80,7 @@ defmodule FriendsWeb.FriendsLive.Components do
|
||||
"""
|
||||
end
|
||||
|
||||
def show_page("relationships", assigns) do
|
||||
def show_page(:relationships, assigns) do
|
||||
~H"""
|
||||
<div id="relationships" class="flex md:flex-row flex-col gap-8">
|
||||
<%= for relation <- @friend |> relations do %>
|
||||
@ -80,15 +102,12 @@ defmodule FriendsWeb.FriendsLive.Components do
|
||||
<div class="italic p-4">No relationships on record yet.</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="form-control flex flex-row my-8">
|
||||
<.link patch={"/friend/#{@friend.slug}/update?page=relationships"} class="btn btn-block md:btn-wide text-white">edit</.link>
|
||||
</div>
|
||||
"""
|
||||
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
|
||||
|
||||
<div class="form-control flex flex-row gap-x-4 md:justify-end mb-4 md:w-1/2">
|
||||
<div class="flex-1">
|
||||
<.link patch={"/friend/#{@friend.slug}"} class="btn btn-block btn-outline">back</.link>
|
||||
<.link patch={Routes.friends_show_path(FriendsWeb.Endpoint, :overview, @friend.slug)} class="btn btn-block btn-outline">back</.link>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<%= 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
|
||||
|
||||
@ -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"""
|
||||
<div class="border-b-4 flex flex-row justify-between">
|
||||
<h1 class="mb-0 pl-2" style="height:48px; text-indent:5px"><%= @friend.name %></h1>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
def menu(assigns) do
|
||||
~H"""
|
||||
<div class="hidden sm:tabs sm:mb-8">
|
||||
<%= for page <- ["overview", "calendar", "relationships"] do %>
|
||||
<% is_active = if(page == @page_view) do "tab-active" end %>
|
||||
<.link patch={"/friend/#{@friend.slug}/#{page}"} class={"font-bold sm:tab-lg flex-grow no-underline tab tab-lifted #{is_active}"}>
|
||||
<%= page |> :string.titlecase() %>
|
||||
</.link>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
defmodule FriendsWeb.FriendLive do
|
||||
use FriendsWeb, :live_view
|
||||
end
|
||||
3
friends/lib/friends_web/live/friends_live.ex
Normal file
3
friends/lib/friends_web/live/friends_live.ex
Normal file
@ -0,0 +1,3 @@
|
||||
defmodule FriendsWeb.FriendsLive do
|
||||
use FriendsWeb, :live_view
|
||||
end
|
||||
@ -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
|
||||
|
||||
"""
|
||||
|
||||
@ -1,5 +1,13 @@
|
||||
<section class="row">
|
||||
<article class="column prose">
|
||||
<FriendsWeb.FriendLive.Friend.content friend={@friend} page_view={@page_view} changeset={@changeset} action={@action} live_action={@live_action}/>
|
||||
<%= Components.menu(assigns) %>
|
||||
<%= Components.header(assigns) %>
|
||||
<%= Components.show_page(@live_action, assigns) %>
|
||||
|
||||
<%= if @editable do %>
|
||||
<div class="form-control flex flex-row mb-4">
|
||||
<.link patch={Routes.friends_edit_path(FriendsWeb.Endpoint, :overview, @friend.slug)} class="btn btn-block md:btn-wide text-white">edit</.link>
|
||||
</div>
|
||||
<% end %>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<ul class="text-xl">
|
||||
<%= for f <- @all_friends do %>
|
||||
<li>
|
||||
<.link href={"/friend/#{f.slug}"}><%= f.name %></.link>
|
||||
<.link href={Routes.friends_show_path(@conn, :overview, f.slug)}><%= f.name %></.link>
|
||||
<%= if @current_user do %>
|
||||
<%= if f.id == @current_user.profile.id do %>
|
||||
(you)
|
||||
@ -14,6 +14,6 @@
|
||||
|
||||
<%= if @current_user do %>
|
||||
<div class="m-4 mt-16">
|
||||
<.link href="/friends/new" class="btn btn-primary">Add Friend</.link>
|
||||
<.link href={Routes.friends_edit_path(@conn, :overview, :new)}>Add Friend</.link>
|
||||
</div>
|
||||
<% end %>
|
||||
@ -9,7 +9,7 @@
|
||||
and basically go back to the 2011 Facebook we all miss.
|
||||
</p>
|
||||
<div class="hidden md:block">
|
||||
<.db_stats all_friends={@all_friends} users={@users} />
|
||||
<.friends_list friends={@friends} />
|
||||
</div>
|
||||
</div>
|
||||
<div id="sign-up" class="prose card md:w-fit bg-neutral-content text-neutral shadow-xl items-center">
|
||||
@ -20,7 +20,7 @@
|
||||
<.sign_up new_friend={@new_friend} />
|
||||
</div>
|
||||
</div>
|
||||
<div id="stats" class="prose w-full mb-8 md:hidden">
|
||||
<.db_stats all_friends={@all_friends} users={@users} />
|
||||
<div id="friends" class="prose w-full mb-8 md:hidden">
|
||||
<.friends_list friends={@friends} />
|
||||
</div>
|
||||
</div>
|
||||
@ -1,6 +1,5 @@
|
||||
defmodule FriendsWeb.FriendView do
|
||||
defmodule FriendsWeb.FriendsView do
|
||||
use FriendsWeb, :view
|
||||
import Phoenix.Component
|
||||
import Helpers
|
||||
|
||||
end
|
||||
@ -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
|
||||
|
||||
@ -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"""
|
||||
<h3 class="mt-12 border-b-2">
|
||||
Database stats
|
||||
</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<.link patch="/friends" class="">
|
||||
<%= pluralize(@all_friends |> length, "friend") %>
|
||||
</.link>
|
||||
</li>
|
||||
<li>
|
||||
<.link patch="/users" class="">
|
||||
<%= pluralize(@users |> length, "user") %>
|
||||
</.link>
|
||||
</li>
|
||||
</ul>
|
||||
"""
|
||||
All Friends
|
||||
</h3>
|
||||
<ul>
|
||||
<%= for friend <- @friends do %>
|
||||
<li>
|
||||
<div id={"friend-#{friend.id}"} class="">
|
||||
<div class="">
|
||||
<h3 class="">
|
||||
<.link href={Routes.live_path(FriendsWeb.Endpoint, FriendsWeb.FriendsLive.Show, friend.slug)}><%= friend.name %></.link>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
"""
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
18
friends/test/friends_web/controllers/friends_live_test.exs
Normal file
18
friends/test/friends_web/controllers/friends_live_test.exs
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user