From d8b8659bef624e5f28574b0a47083c8dba63abc7 Mon Sep 17 00:00:00 2001 From: Armando Roque <43384970+aroquev00@users.noreply.github.com> Date: Wed, 9 Sep 2020 19:10:03 -0500 Subject: [PATCH] Join link (#145) * Fix broken display of answers history * Add click to copy link * Register user when loading play page * Document animal alias process --- .../com/google/sps/daos/DatabaseUserDao.java | 22 +++++++--- .../java/com/google/sps/daos/UserDao.java | 6 ++- .../sps/servlets/JoinGameInstanceServlet.java | 19 ++++++++- src/main/webapp/student/scripts/enter-game.js | 16 +------- src/main/webapp/student/scripts/play-game.js | 40 ++++++++++++++----- .../controlGameInstance.css | 15 +++++++ .../controlGameInstance.html | 1 + .../controlGameInstance.js | 10 +++-- 8 files changed, 95 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/google/sps/daos/DatabaseUserDao.java b/src/main/java/com/google/sps/daos/DatabaseUserDao.java index 6221ca0..4bb0ae4 100644 --- a/src/main/java/com/google/sps/daos/DatabaseUserDao.java +++ b/src/main/java/com/google/sps/daos/DatabaseUserDao.java @@ -11,6 +11,7 @@ import com.google.cloud.firestore.DocumentReference; import com.google.cloud.firestore.DocumentSnapshot; import com.google.cloud.firestore.Firestore; +import com.google.cloud.firestore.WriteResult; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseAuthException; import com.google.firebase.auth.FirebaseToken; @@ -116,8 +117,10 @@ public void createIfNotExists(String idToken) { } + // Register a user in a gameInstance and return its newly assigned animal alias + // If user is already registered, just return the animal alias that was already assigned before @Override - public void joinGameInstance(String idToken, String gameInstanceId) { + public String joinGameInstance(String idToken, String gameInstanceId) { FirebaseToken decodedToken = null; String userId = null; @@ -136,12 +139,17 @@ public void joinGameInstance(String idToken, String gameInstanceId) { ApiFuture UserInGameInstanceFuture = userInGameInstanceDocRef.get(); + String animal = ""; + try { DocumentSnapshot document = UserInGameInstanceFuture.get(); if (!document.exists()) { int numberOfStudent = addOneToMembersCounter(gameInstanceDocRef); - registerUserInGameInstance(userInGameInstanceDocRef, userId, getAnimal(numberOfStudent)); - } + animal = getAnimal(numberOfStudent); + registerUserInGameInstance(userInGameInstanceDocRef, userId, animal); + } else { + animal = (String) document.getData().get("alias"); + } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -153,6 +161,8 @@ public void joinGameInstance(String idToken, String gameInstanceId) { // Add the active GameInstance to the User's entry in "Users" collection firestoreDb.collection("users").document(userId).update("activeGameInstanceId", gameInstanceId); + // Return the animal that was assigned to the user + return animal; } @@ -165,7 +175,8 @@ private void initUser(String userId) { } - private void registerUserInGameInstance(DocumentReference userInGameInstanceDocRef, String userId, String animal) { + private void registerUserInGameInstance(DocumentReference userInGameInstanceDocRef, String userId, String animal) + throws InterruptedException, ExecutionException { Map docData = new HashMap<>(); docData.put("points", 0); docData.put("numberAnswered", 0); @@ -173,7 +184,8 @@ private void registerUserInGameInstance(DocumentReference userInGameInstanceDocR docData.put("numberWrong", 0); docData.put("alias", animal); - userInGameInstanceDocRef.set(docData); + ApiFuture future = userInGameInstanceDocRef.set(docData); + future.get(); } private int addOneToMembersCounter(DocumentReference gameInstanceDocRef) diff --git a/src/main/java/com/google/sps/daos/UserDao.java b/src/main/java/com/google/sps/daos/UserDao.java index 87b400d..d086cc2 100644 --- a/src/main/java/com/google/sps/daos/UserDao.java +++ b/src/main/java/com/google/sps/daos/UserDao.java @@ -1,7 +1,11 @@ package com.google.sps.daos; public interface UserDao { - public void joinGameInstance(String idToken, String gameInstanceId); + + // Register a user in a gameInstance and return its newly assigned animal alias + // If user is already registered, just return the animal alias that was already assigned before + public String joinGameInstance(String idToken, String gameInstanceId); + public void createIfNotExists(String idToken); } diff --git a/src/main/java/com/google/sps/servlets/JoinGameInstanceServlet.java b/src/main/java/com/google/sps/servlets/JoinGameInstanceServlet.java index b79e461..9a695dc 100644 --- a/src/main/java/com/google/sps/servlets/JoinGameInstanceServlet.java +++ b/src/main/java/com/google/sps/servlets/JoinGameInstanceServlet.java @@ -51,7 +51,24 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr UserDao dao = (UserDao) this.getServletContext().getAttribute("userDao"); - dao.joinGameInstance(jsonObj.get("idToken").getAsString(), jsonObj.get("gameInstanceId").getAsString()); + // Register a user in a gameInstance and get its newly assigned animal alias to return it to the client + // If user is already registered, just get the animal alias that was already assigned before + String animal = dao.joinGameInstance(jsonObj.get("idToken").getAsString(), jsonObj.get("gameInstanceId").getAsString()); + + // Convert the anima alias to JSON + String json = convertToJson(animal); + // Send the JSON as response + response.setContentType("application/json;"); + response.getWriter().println(json); + } + + /** + * Convert to JSON using Gson + */ + private String convertToJson(String newGameInstanceId) { + Gson gson = new Gson(); + String json = gson.toJson(newGameInstanceId); + return json; } } diff --git a/src/main/webapp/student/scripts/enter-game.js b/src/main/webapp/student/scripts/enter-game.js index 7f7d36e..fc3de13 100644 --- a/src/main/webapp/student/scripts/enter-game.js +++ b/src/main/webapp/student/scripts/enter-game.js @@ -50,21 +50,7 @@ function verifyGameInstanceExists(gameInstanceId) { // Send the request to join the Game Instance function joinGameInstance(gameInstanceId) { - firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) { - fetch('/joinGameInstance', { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify({idToken: idToken, gameInstanceId: gameInstanceId}) - }).then(() => { - window.location.href = "/student/play-game.html?gameInstanceId=" + gameInstanceId; - }); - }).catch(function(error) { - // Handle error - console.log("Please log in"); - }); + window.location.href = "/student/play-game.html?gameInstanceId=" + gameInstanceId; } // Display a message saying that GameInstanceId is not valid diff --git a/src/main/webapp/student/scripts/play-game.js b/src/main/webapp/student/scripts/play-game.js index 319f14c..05de05d 100644 --- a/src/main/webapp/student/scripts/play-game.js +++ b/src/main/webapp/student/scripts/play-game.js @@ -20,7 +20,7 @@ let active = false; let currentQuestionId = null; let selectedAnswerId = ""; let currentQuestionActive = false; -let gameInstanceId = getGameInstanceIdFromQueryParams(); +let gameInstanceId = null; const resultObject = document.getElementById("result"); let submited = false; let isFinished = false; @@ -49,25 +49,47 @@ function authStateObserver(user) { async function loadGamePanel(user) { // Get the Game Instance's ID in which the user is participating + gameInstanceId = getGameInstanceIdFromQueryParams(); + if (gameInstanceId == null) { gameInstanceId = await getActiveGameInstanceId(user); } + // Register and get animal alias from Firestore, or if exists just retrieve animal alias + registerStudentInGameInstance(gameInstanceId); + // Start listening to the GameInstance initGameInstanceListener(gameInstanceId); - - // Get and display the user's id and alias - initStudentAlias(user, gameInstanceId); } -// // Get and display the user's id and alias in the UI -function initStudentAlias(user, gameInstanceId) { - db.collection("gameInstance").doc(gameInstanceId).collection("students").doc(user.uid).get().then(function(doc) { - const userIdDivElement = document.getElementById('userId'); - userIdDivElement.innerText = `You are: ${doc.data().alias}` +// Register and get animal alias from Firestore, or if exists just retrieve assigned animal alias +function registerStudentInGameInstance(gameInstanceId) { + firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) { + fetch('/joinGameInstance', { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({idToken: idToken, gameInstanceId: gameInstanceId}) + }).then((response) => { + response.json().then(animal => { + // Display the user's alias + initStudentAlias(animal); + }); + }); + }).catch(function(error) { + // Handle error + console.log("Please log in"); }); } +// Display the user's alias in the UI +function initStudentAlias(animalAlias) { + const userIdDivElement = document.getElementById('userId'); + userIdDivElement.innerText = `You are: ${animalAlias}` +} + // Gets the gameInstanceId from the query string if there is // If not, it returns null function getGameInstanceIdFromQueryParams() { diff --git a/src/main/webapp/teacher/controlGameInstance/controlGameInstance.css b/src/main/webapp/teacher/controlGameInstance/controlGameInstance.css index 93d0a62..5250935 100644 --- a/src/main/webapp/teacher/controlGameInstance/controlGameInstance.css +++ b/src/main/webapp/teacher/controlGameInstance/controlGameInstance.css @@ -28,3 +28,18 @@ #cardActions { text-align: center; } + +#jsShareGameInstance { + color: red; + cursor: pointer; +} + +#jsShareGameInstance:hover { + color: blue; + cursor: pointer; +} + +#jsShareGameInstance:active { + color: gray; + cursor: pointer; +} diff --git a/src/main/webapp/teacher/controlGameInstance/controlGameInstance.html b/src/main/webapp/teacher/controlGameInstance/controlGameInstance.html index 4cf5325..33b4ab4 100644 --- a/src/main/webapp/teacher/controlGameInstance/controlGameInstance.html +++ b/src/main/webapp/teacher/controlGameInstance/controlGameInstance.html @@ -88,6 +88,7 @@

Game Info

+
diff --git a/src/main/webapp/teacher/controlGameInstance/controlGameInstance.js b/src/main/webapp/teacher/controlGameInstance/controlGameInstance.js index 78362d1..6af39b5 100644 --- a/src/main/webapp/teacher/controlGameInstance/controlGameInstance.js +++ b/src/main/webapp/teacher/controlGameInstance/controlGameInstance.js @@ -148,6 +148,12 @@ function buildActiveGameInstanceUI({ gameInstanceId, gameInstance, game} = {}) { function addGameInstanceIdToUI(gameInstanceId) { const gameInstanceIdElement = document.getElementById("jsGameInstanceId"); gameInstanceIdElement.innerText = "This gameInstance's ID is: " + gameInstanceId; + + const shareGameInstanceElement = document.getElementById('jsShareGameInstance'); + shareGameInstanceElement.innerText = "Share this link with your students for them to join (click to copy to clipboard): " + "https://quizzy-step-2020.uc.r.appspot.com/student/play-game.html?gameInstanceId=" + gameInstanceId; + shareGameInstanceElement.addEventListener('click', () => { + navigator.clipboard.writeText("https://quizzy-step-2020.uc.r.appspot.com/student/play-game.html?gameInstanceId=" + gameInstanceId); + }); } // Adds the Game's details to the UI @@ -479,9 +485,7 @@ function addQuestionAnswerToHistoryUI({ questionId, answerId, answer } = {}) { answerInQuestionStatsDivElement.innerText = answer.title + ' with ' + answer.numberAnswers + ' answers.'; if (answer.correct) { - questionAnswerDivElement.innerText = 'Correctly answered, chose: "' + answer.chosen + '"'; - } else { - questionAnswerDivElement.innerText = 'Incorrect answer, chose: "' + answer.chosen + '"'; + answerInQuestionStatsDivElement.innerText += ' (Correct answer)'; } // Add the answer to its component in the DOM