From c10d2f3e4efed8f11fad749b09e105d329133ff8 Mon Sep 17 00:00:00 2001 From: Khushal Malhotra Date: Fri, 6 Mar 2026 23:38:48 +0530 Subject: [PATCH] feat: redirect players to game page when game ends - Add game_finished?/1 function to Game module - Implement game-end redirect in PlayerLive.Show - Redirect from /games/:game_id/players/:player_id to /games/:game_id - Handle both initial access and real-time game end events - Use push_navigate for seamless LiveView redirects Fixes issue where players could access finished game pages instead of being redirected to game summary. --- copi.owasp.org/lib/copi/cornucopia/game.ex | 4 +++ .../lib/copi_web/live/player_live/show.ex | 31 ++++++++++++++----- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/copi.owasp.org/lib/copi/cornucopia/game.ex b/copi.owasp.org/lib/copi/cornucopia/game.ex index 652eccec2..c532c61a2 100644 --- a/copi.owasp.org/lib/copi/cornucopia/game.ex +++ b/copi.owasp.org/lib/copi/cornucopia/game.ex @@ -62,4 +62,8 @@ defmodule Copi.Cornucopia.Game do Enum.count(players_still_to_play) > 0 end + + def game_finished?(game) do + game.finished_at != nil + end end diff --git a/copi.owasp.org/lib/copi_web/live/player_live/show.ex b/copi.owasp.org/lib/copi_web/live/player_live/show.ex index bc71e3d8d..1b2bef5c3 100644 --- a/copi.owasp.org/lib/copi_web/live/player_live/show.ex +++ b/copi.owasp.org/lib/copi_web/live/player_live/show.ex @@ -16,25 +16,40 @@ defmodule CopiWeb.PlayerLive.Show do end @impl true - def handle_params(%{"id" => player_id}, _, socket) do + def handle_params(%{"id" => player_id, "game_id" => url_game_id}, _, socket) do with {:ok, player} <- Player.find(player_id) do - with {:ok, game} <- Game.find(player.game_id) do - CopiWeb.Endpoint.subscribe(topic(player.game_id)) - {:noreply, socket |> assign(:game, game) |> assign(:player, player)} + # Validate player belongs to URL game + if player.game_id != url_game_id do + {:noreply, redirect(socket, to: "/error")} else - {:error, _reason} -> - {:ok, redirect(socket, to: "/error")} + with {:ok, game} <- Game.find(player.game_id) do + # Check if game is finished and redirect if so + if Game.game_finished?(game) do + {:noreply, push_navigate(socket, to: "/games/#{game.id}")} + else + CopiWeb.Endpoint.subscribe(topic(player.game_id)) + {:noreply, socket |> assign(:game, game) |> assign(:player, player)} + end + else + {:error, _reason} -> + {:noreply, redirect(socket, to: "/error")} + end end else {:error, _reason} -> - {:ok, redirect(socket, to: "/error")} + {:noreply, redirect(socket, to: "/error")} end end @impl true def handle_info(%{topic: _message_topic, event: "game:updated", payload: updated_game}, socket) do with {:ok, updated_player} <- Player.find(socket.assigns.player.id) do - {:noreply, socket |> assign(:game, updated_game) |> assign(:player, updated_player)} + # Check if game is finished and redirect if so + if Game.game_finished?(updated_game) do + {:noreply, push_navigate(socket, to: "/games/#{updated_game.id}")} + else + {:noreply, socket |> assign(:game, updated_game) |> assign(:player, updated_player)} + end else {:error, _reason} -> {:ok, redirect(socket, to: "/error")}