Browse Source

Updating to the new player ID API

Kirk Trombley 5 years ago
parent
commit
c5a0a7d09f
6 changed files with 54 additions and 43 deletions
  1. 13 11
      README.md
  2. 9 7
      client/src/domain/apiMethods.js
  3. 10 8
      client/src/domain/gameStore.js
  4. 4 4
      client/src/hooks/useRoundInfo.jsx
  5. 1 1
      server/app.py
  6. 17 12
      server/game_api.py

+ 13 - 11
README.md

@@ -11,7 +11,7 @@
 ```
 API Endpoints
 GET /
-    Returns {
+    Returns 200 and {
         "version": string,
         "status": string
     }
@@ -19,11 +19,11 @@ PUT /game
     Accepts {
         "timer": number
     }
-    Returns {
+    Returns 200 and {
         "gameId": string
     }
 GET /game/{ID}
-    Returns {
+    Returns 404 vs 200 and {
         "gameId": string,
         "timer": number,
         "coords": {
@@ -48,11 +48,15 @@ GET /game/{ID}
         ]
     }
 POST /game/{ID}/join
-    Header Authorization: Name string
-    Returns 201 vs 401
+    Accepts {
+        "playerName": string
+    }
+    Returns (401, 404, 409) vs 201 and {
+        "playerId": string
+    }
 GET /game/{ID}/current
-    Header Authorization: Name string
-    Returns {
+    Header Authorization: Player string
+    Returns (400, 404) vs 200 and {
         "currentRound": string || null,
         "coord": {
             "lat": number,
@@ -61,14 +65,14 @@ GET /game/{ID}/current
         "timer": number
     }
 POST /game/{ID}/guesses/{round}
-    Header Authorization: Name string
+    Header Authorization: Player string
     Accepts {
         "lat": number,
         "lng": number
     } OR {
         "timeout": boolean
     }
-    Returns 400 vs 201 and {
+    Returns (400, 401, 404, 409) vs 201 and {
         "score": number,
         "totalScore": number,
         "distance": number || null,
@@ -83,8 +87,6 @@ POST /game/{ID}/guesses/{round}
 - Update UI to create game without providing a name
 - Genericize number of rounds in API
 - Change UI to allow round number setting
-- Change join API to take player name as body argument and return ID
-- Use player ID "auth" in API instead of name
 - Error handling in UI
 - Re-join a game you did not finish
 - Optimize docker file or set up compose structure

+ 9 - 7
client/src/domain/apiMethods.js

@@ -1,4 +1,4 @@
-const API_BASE = "https://kirkleon.ddns.net/terrassumptions/api";
+const API_BASE = "http://localhost:5000";
 
 export const getStatus = async () => {
     try {
@@ -35,22 +35,24 @@ export const gameInfo = async (gameId) => {
     return await res.json();
 }
 
-export const joinGame = async (gameId, name) => {
+export const joinGame = async (gameId, playerName) => {
     const res = await fetch(`${API_BASE}/game/${gameId}/join`, {
         method: "POST",
         headers: {
-            "Authorization": `Name ${name}`
+            "Content-Type": "application/json",
         },
+        body: JSON.stringify({ playerName }),
     });
     if (!res.ok) {
         throw Error(res.statusText);
     }
+    return await res.json();
 }
 
-export const getCurrentRound = async (gameId, name) => {
+export const getCurrentRound = async (gameId, playerId) => {
     const res = await fetch(`${API_BASE}/game/${gameId}/current`, {
         headers: {
-            "Authorization": `Name ${name}`
+            "Authorization": `Player ${playerId}`
         },
     });
     if (!res.ok) {
@@ -59,11 +61,11 @@ export const getCurrentRound = async (gameId, name) => {
     return await res.json();
 }
 
-export const sendGuess = async (gameId, name, round, point) => {
+export const sendGuess = async (gameId, playerId, round, point) => {
     const res = await fetch(`${API_BASE}/game/${gameId}/guesses/${round}`, {
         method: "POST",
         headers: {
-            "Authorization": `Name ${name}`,
+            "Authorization": `Player ${playerId}`,
             "Content-Type": "application/json",
         },
         body: JSON.stringify(point),

+ 10 - 8
client/src/domain/gameStore.js

@@ -8,6 +8,7 @@ export const [
     usePlayerName,
     useLastRound,
     useGameJoined,
+    usePlayerId,
     useGameState,
   },
   dispatch,
@@ -24,6 +25,7 @@ export const [
     totalScore: -1,
   },
   gameJoined: false,
+  playerId: null,
   gameState: PRE_GAME,
 }, {
   setPlayerName: ([set], playerName) => set({ playerName }),
@@ -31,25 +33,24 @@ export const [
   createGame: async ([set, get], timer) => {
     const gameId = await createGame(timer);
     const name = get.playerName();
-    await joinGame(gameId, name);
-    set({ gameId, gameJoined: true, gameState: PRE_ROUND });
+    const { playerId } = await joinGame(gameId, name);
+    set({ gameId, gameJoined: true, playerId, gameState: PRE_ROUND });
   },
   joinGame: async ([set, get]) => {
     const gameId = get.gameId();
     const name = get.playerName();
-    await joinGame(gameId, name);
-    set({ gameJoined: true });
+    const { playerId } = await joinGame(gameId, name);
+    set({ gameJoined: true, playerId });
   },
   startRound: ([set]) => set({ gameState: IN_ROUND }),
   submitGuess: async ([set, get], selectedPoint, roundNum, targetPoint) => {
-    const gameId = get.gameId();
-    const name = get.playerName();
     const { score, totalScore } = await sendGuess(
-      gameId,
-      name,
+      get.gameId(),
+      get.playerId(),
       roundNum,
       selectedPoint || { timeout: true }
     );
+    console.log(score + " " + totalScore);
     set({
       lastRound: {
         roundNum,
@@ -66,6 +67,7 @@ export const [
   }),
   resetGame: ([set]) => set({
     gameJoined: false,
+    playerId: null,
     gameState: PRE_GAME,
   }),
 });

+ 4 - 4
client/src/hooks/useRoundInfo.jsx

@@ -1,16 +1,16 @@
 import { useState, useEffect } from 'react';
 import { getCurrentRound } from "../domain/apiMethods";
-import { useGameId, usePlayerName } from '../domain/gameStore';
+import { useGameId, usePlayerId } from '../domain/gameStore';
 
 export default () => {
   const gameId = useGameId();
-  const playerName = usePlayerName();
+  const playerId = usePlayerId();
   const [finished, setFinished] = useState(false);
   const [roundInfo, setRoundInfo] = useState({currentRound: null, targetPoint: null, roundSeconds: null});
 
   useEffect(() => {
     const setup = async () => {
-      const { currentRound, coord, timer } = await getCurrentRound(gameId, playerName);
+      const { currentRound, coord, timer } = await getCurrentRound(gameId, playerId);
       if (currentRound) {
         setRoundInfo({ currentRound, targetPoint: coord, roundSeconds: timer });
       } else {
@@ -18,7 +18,7 @@ export default () => {
       }
     }
     setup();
-  }, [gameId, playerName]);
+  }, [gameId, playerId]);
 
   return [finished, roundInfo];
 }

+ 1 - 1
server/app.py

@@ -30,7 +30,7 @@ def version():
     """
     Return the version of the API and a status message, "healthy"
     """
-    return jsonify({"version": "2", "status": "healthy"})
+    return jsonify({"version": "3", "status": "healthy"})
 
 
 if __name__ == "__main__":

+ 17 - 12
server/game_api.py

@@ -6,13 +6,6 @@ import lib
 game = Blueprint("game", __name__)
 
 
-def require_name():
-    name = request.headers.get("Authorization", type=str)
-    if name is None:
-        abort(401)
-    return name.split(maxsplit=1)[-1]
-
-
 def require_game(game_id):
     g = db.Game.query.get(game_id)
     if g is None:
@@ -21,8 +14,14 @@ def require_game(game_id):
 
 
 def require_player(game_id):
-    name = require_name()
-    player = db.Player.query.filter(db.Player.game_id == game_id, db.Player.player_name == name).first()
+    auth = request.headers.get("Authorization", type=str)
+    if auth is None:
+        abort(401)
+    try:
+        pid = int(auth.split(maxsplit=1)[-1])
+    except ValueError:
+        abort(401)
+    player = db.Player.query.get(pid)
     if player is None:
         abort(404)
     return player
@@ -47,14 +46,19 @@ def game_settings(game_id):
 
 @game.route("/<game_id>/join", methods=["POST"])
 def join(game_id):
-    name = require_name()
+    name = request.json.get("playerName", None)
+    if name is None:
+        abort(400)
+
     g = require_game(game_id)
 
     if db.Player.query.filter(db.Player.game_id == game_id, db.Player.player_name == name).first() is not None:
         abort(409)
 
-    g.join(name)
-    return "", 201
+    p = g.join(name)
+    return jsonify({
+        "playerId": str(p.player_id)
+    }), 201
 
 
 @game.route("/<game_id>/current")
@@ -66,6 +70,7 @@ def current_round(game_id):
         coord = None
     else:
         lookup = db.Coordinate.query.get((game_id, cur_rnd))
+        cur_rnd = str(cur_rnd)
         if lookup is None:
             coord = None
         else: