1
0
mirror of https://github.com/danbee/chess synced 2025-03-04 08:39:06 +00:00

User can login and create games

This commit is contained in:
Daniel Barber 2018-01-28 19:35:37 -05:00
parent dda4bf0c5a
commit 1299d4f5e5
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
10 changed files with 112 additions and 19 deletions

View File

@ -23,9 +23,10 @@ config :logger, :console,
metadata: [:request_id] metadata: [:request_id]
# Configure authentication provider # Configure authentication provider
# Replace secret_key in prod.secret.exs
config :chess, Chess.Auth.Guardian, config :chess, Chess.Auth.Guardian,
issuer: "chess", issuer: "chess",
secret_key: System.get_env("GUARDIAN_SECRET_KEY") secret_key: "vd2vXkrYTTFKSKmNMoS2/Hk4Fxn8BkyzsVArRkxJazdQ3mr6bI4YgAC6f8ODiWlM"
# Import environment specific config. This must remain at the bottom # Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.

View File

@ -3,10 +3,10 @@ defmodule Chess.Auth.ErrorHandler do
import Plug.Conn import Plug.Conn
def auth_error(conn, {type, _reason}, _opts) do def auth_error(conn, {_type, _reason}, _opts) do
body = to_string(type)
conn conn
|> put_resp_content_type("text/plain") |> Phoenix.Controller.put_flash(:info, "You must be logged in")
|> send_resp(401, body) |> Phoenix.Controller.redirect(to: "/")
|> halt()
end end
end end

View File

@ -1,5 +1,5 @@
defmodule Chess.Auth.Guardian do defmodule Chess.Auth.Guardian do
use Guardian, otp_app: :auth_ex use Guardian, otp_app: :chess
alias Chess.Auth alias Chess.Auth
@ -10,8 +10,7 @@ defmodule Chess.Auth.Guardian do
def resource_from_claims(claims) do def resource_from_claims(claims) do
user = claims["sub"] user = claims["sub"]
|> Auth.get_user! |> Auth.get_user!
{:ok, user}
# If something goes wrong here return {:error, reason} {:ok, user}
end end
end end

View File

@ -35,7 +35,8 @@ defmodule ChessWeb do
namespace: ChessWeb namespace: ChessWeb
# Import convenience functions from controllers # Import convenience functions from controllers
import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1] import Phoenix.Controller,
only: [get_csrf_token: 0, get_flash: 2, view_module: 1]
# Use all HTML functionality (forms, tags, etc) # Use all HTML functionality (forms, tags, etc)
use Phoenix.HTML use Phoenix.HTML

View File

@ -3,6 +3,7 @@ defmodule ChessWeb.SessionController do
alias Chess.Auth alias Chess.Auth
alias Chess.Auth.User alias Chess.Auth.User
alias Chess.Auth.Guardian
def new(conn, _params) do def new(conn, _params) do
changeset = User.changeset(%User{}) changeset = User.changeset(%User{})
@ -14,8 +15,9 @@ defmodule ChessWeb.SessionController do
%{"user" => %{"username" => username, "password" => password}} %{"user" => %{"username" => username, "password" => password}}
) do ) do
case Auth.authenticate_user(username, password) do case Auth.authenticate_user(username, password) do
{:ok, _user} -> {:ok, user} ->
conn conn
|> Guardian.Plug.sign_in(user)
|> put_flash(:info, "You are signed in") |> put_flash(:info, "You are signed in")
|> redirect(to: game_path(conn, :index)) |> redirect(to: game_path(conn, :index))
{:error, _error} -> {:error, _error} ->
@ -25,4 +27,11 @@ defmodule ChessWeb.SessionController do
|> render("new.html", changeset: changeset) |> render("new.html", changeset: changeset)
end end
end end
def delete(conn, _params) do
conn
|> Guardian.Plug.sign_out()
|> put_flash(:info, "You are logged out")
|> redirect(to: page_path(conn, :index))
end
end end

View File

@ -5,21 +5,37 @@ defmodule ChessWeb.Router do
plug :accepts, ["html"] plug :accepts, ["html"]
plug :fetch_session plug :fetch_session
plug :fetch_flash plug :fetch_flash
# plug :protect_from_forgery plug :protect_from_forgery
plug :put_secure_browser_headers plug :put_secure_browser_headers
end end
pipeline :auth do
plug Chess.Auth.Pipeline
end
pipeline :ensure_auth do
plug Guardian.Plug.EnsureAuthenticated
end
pipeline :api do pipeline :api do
plug :accepts, ["json"] plug :accepts, ["json"]
end end
scope "/", ChessWeb do scope "/", ChessWeb do
pipe_through :browser # Use the default browser stack pipe_through [:browser, :auth] # Use the default browser stack
get "/", PageController, :index get "/", PageController, :index
resources "/games", GameController, only: [:index, :create, :show, :delete] resources "/session", SessionController,
resources "/session", SessionController, only: [:new, :create], singleton: true only: [:new, :create, :delete], singleton: true
resources "/registration", RegistrationController, only: [:new, :create], singleton: true resources "/registration", RegistrationController,
only: [:new, :create], singleton: true
end
scope "/", ChessWeb do
pipe_through [:browser, :auth, :ensure_auth]
resources "/games", GameController,
only: [:index, :create, :show, :delete]
end end
# Other scopes may use custom stacks. # Other scopes may use custom stacks.

View File

