From 6afdcdfa3e65b5e29f249aeb05485e9850624f8b Mon Sep 17 00:00:00 2001 From: theMarinac Date: Wed, 11 Dec 2019 15:56:22 +0100 Subject: [PATCH] readme update --- README.md | 174 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 158 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 90155b2..cbd3b86 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Auth tutorial for setting up basic user auth with `put_session()` -**NOTE: PHOENIX_APP and PHOENIX_APP_WEB are just macros here, in your app user your apps name!** - ## Deps used ```bash @@ -22,9 +20,11 @@ Make sure that you have some context that is like `Accounts.User` with `email:un You can do this with ```bash -terminal:~/PHOENIX_PROJECT/$ mix phx.gen.html Accounts User users email:string:unique password_hash:string +terminal:~/tutorial/$ mix phx.gen.html Accounts User users email:string:unique password_hash:string ``` +Add `resources "/users", UserController, singleton: true` to the `router.ex` + ### Password hashing After that open up `accounts/user.ex` and add line bellow to `changeset()` @@ -38,12 +38,12 @@ end ### Auth helper -In `PHOENIX_APP_WEB/` create folder `/helpers` and create file `auth.ex` +In `/tutorial_web/` create folder `/helpers` and create file `auth.ex` ```elixir -defmodule PHOENIX_APP_WEB.Helpers.Auth do +defmodule TutorialWeb.Helpers.Auth do import Plug.Conn, only: [get_session: 2] - alias PHOENIX_APP.{Repo, Accounts.User} + alias Tutorial.{Repo, Accounts.User} def signed_in?(conn) do user_id = get_session(conn, :current_user_id) @@ -52,13 +52,13 @@ defmodule PHOENIX_APP_WEB.Helpers.Auth do end ``` -Then open your `PHOENIX_APP_WEB.ex` and inside add this `import`, we are doing this because we want to have this function in every `view` +Then open your `tutorial_web.ex` and inside add this `import`, we are doing this because we want to have this function in every `view` ```elixir def view do quote do ... - import PHOENIX_APP_WEB.Helpers.Auth, only: [signed_in?: 1] + import TutorialWeb.Helpers.Auth, only: [signed_in?: 1] end end ``` @@ -120,8 +120,8 @@ One will be used for Signing in and the other for Signing out Create `session_view.ex` in `/views` folder ```elixir -defmodule PHOENIX_APP_WEB.SessionView do - use PHOENIX_APP_WEB, :view +defmodule TutorialWeb.SessionView do + use TutorialWeb, :view end ``` @@ -130,7 +130,7 @@ end under you `scope "/"` add following ```elixir -scope "/", PHOENIX_APP_WEB do +scope "/", TutorialWeb do pipe_through :browser ... # Sign in @@ -148,11 +148,13 @@ end #### Controller -```elixir -defmodule PHOENIX_APP_WEB.SessionController do - use PHOENIX_APP_WEB, :controller +Create `session_controller.ex` in `/controllers` - alias PHOENIX_APP.Accounts +```elixir +defmodule TutorialWeb.SessionController do + use TutorialWeb, :controller + + alias Tutorial.Accounts alias Accounts.User def sign_in(conn, _params) do @@ -214,4 +216,144 @@ defmodule PHOENIX_APP_WEB.SessionController do end end -``` \ No newline at end of file +``` + +#### Update `accounts.ex` + +Remember when we wrote `user = Accounts.get_by_email(auth_params["email"])` we need to define that fn +Open `accounts.ex` and add this fn after `get_user!(id)` + +```elixir + def get_by_email(nil), do: nil + + def get_by_email(email), do: User |> Repo.get_by(email: email) +``` + +**NOTE** We will use advantage of pattern matching and create two fn-s just in case we get `nil` + +#### Update `user_controller.ex` + +##### Part 1 (update params) + +In `UserController` `show`, `edit`, `update` and `delete` second param is trying to pattern match for `%{"id" => id}` but since we are going to get user data from `conn.asssigns.current_user` go ahead and replace `%{"id" => id}` with `_params` + +```elixir +def FN(conn, %{"id" => id}) do + ... +end +# CHANGE TO +def FN(conn, _params) do + ... +end +``` + +*Do that for all 4 of them* + +##### Part 2 (update user data) + +We are still in `UserController` and fn's `show`, `edit`, `update` and `delete` are using that `id` that we just removed, to obtain user data. We are going to change that now + +```elixir +# Change +user = Accounts.get_user!(id) +# Into +user = conn.assigns.current_user +``` + +### Set `conn.assigns.current_user` + +Now we need to assign `current_user` to `@conn`. But how? +Read more to find out. :) + +#### Setting up Auth Plug + +You remember that `/helpers` folder that we created earlier? Open it and create new file inside, called `plug_auth.ex` and put this code inside. + +```elixir +defmodule TutorialWeb.Helpers.AuthGuest do + import Plug.Conn + import Phoenix.Controller + alias Tutorial.Accounts + + def init(default), do: default + + def call(conn, _opts) do + user_id = get_session(conn, :current_user_id) + auth_reply(conn, user_id) + end + + defp auth_reply(conn, nil) do + conn + |> put_flash(:error, "You have to sign in first!") + |> redirect(to: "/sign-in") + |> halt() + end + + defp auth_reply(conn, user_id) do + user = Accounts.get_user!(user_id) + + conn + |> assign(:current_user, user) + end +end +``` + +After that add this code into your `router.ex` + +```elixir + pipeline :auth do + plug TutorialWeb.Helpers.AuthGuest + end +``` + +And add that pipeline in `pipe_through` for scope you want to require logged user +For example: + +```elixir +scope "/", TutorialWeb do + pipe_through [:browser, :auth] + resources "/users", UserController, singleton: true +end +``` + +## Templates update /users/ && add Sign-in and Sign-out links + +### User template + +After adding all of this, few things need to be considered. + +* `singleton: true` + * We don't want our user to have acces to the list of **ALL USERS** so we need to remove links that point `to: Routes.user_path(@conn, :index)`. + Lets give that power only to admin. + +* UserController fn-s `new` and `create` + * Again we don't want our user to be able to use these functions that are pre-generated by + `mix phx.gen.html` so we should delete those **files**, **controller functions** and **limit** + them in `router.ex`. Update existing resources tag with following. + `resources "/users", UserController, only: [:show, :edit, :update], singleton: true` + +* Update UserController fn's with redirect + * Some fn's where you redirect to path that doesn't take user as params + but you still pass it because of `mix phx.gen.html`. You just need to + remove that user. + +And finally lets open `/layout/app.html.eex` and add following + +```elixir +<%= if signed_in?(@conn) do %> + <%= link "Sign out", to: Routes.session_path(@conn, :sign_out), method: :post %> +<% else %> + <%= link "Sign in", to: Routes.session_path(@conn, :sign_in), method: :get %> + | + <%= link "Sign up", to: Routes.session_path(@conn, :sign_up), method: :get %> +<% end %> +``` + +**** + +## mix phx.server + +Yep you read it, just run your app now and it should most of it gucci. :) +*except the `html.eex` files that you didn't change* :P + +****