diff --git a/.gitignore b/.gitignore index 38193138..7b37986f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.swp *.swo +priv_notes.txt diff --git a/backend/.iex.exs b/backend/.iex.exs index 2e0050a7..8c574a95 100644 --- a/backend/.iex.exs +++ b/backend/.iex.exs @@ -1,4 +1,5 @@ alias Spades.Rooms +alias Spades.Rooms.Room alias SpadesGame.{ Card, diff --git a/backend/lib/spades/rooms.ex b/backend/lib/spades/rooms.ex index 2287923f..33b95bfe 100644 --- a/backend/lib/spades/rooms.ex +++ b/backend/lib/spades/rooms.ex @@ -38,6 +38,11 @@ defmodule Spades.Rooms do """ def get_room!(id), do: Repo.get!(Room, id) + def get_room_by_name(name) do + Room + |> Repo.get_by(name: name) + end + @doc """ Creates a room. diff --git a/backend/lib/spades_game/game_options.ex b/backend/lib/spades_game/game_options.ex index c0aa0d41..9aac21c5 100644 --- a/backend/lib/spades_game/game_options.ex +++ b/backend/lib/spades_game/game_options.ex @@ -10,6 +10,7 @@ defmodule SpadesGame.GameOptions do hardcoded_cards: boolean } + @derive {Jason.Encoder, only: [:hardcoded_cards]} schema "gameuioptions" do field(:hardcoded_cards, :boolean) end diff --git a/backend/lib/spades_game/game_registry.ex b/backend/lib/spades_game/game_registry.ex new file mode 100644 index 00000000..efa6dd18 --- /dev/null +++ b/backend/lib/spades_game/game_registry.ex @@ -0,0 +1,40 @@ +defmodule SpadesGame.GameRegistry do + @moduledoc """ + Keeps track of games. + """ + require Logger + alias SpadesGame.{GameUI} + alias Spades.Rooms + alias Spades.Rooms.Room + + def add(_game_name, %GameUI{} = gameui) do + gameui + |> to_room_param() + |> Rooms.create_room() + end + + def update(game_name, %GameUI{} = gameui) do + room = Rooms.get_room_by_name(game_name) + + case room do + %Room{} -> Rooms.update_room(room, to_room_param(gameui)) + _ -> nil + end + end + + def remove(game_name) do + room = Rooms.get_room_by_name(game_name) + + case room do + %Room{} -> Rooms.delete_room(room) + _ -> nil + end + end + + defp to_room_param(%GameUI{} = gameui) do + # created_at: DateTime.t() + %{ + name: gameui.game_name + } + end +end diff --git a/backend/lib/spades_game/ui/game_ui_server.ex b/backend/lib/spades_game/ui/game_ui_server.ex index 6efe366f..c79f9322 100644 --- a/backend/lib/spades_game/ui/game_ui_server.ex +++ b/backend/lib/spades_game/ui/game_ui_server.ex @@ -6,7 +6,7 @@ defmodule SpadesGame.GameUIServer do @timeout :timer.hours(1) require Logger - alias SpadesGame.{GameOptions, GameUI} + alias SpadesGame.{GameOptions, GameUI, GameRegistry, GameSupervisor} @doc """ start_link/2: Generates a new game server under a provided name. @@ -49,7 +49,7 @@ defmodule SpadesGame.GameUIServer do def init({game_name, options = %GameOptions{}}) do gameui = GameUI.new(game_name, options) - # GameRegistry.add(gameui.game_name, game_info(gameui)) + GameRegistry.add(gameui.game_name, gameui) {:ok, gameui, timeout(gameui)} end @@ -59,6 +59,9 @@ defmodule SpadesGame.GameUIServer do {:reply, new_state, new_state, timeout(new_state)} end + # In some state updating function: + # GameRegistry.update(new_gameui.game_name, gameui) + # timeout/1 # Given the current state of the game, what should the # GenServer timeout be? (Games with winners expire quickly) @@ -73,15 +76,15 @@ defmodule SpadesGame.GameUIServer do def terminate({:shutdown, :timeout}, state) do Logger.info("Terminate (Timeout) running for #{state.game_name}") - # GameSupervisor.stop_game(state.game_name) - # GameRegistry.remove(state.game_name) + GameSupervisor.stop_game(state.game_name) + GameRegistry.remove(state.game_name) :ok end # Do I need to trap exits here? def terminate(_reason, state) do Logger.info("Terminate (Non Timeout) running for #{state.game_name}") - # GameRegistry.remove(state.game_name) + GameRegistry.remove(state.game_name) :ok end end diff --git a/backend/lib/spades_web/controllers/api/v1/game_controller.ex b/backend/lib/spades_web/controllers/api/v1/game_controller.ex new file mode 100644 index 00000000..db4f5259 --- /dev/null +++ b/backend/lib/spades_web/controllers/api/v1/game_controller.ex @@ -0,0 +1,27 @@ +defmodule SpadesWeb.API.V1.GameController do + use SpadesWeb, :controller + + require Logger + + alias Spades.Rooms + alias Spades.Rooms.Room + alias SpadesUtil.{NameGenerator} + alias SpadesGame.{GameOptions, GameUISupervisor} + + def create(conn, _params) do + game_name = NameGenerator.generate() + options = %GameOptions{} + + with {:ok, _pid} <- GameUISupervisor.start_game(game_name, options), + %Room{} = room <- Rooms.get_room_by_name(game_name) do + conn + |> put_status(:created) + |> json(%{success: %{message: "Created game", room: room}}) + else + _ -> + conn + |> put_status(500) + |> json(%{error: %{status: 500, message: "Unable to create game"}}) + end + end +end diff --git a/backend/lib/spades_web/controllers/room_controller.ex b/backend/lib/spades_web/controllers/room_controller.ex index 7f0720fd..5b31840c 100644 --- a/backend/lib/spades_web/controllers/room_controller.ex +++ b/backend/lib/spades_web/controllers/room_controller.ex @@ -3,8 +3,8 @@ defmodule SpadesWeb.RoomController do alias Spades.Rooms alias Spades.Rooms.Room - alias SpadesUtil.{NameGenerator, Slugify} - alias SpadesGame.GameSupervisor + # alias SpadesUtil.{NameGenerator, Slugify} + # alias SpadesGame.GameSupervisor action_fallback SpadesWeb.FallbackController @@ -13,22 +13,8 @@ defmodule SpadesWeb.RoomController do render(conn, "index.json", rooms: rooms) end - def create(conn, %{"room" => room_params}) do - game_name = NameGenerator.generate() - - room_params = - room_params - |> Map.put("name", game_name) - |> Map.put("slug", Slugify.slugify(game_name)) - - with {:ok, _pid} <- GameSupervisor.start_game(game_name), - {:ok, %Room{} = room} <- Rooms.create_room(room_params) do - conn - |> put_status(:created) - |> put_resp_header("location", Routes.room_path(conn, :show, room)) - |> render("show.json", room: room) - end - end + # Create: Removed, users no longer able to create rooms by API + # Possibly this entire controller should be removed def show(conn, %{"id" => id}) do room = Rooms.get_room!(id) diff --git a/backend/lib/spades_web/router.ex b/backend/lib/spades_web/router.ex index c17b486c..cd3f4d19 100644 --- a/backend/lib/spades_web/router.ex +++ b/backend/lib/spades_web/router.ex @@ -47,6 +47,7 @@ defmodule SpadesWeb.Router do # Testing Junk get "/authtest", JunkController, :authtest + post "/games", GameController, :create end scope "/api/v1", SpadesWeb.API.V1, as: :api_v1 do diff --git a/backend/test/spades_game/ui/game_ui_server_test.exs b/backend/test/spades_game/ui/game_ui_server_test.exs index 857d6492..488db908 100644 --- a/backend/test/spades_game/ui/game_ui_server_test.exs +++ b/backend/test/spades_game/ui/game_ui_server_test.exs @@ -1,5 +1,6 @@ defmodule GameUiServerTest do - use ExUnit.Case, async: true + use ExUnit.Case + use Spades.DataCase alias SpadesGame.{Card, GameOptions, GameUIServer, GameUI, Game} describe "start_link/2" do diff --git a/backend/test/spades_game/ui/game_ui_supervisor_test.exs b/backend/test/spades_game/ui/game_ui_supervisor_test.exs index 8d6f4e07..b2dbe3fe 100644 --- a/backend/test/spades_game/ui/game_ui_supervisor_test.exs +++ b/backend/test/spades_game/ui/game_ui_supervisor_test.exs @@ -1,5 +1,6 @@ defmodule GameUiSupervisorTest do - use ExUnit.Case, async: true + use ExUnit.Case + use Spades.DataCase doctest SpadesGame.GameUISupervisor alias SpadesGame.{GameUISupervisor, GameUIServer, GameOptions} diff --git a/backend/test/spades_web/controllers/room_controller_test.exs b/backend/test/spades_web/controllers/room_controller_test.exs index 0b486827..47ee8d2c 100644 --- a/backend/test/spades_web/controllers/room_controller_test.exs +++ b/backend/test/spades_web/controllers/room_controller_test.exs @@ -28,39 +28,6 @@ defmodule SpadesWeb.RoomControllerTest do end end - describe "create room" do - test "renders room when data is valid", %{conn: conn} do - ############# - # a = Routes.room_path(conn, :create) - # a |> IO.inspect(label: "path") - - # @create_attrs - # |> IO.inspect(label: "attrs") - - ############# - - conn = post(conn, Routes.room_path(conn, :create), room: @create_attrs) - assert %{"id" => id} = json_response(conn, 201)["data"] - - conn = get(conn, Routes.room_path(conn, :show, id)) - - assert %{ - "id" => id - # "name" => "some name" - # Name is automatically generated. - } = json_response(conn, 200)["data"] - end - - ## Since names are automatically generated, and - ## they're the only field right now, we can't - ## generate invalid data. - - # test "renders errors when data is invalid", %{conn: conn} do - # conn = post(conn, Routes.room_path(conn, :create), room: @invalid_attrs) - # assert json_response(conn, 422)["errors"] != %{} - # end - end - describe "update room" do setup [:create_room] diff --git a/frontend/src/features/lobby/CreateRoomModal.tsx b/frontend/src/features/lobby/CreateRoomModal.tsx index bdbbb8f7..7a7841ab 100644 --- a/frontend/src/features/lobby/CreateRoomModal.tsx +++ b/frontend/src/features/lobby/CreateRoomModal.tsx @@ -1,12 +1,9 @@ import React, { useState } from "react"; import { Redirect } from "react-router"; import axios from "axios"; -//import cx from "classnames"; import ReactModal from "react-modal"; import Button from "../../components/basic/Button"; -import { getRandomInt } from "../../util/util"; - interface Props { isOpen: boolean; closeModal: () => void; @@ -20,17 +17,16 @@ export const CreateRoomModal: React.FC = ({ isOpen, closeModal }) => { const [roomSlugCreated, setRoomSlugCreated] = useState(null); const createRoom = async () => { - const name = "Room Name " + getRandomInt(1, 10000); - const data = { room: { name } }; + const data = { room: { name: "" } }; setIsLoading(true); setIsError(false); try { - const res = await axios.post("/be/api/rooms", data); + const res = await axios.post("/be/api/v1/games", data); setIsLoading(false); if (res.status !== 201) { throw new Error("Room not created"); } - const room = res.data.data; + const room = res.data.success.room; setRoomSlugCreated(room.slug); } catch (err) { setIsLoading(false); diff --git a/frontend/src/features/lobby/Lobby.tsx b/frontend/src/features/lobby/Lobby.tsx index f1841e1d..6413c1bb 100644 --- a/frontend/src/features/lobby/Lobby.tsx +++ b/frontend/src/features/lobby/Lobby.tsx @@ -57,12 +57,14 @@ export const Lobby: React.FC = () => { {roomItems && ( - - - - - - + + + + + + + + {roomItems}
idnamewestnortheastsouth
idnamewestnortheastsouth