<%= get_flash(@conn, :info) %>
+<%= get_flash(@conn, :error) %>
<%= @inner_content %>diff --git a/friends/lib/friends/accounts/user.ex b/friends/lib/friends/accounts/user.ex index e63a464..db2af5a 100644 --- a/friends/lib/friends/accounts/user.ex +++ b/friends/lib/friends/accounts/user.ex @@ -2,6 +2,8 @@ defmodule Friends.Accounts.User do use Ecto.Schema import Ecto.Changeset + @repo Friends.Repo + schema "users" do field :email, :string field :password, :string, virtual: true, redact: true @@ -9,6 +11,17 @@ defmodule Friends.Accounts.User do field :confirmed_at, :naive_datetime timestamps() + + has_one :profile, Friends.Friend + end + + def load_profile(%Friends.Accounts.User{profile: %Ecto.Association.NotLoaded{}} = model) do + model + |> @repo.preload(:profile) + end + + def load_profile(nil) do + %{profile: nil} end @doc """ @@ -47,7 +60,7 @@ defmodule Friends.Accounts.User do defp validate_password(changeset, opts) do changeset |> validate_required([:password]) - |> validate_length(:password, min: 12, max: 72) + |> validate_length(:password, min: 6, max: 72) # |> validate_format(:password, ~r/[a-z]/, message: "at least one lower case character") # |> validate_format(:password, ~r/[A-Z]/, message: "at least one upper case character") # |> validate_format(:password, ~r/[!?@#$%^&*_0-9]/, message: "at least one digit or punctuation character") diff --git a/friends/lib/friends/accounts/user_notifier.ex b/friends/lib/friends/accounts/user_notifier.ex index b8d4806..c3cec41 100644 --- a/friends/lib/friends/accounts/user_notifier.ex +++ b/friends/lib/friends/accounts/user_notifier.ex @@ -8,7 +8,7 @@ defmodule Friends.Accounts.UserNotifier do email = new() |> to(recipient) - |> from({"Friends", "contact@example.com"}) + |> from({"Friends App", "ryan@pandu.ski"}) |> subject(subject) |> text_body(body) diff --git a/friends/lib/friends/friend.ex b/friends/lib/friends/friend.ex index 62294f5..27a26f8 100644 --- a/friends/lib/friends/friend.ex +++ b/friends/lib/friends/friend.ex @@ -16,7 +16,7 @@ defmodule Friends.Friend do field(:slug, :string) field(:memories, {:array, :string}) - # has_many(:photos, Media.Photo) + belongs_to :user, Friends.Accounts.User, foreign_key: :user_id many_to_many( :relationships, @@ -35,20 +35,26 @@ defmodule Friends.Friend do def changeset(friend, params \\ %{}) do friend - |> Ecto.Changeset.cast(params, [:name, :born, :nickname, :email, :phone, :slug]) + |> Ecto.Changeset.cast(params, [:name, :born, :nickname, :email, :phone, :slug, :user_id]) |> Ecto.Changeset.validate_required([:name, :email, :phone, :born]) |> Ecto.Changeset.validate_format(:name, ~r/\w+\ \w+/) - |> Ecto.Changeset.validate_format(:email, Regex.compile!("^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")) - |> Ecto.Changeset.validate_format(:phone, Regex.compile!("^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$")) + |> Ecto.Changeset.validate_format( + :email, + Regex.compile!("^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$") + ) + |> Ecto.Changeset.validate_format( + :phone, + Regex.compile!("^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$") + ) |> Ecto.Changeset.unique_constraint(:name) + |> Ecto.Changeset.unique_constraint(:email) end def all() do - preloads = [:relationships, :reverse_relationships] + preloads = [:relationships, :reverse_relationships, :user] @repo.all(from(f in Friends.Friend, preload: ^preloads)) end - def new(params \\ %{}) do %Friend{id: "new"} |> struct(params) @@ -62,6 +68,7 @@ defmodule Friends.Friend do ) ) end + def get_by_id(id) do @repo.one( from(f in Friend, @@ -71,49 +78,61 @@ defmodule Friends.Friend do ) end + def get_by_email(email) do + @repo.one( + from(f in Friend, + where: f.email == ^email, + preload: [:relationships, :reverse_relationships] + ) + ) + end + def create_or_update(params) do case params.id do "new" -> - %Friend{} |> Friend.changeset(%{params | id: nil}) - |> Map.put(:action, :insert) - |> @repo.insert! - _number -> - Friend.get_by_id(params.id |> String.to_integer) - |> Friend.changeset(params) - |> Map.put(:action, :update) - |> @repo.update! + %Friend{} + |> Friend.changeset(%{params | id: nil}) + |> Map.put(:action, :insert) + |> @repo.insert! + + _number -> + Friend.get_by_id(params.id |> String.to_integer()) + |> Friend.changeset(params) + |> Map.put(:action, :update) + |> @repo.update! end end def get_relationships(friend) do friend - |> relations - |> Enum.map(&(relation(friend, &1))) + |> relations + |> Enum.map(&relation(friend, &1)) end def get_events(friend) do friend - |> get_relationships - |> Enum.map(&(&1.events)) - |> List.flatten + |> get_relationships + |> Enum.map(& &1.events) + |> List.flatten() end def age(friend) do # Age in years - Date.diff(Date.utc_today,friend.born) |> div(365) + Date.diff(Date.utc_today(), friend.born) |> div(365) end # TODO: Refactor def create_birth_event(friend) do - if is_nil @repo.all( - from(e in Friends.Event, - where: e.name == "born" - )) |> List.flatten do + if is_nil( + @repo.all( + from(e in Friends.Event, + where: e.name == "born" + ) + ) + |> List.flatten() + ) do else "find" end end - - - end diff --git a/friends/lib/friends_web/controllers/friend_controller.ex b/friends/lib/friends_web/controllers/friend_controller.ex new file mode 100644 index 0000000..8709ee7 --- /dev/null +++ b/friends/lib/friends_web/controllers/friend_controller.ex @@ -0,0 +1,13 @@ +defmodule FriendsWeb.FriendController 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) + |> 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 7401d19..be9f39e 100644 --- a/friends/lib/friends_web/controllers/page_controller.ex +++ b/friends/lib/friends_web/controllers/page_controller.ex @@ -1,16 +1,63 @@ defmodule FriendsWeb.PageController do use FriendsWeb, :controller - alias Friends.{Friend, Relationship} - import Helpers + alias Friends.{Friend, Repo, Accounts.User} + + import Helpers.Names + + plug :assign_profile def index(conn, _params) do - - new_friend = Friend.new |> Friend.changeset + new_friend = Friend.new() |> Friend.changeset() conn |> assign(:new_friend, new_friend) - |> assign(:all_friends, Friend.all) - |> assign(:users, Friends.Accounts.User |> Friends.Repo.all) + |> assign(:all_friends, Friend.all()) + |> assign(:users, User |> Repo.all()) |> render("index.html") end + + defp assign_profile(conn, _opts) do + current_user = conn.assigns.current_user + + case current_user do + nil -> + # No logged in user, and no profile + conn + + user -> + case user.profile do + nil -> + # Logged in user, but no profile + # Is there a profile with the same email? + try_profile = user.email |> Friends.Friend.get_by_email() + + case try_profile do + nil -> + # If not, we need to make a new profile + conn + |> redirect(to: Routes.profile_form_path(conn, :new)) + + # If so, link 'em and be done with it + friend -> + friend + |> Friends.Friend.changeset(%{ + user_id: user.id + }) + |> Friends.Repo.update!() + + conn + |> put_flash( + :info, + "Welcome to the app, #{friend |> first_name()}!" + ) + |> redirect(to: Routes.friend_path(conn, :index)) + end + + _profile -> + # Logged in user, and linked profile + conn + |> redirect(to: Routes.friend_path(conn, :index)) + end + end + end end diff --git a/friends/lib/friends_web/controllers/user_auth.ex b/friends/lib/friends_web/controllers/user_auth.ex index 30eb900..742a75c 100644 --- a/friends/lib/friends_web/controllers/user_auth.ex +++ b/friends/lib/friends_web/controllers/user_auth.ex @@ -91,7 +91,13 @@ defmodule FriendsWeb.UserAuth do def fetch_current_user(conn, _opts) do {user_token, conn} = ensure_user_token(conn) user = user_token && Accounts.get_user_by_session_token(user_token) - assign(conn, :current_user, user) + + assign( + conn, + :current_user, + user + |> Friends.Repo.preload(:profile) + ) end defp ensure_user_token(conn) do diff --git a/friends/lib/friends_web/controllers/user_profile_controller.ex b/friends/lib/friends_web/controllers/user_profile_controller.ex new file mode 100644 index 0000000..9bd9695 --- /dev/null +++ b/friends/lib/friends_web/controllers/user_profile_controller.ex @@ -0,0 +1,32 @@ +defmodule FriendsWeb.UserProfileController do + use FriendsWeb, :controller + + alias Friends.Accounts + alias FriendsWeb.Router.Helpers, as: Routes + + plug :assign_profile + + + + @doc """ + Checks if the user has linked a profile yet, + and redirects to the profile creation flow + if not. + """ + def main(conn) do + conn + |> put_flash(:info, "test") + end + + defp assign_profile(conn, _opts) do + user = conn.assigns.current_user + + msg = case user.profile do + nil -> "No profile!" + profile -> "Yes profile! #{profile.name}" + end + + conn + |> put_flash(:info, msg) + end +end diff --git a/friends/lib/friends_web/router.ex b/friends/lib/friends_web/router.ex index 125b8dd..ef62b00 100644 --- a/friends/lib/friends_web/router.ex +++ b/friends/lib/friends_web/router.ex @@ -21,8 +21,10 @@ defmodule FriendsWeb.Router do pipe_through :browser get "/", PageController, :index - live "/friend/:slug", FriendsLive.Show + get "/friends", FriendController, :index + live "/friend/:slug", FriendLive.Show + live "/friend/:slug/edit", FriendLive.Edit end # Other scopes may use custom stacks. @@ -63,6 +65,7 @@ defmodule FriendsWeb.Router do scope "/", 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 @@ -76,6 +79,9 @@ defmodule FriendsWeb.Router do 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 diff --git a/friends/lib/friends_web/templates/friend/index.html.heex b/friends/lib/friends_web/templates/friend/index.html.heex new file mode 100644 index 0000000..355e334 --- /dev/null +++ b/friends/lib/friends_web/templates/friend/index.html.heex @@ -0,0 +1,13 @@ +
<%= get_flash(@conn, :info) %>
+<%= get_flash(@conn, :error) %>
<%= @inner_content %>You have made a user account, but we don't yet have a profile for you.
+ +