mirror of
https://github.com/danbee/chess
synced 2025-03-04 08:39:06 +00:00
User can sign in
This commit is contained in:
parent
9be77a9ad0
commit
374524bb1d
12
lib/chess/auth/error_handler.ex
Normal file
12
lib/chess/auth/error_handler.ex
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
defmodule Chess.Auth.ErrorHandler do
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
import Plug.Conn
|
||||||
|
|
||||||
|
def auth_error(conn, {type, _reason}, _opts) do
|
||||||
|
body = to_string(type)
|
||||||
|
conn
|
||||||
|
|> put_resp_content_type("text/plain")
|
||||||
|
|> send_resp(401, body)
|
||||||
|
end
|
||||||
|
end
|
||||||
17
lib/chess/auth/pipeline.ex
Normal file
17
lib/chess/auth/pipeline.ex
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
defmodule Chess.Auth.Pipeline do
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
use Guardian.Plug.Pipeline,
|
||||||
|
otp_app: :chess,
|
||||||
|
error_handler: Chess.Auth.ErrorHandler,
|
||||||
|
module: Chess.Auth.Guardian
|
||||||
|
|
||||||
|
# If there is a session token, validate it
|
||||||
|
plug Guardian.Plug.VerifySession, claims: %{"typ" => "access"}
|
||||||
|
|
||||||
|
# If there is an authorization header, validate it
|
||||||
|
plug Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"}
|
||||||
|
|
||||||
|
# Load the user if either of the verifications worked
|
||||||
|
plug Guardian.Plug.LoadResource, allow_blank: true
|
||||||
|
end
|
||||||
@ -14,6 +14,11 @@ defmodule Chess.Auth.User do
|
|||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def changeset(user) do
|
||||||
|
user
|
||||||
|
|> cast(%{}, [:username, :password])
|
||||||
|
end
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
def changeset(%User{} = user, attrs) do
|
def changeset(%User{} = user, attrs) do
|
||||||
user
|
user
|
||||||
|
|||||||
@ -40,6 +40,8 @@ defmodule ChessWeb do
|
|||||||
# Use all HTML functionality (forms, tags, etc)
|
# Use all HTML functionality (forms, tags, etc)
|
||||||
use Phoenix.HTML
|
use Phoenix.HTML
|
||||||
|
|
||||||
|
import Formulator
|
||||||
|
|
||||||
import ChessWeb.Router.Helpers
|
import ChessWeb.Router.Helpers
|
||||||
import ChessWeb.ErrorHelpers
|
import ChessWeb.ErrorHelpers
|
||||||
import ChessWeb.Gettext
|
import ChessWeb.Gettext
|
||||||
|
|||||||
28
lib/chess_web/controllers/session_controller.ex
Normal file
28
lib/chess_web/controllers/session_controller.ex
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
defmodule ChessWeb.SessionController do
|
||||||
|
use ChessWeb, :controller
|
||||||
|
|
||||||
|
alias Chess.Auth
|
||||||
|
alias Chess.Auth.User
|
||||||
|
|
||||||
|
def new(conn, _params) do
|
||||||
|
changeset = User.changeset(%User{})
|
||||||
|
render(conn, "new.html", changeset: changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(
|
||||||
|
conn,
|
||||||
|
%{"user" => %{"username" => username, "password" => password}}
|
||||||
|
) do
|
||||||
|
case Auth.authenticate_user(username, password) do
|
||||||
|
{:ok, _user} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "You are signed in")
|
||||||
|
|> redirect(to: game_path(conn, :index))
|
||||||
|
{:error, _error} ->
|
||||||
|
changeset = User.changeset(%User{})
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, "Bad username or password")
|
||||||
|
|> render("new.html", changeset: changeset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -17,7 +17,8 @@ defmodule ChessWeb.Router do
|
|||||||
pipe_through :browser # Use the default browser stack
|
pipe_through :browser # Use the default browser stack
|
||||||
|
|
||||||
get "/", GameController, :index
|
get "/", GameController, :index
|
||||||
resources "/games", GameController, only: [:create, :show, :delete]
|
resources "/games", GameController, only: [:index, :create, :show, :delete]
|
||||||
|
resources "/session", SessionController, only: [:new, :create], singleton: true
|
||||||
end
|
end
|
||||||
|
|
||||||
# Other scopes may use custom stacks.
|
# Other scopes may use custom stacks.
|
||||||
|
|||||||
@ -1,2 +0,0 @@
|
|||||||
<div id="app">
|
|
||||||
</div>
|
|
||||||
21
lib/chess_web/templates/session/new.html.eex
Normal file
21
lib/chess_web/templates/session/new.html.eex
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<h2>Sign in</h2>
|
||||||
|
|
||||||
|
<%= form_for @changeset, session_path(@conn, :create), [class: "create-session"], fn f -> %>
|
||||||
|
<%= if @changeset.action do %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p>Oops, something went wrong! Please check the errors below.</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-field">
|
||||||
|
<%= input f, :username %>
|
||||||
|
</div>
|
||||||
|
<div class="form-field">
|
||||||
|
<%= input f, :password, as: :password %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<%= submit "Sign in", class: "btn btn-primary" %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
@ -1,3 +0,0 @@
|
|||||||
defmodule ChessWeb.PageView do
|
|
||||||
use ChessWeb, :view
|
|
||||||
end
|
|
||||||
3
lib/chess_web/views/session_view.ex
Normal file
3
lib/chess_web/views/session_view.ex
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
defmodule ChessWeb.SessionView do
|
||||||
|
use ChessWeb, :view
|
||||||
|
end
|
||||||
1
mix.exs
1
mix.exs
@ -33,6 +33,7 @@ defmodule Chess.Mixfile do
|
|||||||
[{:argon2_elixir, "~> 1.2"},
|
[{:argon2_elixir, "~> 1.2"},
|
||||||
{:comeonin, "~> 4.0"},
|
{:comeonin, "~> 4.0"},
|
||||||
{:credo, "~> 0.8", only: [:dev, :test]},
|
{:credo, "~> 0.8", only: [:dev, :test]},
|
||||||
|
{:formulator, "~> 0.1.6"},
|
||||||
{:phoenix, "~> 1.3.0"},
|
{:phoenix, "~> 1.3.0"},
|
||||||
{:phoenix_pubsub, "~> 1.0"},
|
{:phoenix_pubsub, "~> 1.0"},
|
||||||
{:phoenix_ecto, "~> 3.0"},
|
{:phoenix_ecto, "~> 3.0"},
|
||||||
|
|||||||
1
mix.lock
1
mix.lock
@ -14,6 +14,7 @@
|
|||||||
"elixir_make": {:hex, :elixir_make, "0.4.0", "992f38fabe705bb45821a728f20914c554b276838433349d4f2341f7a687cddf", [:mix], [], "hexpm"},
|
"elixir_make": {:hex, :elixir_make, "0.4.0", "992f38fabe705bb45821a728f20914c554b276838433349d4f2341f7a687cddf", [:mix], [], "hexpm"},
|
||||||
"file_system": {:hex, :file_system, "0.2.4", "f0bdda195c0e46e987333e986452ec523aed21d784189144f647c43eaf307064", [:mix], [], "hexpm"},
|
"file_system": {:hex, :file_system, "0.2.4", "f0bdda195c0e46e987333e986452ec523aed21d784189144f647c43eaf307064", [:mix], [], "hexpm"},
|
||||||
"fs": {:hex, :fs, "0.9.2", "ed17036c26c3f70ac49781ed9220a50c36775c6ca2cf8182d123b6566e49ec59", [], []},
|
"fs": {:hex, :fs, "0.9.2", "ed17036c26c3f70ac49781ed9220a50c36775c6ca2cf8182d123b6566e49ec59", [], []},
|
||||||
|
"formulator": {:hex, :formulator, "0.1.6", "266caf4c4bce2b7dc5be2da5e55d8c36120b3eaa6a5f82b9a6c1342ddbc18597", [:mix], [{:gettext, ">= 0.11.0", [hex: :gettext, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.4", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"gettext": {:hex, :gettext, "0.14.0", "1a019a2e51d5ad3d126efe166dcdf6563768e5d06c32a99ad2281a1fa94b4c72", [:mix], [], "hexpm"},
|
"gettext": {:hex, :gettext, "0.14.0", "1a019a2e51d5ad3d126efe166dcdf6563768e5d06c32a99ad2281a1fa94b4c72", [:mix], [], "hexpm"},
|
||||||
"guardian": {:hex, :guardian, "1.0.1", "db0fbaf571c3b874785818b7272eaf5f1ed97a2f9b1f8bc5dc8b0fb8f8f7bb06", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}, {:uuid, ">= 1.1.1", [hex: :uuid, repo: "hexpm", optional: false]}], "hexpm"},
|
"guardian": {:hex, :guardian, "1.0.1", "db0fbaf571c3b874785818b7272eaf5f1ed97a2f9b1f8bc5dc8b0fb8f8f7bb06", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}, {:uuid, ">= 1.1.1", [hex: :uuid, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"hackney": {:hex, :hackney, "1.10.1", "c38d0ca52ea80254936a32c45bb7eb414e7a96a521b4ce76d00a69753b157f21", [:rebar3], [{:certifi, "2.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
|
"hackney": {:hex, :hackney, "1.10.1", "c38d0ca52ea80254936a32c45bb7eb414e7a96a521b4ce76d00a69753b157f21", [:rebar3], [{:certifi, "2.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
|
|||||||
8
test/chess_web/controllers/session_controller_test.exs
Normal file
8
test/chess_web/controllers/session_controller_test.exs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
defmodule Chess.SessionControllerTest do
|
||||||
|
use ChessWeb.ConnCase
|
||||||
|
|
||||||
|
test "shows sign in form", %{conn: conn} do
|
||||||
|
conn = get conn, session_path(conn, :new)
|
||||||
|
assert html_response(conn, 200) =~ "Sign in"
|
||||||
|
end
|
||||||
|
end
|
||||||
39
test/features/session_test.exs
Normal file
39
test/features/session_test.exs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
defmodule Chess.SessionTest do
|
||||||
|
use ChessWeb.FeatureCase
|
||||||
|
|
||||||
|
alias Chess.Auth.User
|
||||||
|
|
||||||
|
import Wallaby.Query, only: [text_field: 1, button: 1]
|
||||||
|
|
||||||
|
test "user cannot sign in with incorrect password", %{session: session} do
|
||||||
|
create_user()
|
||||||
|
|
||||||
|
session
|
||||||
|
|> visit("/session/new")
|
||||||
|
|> fill_in(text_field("Username"), with: "link@example.com")
|
||||||
|
|> fill_in(text_field("Password"), with: "calamityganon")
|
||||||
|
|> click(button("Sign in"))
|
||||||
|
|
||||||
|
assert session |> has_text?("Bad username or password")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "user can sign in with correct details", %{session: session} do
|
||||||
|
create_user()
|
||||||
|
|
||||||
|
session
|
||||||
|
|> visit("/session/new")
|
||||||
|
|> fill_in(text_field("Username"), with: "link@example.com")
|
||||||
|
|> fill_in(text_field("Password"), with: "ilovezelda")
|
||||||
|
|> click(button("Sign in"))
|
||||||
|
|
||||||
|
assert session |> has_text?("You are signed in")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp create_user() do
|
||||||
|
changeset = User.changeset(
|
||||||
|
%User{},
|
||||||
|
%{username: "link@example.com", password: "ilovezelda"}
|
||||||
|
)
|
||||||
|
Repo.insert!(changeset)
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user