@ -15,9 +15,15 @@
<div class="container"> <div class="container">
<header role="banner"> <header role="banner">
<nav role="user"> <nav role="user">
<%= if current_user = Guardian.Plug.current_resource(@conn) do %>
<%= current_user.username %>
|
<%= link("Log out", to: session_path(@conn, :delete), method: :delete) %>
<% else %>
<%= link("Register", to: registration_path(@conn, :new)) %> <%= link("Register", to: registration_path(@conn, :new)) %>
| |
<%= link("Log in", to: session_path(@conn, :new)) %> <%= link("Log in", to: session_path(@conn, :new)) %>
<% end %>
</nav> </nav>
<h1>Chess</h1> <h1>Chess</h1>
</header> </header>

View File

@ -2,26 +2,32 @@ defmodule Chess.GameControllerTest do
use ChessWeb.ConnCase use ChessWeb.ConnCase
alias Chess.Store.Game alias Chess.Store.Game
alias Chess.Auth.User
alias Chess.Auth.Guardian
@valid_attrs %{} @valid_attrs %{}
test "lists all entries on index", %{conn: conn} do test "lists all entries on index", %{conn: conn} do
conn = login(conn)
conn = get conn, game_path(conn, :index) conn = get conn, game_path(conn, :index)
assert html_response(conn, 200) =~ "Listing games" assert html_response(conn, 200) =~ "Listing games"
end end
test "creates resource and redirects when data is valid", %{conn: conn} do test "creates resource and redirects when data is valid", %{conn: conn} do
conn = login(conn)
conn = post conn, game_path(conn, :create), game: @valid_attrs conn = post conn, game_path(conn, :create), game: @valid_attrs
game = Repo.one(Game) game = Repo.one(Game)
assert redirected_to(conn) == game_path(conn, :show, game) assert redirected_to(conn) == game_path(conn, :show, game)
end end
test "shows chosen resource", %{conn: conn} do test "shows chosen resource", %{conn: conn} do
conn = login(conn)
game = Repo.insert! %Game{} game = Repo.insert! %Game{}
conn = get conn, game_path(conn, :show, game) conn = get conn, game_path(conn, :show, game)
assert html_response(conn, 200) =~ "<div id=\"app\" data-game-id=\"#{game.id}\">" assert html_response(conn, 200) =~ "<div id=\"app\" data-game-id=\"#{game.id}\">"
end end
test "renders page not found when id is nonexistent", %{conn: conn} do test "renders page not found when id is nonexistent", %{conn: conn} do
conn = login(conn)
assert_error_sent 404, fn -> assert_error_sent 404, fn ->
get conn, game_path(conn, :show, -1) get conn, game_path(conn, :show, -1)
end end
@ -29,8 +35,22 @@ defmodule Chess.GameControllerTest do
test "deletes chosen resource", %{conn: conn} do test "deletes chosen resource", %{conn: conn} do
game = Repo.insert! %Game{} game = Repo.insert! %Game{}
conn = login(conn)
conn = delete conn, game_path(conn, :delete, game) conn = delete conn, game_path(conn, :delete, game)
assert redirected_to(conn) == game_path(conn, :index) assert redirected_to(conn) == game_path(conn, :index)
refute Repo.get(Game, game.id) refute Repo.get(Game, game.id)
end end
defp login(conn) do
user = create_user()
conn |> Guardian.Plug.sign_in(user)
end
defp create_user() do
changeset = User.changeset(
%User{},
%{username: "link@hyrule.kingdom", password: "ilovezelda"}
)
Repo.insert!(changeset)
end
end end

View File

@ -1,7 +1,9 @@
defmodule Chess.GamesTest do defmodule Chess.GamesTest do
use ChessWeb.FeatureCase use ChessWeb.FeatureCase
import Wallaby.Query, only: [css: 1, css: 2, button: 1] import Wallaby.Query, only: [css: 1, css: 2, button: 1, text_field: 1]
alias Chess.Auth.User
test "visit homepage", %{session: session} do test "visit homepage", %{session: session} do
session session
@ -11,12 +13,14 @@ defmodule Chess.GamesTest do
test "can create a new game", %{session: session} do test "can create a new game", %{session: session} do
session session
|> login()
|> create_game() |> create_game()
|> assert_has(css(".board")) |> assert_has(css(".board"))
end end
test "can move a piece", %{session: session} do test "can move a piece", %{session: session} do
session session
|> login()
|> create_game() |> create_game()
session session
@ -30,6 +34,24 @@ defmodule Chess.GamesTest do
|> assert_has(square_containing("f4-r3", "white.pawn")) |> assert_has(square_containing("f4-r3", "white.pawn"))
end end
defp login(session) do
create_user()
session
|> visit("/session/new")
|> fill_in(text_field("Username"), with: "link@hyrule.kingdom")
|> fill_in(text_field("Password"), with: "ilovezelda")
|> click(button("Sign in"))
end
defp create_user() do
changeset = User.changeset(
%User{},
%{username: "link@hyrule.kingdom", password: "ilovezelda"}
)
Repo.insert!(changeset)
end
defp create_game(session) do defp create_game(session) do
session session
|> visit("/games") |> visit("/games")

View File

@ -42,6 +42,25 @@ defmodule Chess.SessionTest do
|> click(button("Sign in")) |> click(button("Sign in"))
assert session |> has_text?("You are signed in") assert session |> has_text?("You are signed in")
assert session |> has_text?("Listing games")
assert session |> has_text?("link@hyrule.kingdom")
end
test "user can sign out", %{session: session} do
create_user()
session
|> visit("/")
|> click(link("Log in"))
|> fill_in(text_field("Username"), with: "link@hyrule.kingdom")
|> fill_in(text_field("Password"), with: "ilovezelda")
|> click(button("Sign in"))
session
|> visit("/")
|> click(link("Log out"))
assert session |> has_text?("You are logged out")
end end
defp create_user() do defp create_user() do