From dd02165083dccea40c0e34b2bd859b0d31206758 Mon Sep 17 00:00:00 2001
From: "alec.schmidt" <alec.schmidt@etu.hesge.ch>
Date: Mon, 12 Jun 2023 18:15:34 +0200
Subject: [PATCH] game can start and show questions/answers

---
 API/db/app.db                                 | Bin 36864 -> 36864 bytes
 API/src/database/Database.ts                  |  28 ++++++--
 API/src/routes/BaseRoutes.ts                  |   4 ++
 API/src/socket.io/ServerIO.ts                 |  68 ++++++++++++++----
 frontend/src/app/app.component.html           |   2 +-
 frontend/src/app/app.component.ts             |   4 ++
 .../src/app/gameroom/gameroom.component.html  |  24 +++++--
 .../src/app/gameroom/gameroom.component.ts    |  28 +++++++-
 .../app/services/authentication.service.ts    |   3 -
 frontend/src/app/services/socket.service.ts   |  49 +++++++++++--
 10 files changed, 178 insertions(+), 32 deletions(-)

diff --git a/API/db/app.db b/API/db/app.db
index a1e13e4fb81d71b67d2b35525e3b901708a8f4f0..0b24d66b013e0f14002ec1b06dd426f5e50d6afd 100644
GIT binary patch
delta 240
zcmZozz|^pSX@WH4^@%dhjMq0NwAyRx@G>#WGZvPn7MEn^=M~FyGBS%ZmKLWL6-)9m
zFfcIjA7bFY%YTU9Z?mF+Gymj3|3Ya=c@_pm<v^$w1ta&vEA!Kf5(_diQzzf`SLb5l
zzr(=)n*R=e@n%JV4F1Vw@yS9A3=DkCii`+N@|$1BODc%5@gHX3|IYu8|0(}X{`35Y
z`7`)4_@g%~3b^o3j_Xgg<<eng5M|^HNi8ms=g?+l5M<==&z9%X0*P{Xq-N&Hvum<4
W@H29l$g*pI8OE~g>L3QEkt_fx{6261

delta 233
zcmZozz|^pSX@WH4#fdV`j2Aa1wAyQG@-i{YGZvPn7MEn^=M~FxGBS%ZmKLWL6-)9m
zFfcIk-(}#x%b&vUw^>oZnSXMif8peF@!SG=3OR{+$*DyOrFjY|MVV=n@A|8AG4j7=
z;D60u%U`@%Q6PhVa#?(`5W2z=h0U+yB^AV&`JXcIf9HS4|CB!i4x=|K3b^o3j_Xgg
zP0UNrNmWQmRY)pIEG$h-PZefhV9*w1<ghdmVqjoU6lP@CWM$xI<S>zC*8nq&W!cq1
I3{E3i0EA&bo&W#<

diff --git a/API/src/database/Database.ts b/API/src/database/Database.ts
index e7d0f9a..a831a01 100644
--- a/API/src/database/Database.ts
+++ b/API/src/database/Database.ts
@@ -130,10 +130,17 @@ class DBHandler {
     }
 
     async getQuestions(req:express.Request, res:express.Response) {
-        const query = "SELECT * FROM questions";
-        const query_answers = "SELECT * FROM answer";
+        const id = req.params.id;
+        
+        if (id === undefined) {
+            var query = "SELECT * FROM questions";
+            var questions = await asyncdb.all(query);
+        }
+        else {
+            query = "SELECT * FROM questions WHERE id =" + id;
+            questions = await asyncdb.get(query);
+        }
         
-        let questions = await asyncdb.all(query);
         res.status(StatusCodes.OK).json(questions)
     }
 
@@ -143,7 +150,6 @@ class DBHandler {
                         SET question='"+ a.question +"', category='"+ a.category +"' \
                         WHERE id=" + req.params.id;
         
-        
         asyncdb.all(request)
         .then(() => res.status(StatusCodes.OK).end())
         .catch(e => console.log(e));
@@ -218,6 +224,20 @@ class DBHandler {
         .catch(e => console.log(e));
     }
 
+    async getQuestionsForGame() {
+        const query = "SELECT * FROM questions ORDER BY RANDOM() LIMIT 10;";
+        let questions = await asyncdb.all(query);
+        return questions;
+    }
+
+    async getAnswersForGame(question_id: number) {
+        const query = "SELECT * FROM answer WHERE id_question=" + question_id;
+
+        const answers = await asyncdb.all(query);
+        console.log(answers);
+        return answers;
+    }
+
 }
 
 export default new DBHandler();
\ No newline at end of file
diff --git a/API/src/routes/BaseRoutes.ts b/API/src/routes/BaseRoutes.ts
index 0b7dd53..1479e16 100644
--- a/API/src/routes/BaseRoutes.ts
+++ b/API/src/routes/BaseRoutes.ts
@@ -164,6 +164,10 @@ router.get(ROUTE+'/question', (req: express.Request, res: express.Response) => {
     DBHandler.getQuestions(req, res);
 })
 
+router.get(ROUTE+'/question/:id', (req: express.Request, res: express.Response) => {
+    DBHandler.getQuestions(req, res);
+})
+
 router.patch(ROUTE+'/question/:id', (req: express.Request, res: express.Response) => {
     const token = req.headers['authorization'] && req.headers['authorization'].split(' ')[1];
 
diff --git a/API/src/socket.io/ServerIO.ts b/API/src/socket.io/ServerIO.ts
index 504ca90..829fb6e 100644
--- a/API/src/socket.io/ServerIO.ts
+++ b/API/src/socket.io/ServerIO.ts
@@ -1,15 +1,17 @@
 import * as IO from 'socket.io';
 import logger  from '../logging/WinstonLogger';
 import http    from 'http';
-import { User_t } from '../database/Database';
+import { Answer_t, Question_t, User_t } from '../database/Database';
+import DBHandler       from '../database/Database';
 
 const jwt = require('jsonwebtoken');
 //TODO: In this file you can add/edit all things about socket.io
 
 class ServerIO extends IO.Server {
 
-    private playerNumber: number = 0;
+    private gameOngoing: boolean = false;
     private playerList: string[] = [];
+    private questions : Question_t[] = [];
 
     constructor(server: http.Server) {
         super(server, {
@@ -20,16 +22,9 @@ class ServerIO extends IO.Server {
 
         this.on('connection', (socket: IO.Socket) => {
             logger.info(`New socket on ${ socket.client.conn.remoteAddress }`);
-            const token = socket.handshake.query.Authorization;
-            
-            if (token === "null") {
-                logger.info(`User not logged in, disconnecting ${ socket.client.conn.remoteAddress }`)
-                socket.emit("Not Logged In");
-                return socket.disconnect();
-            }
             
             this.registerEventsOnSocket(socket);
-            socket.emit('Players Waiting', this.playerNumber)
+            socket.emit('Players Waiting', this.playerList.length)
         });
     }
 
@@ -39,10 +34,13 @@ class ServerIO extends IO.Server {
         });
 
         socket.on('Join Room', _ => {
+
+            if (this.gameOngoing)
+                return socket.emit('Room Full');
+
             const token = socket.handshake.query.Authorization;    
 
             var user: User_t = null;
-            console.log(token)
             jwt.verify(token, process.env.TOKEN_SECRET, (err:any, res:User_t) => {
                 // console.log(err);
                 if (err) return false;
@@ -54,6 +52,9 @@ class ServerIO extends IO.Server {
             
             socket.emit('Players Waiting', this.playerList.length)
             socket.broadcast.emit('Players Waiting', this.playerList.length);
+
+            if (this.playerList.length == 3)
+                this.game();
         })
 
         socket.on('Leave Room', _ => {
@@ -71,7 +72,7 @@ class ServerIO extends IO.Server {
                 this.playerList.splice(index, 1);
                 logger.info(username + ` left the game`);
             }
-            
+
             socket.emit('Players Waiting', this.playerList.length)
             socket.broadcast.emit('Players Waiting', this.playerList.length);
         })
@@ -97,7 +98,50 @@ class ServerIO extends IO.Server {
             logger.info(username + ` left the game`);
             socket.emit('Players Waiting', this.playerList.length);
         })
+
+        socket.on(`Answer`, answer => {
+
+
+            this.sendQuestion();
+        })
+    } 
+
+    private async game() {
+        this.gameOngoing = true;
+
+        await DBHandler.getQuestionsForGame()
+        .then(res => {
+            this.questions = res as Question_t[];
+        });
+        this.emit("Game Start");
+
+        this.sendQuestion();
+    }
+
+    async sendQuestion() {
+
+        if (this.questions.length == 0)
+            return this.gameEnd()
+
+        console.log(this.questions)
+        
+        let currentQuestion = this.questions.pop()
+
+        this.emit("Question", currentQuestion.question);
+
+        var answers: Answer_t[];
+        await DBHandler.getAnswersForGame(currentQuestion.id)
+        .then(ans => {
+            answers = ans as Answer_t[];
+        })
+
+        this.emit("Answers", answers);
     }
+
+    gameEnd() {
+
+    }
+
 }
 
 
diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html
index ea1657f..c4e9008 100644
--- a/frontend/src/app/app.component.html
+++ b/frontend/src/app/app.component.html
@@ -20,7 +20,7 @@
         <app-user-dropdown [username]="auth.getUsername()"></app-user-dropdown>
     </div>
 
-    <div *ngIf="auth.isLoggedIn()">
+    <div *ngIf="auth.isLoggedIn() && !hasRoute('admin')">
         <app-gameroom></app-gameroom>
     </div>
 
diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts
index d4efe2a..a071477 100644
--- a/frontend/src/app/app.component.ts
+++ b/frontend/src/app/app.component.ts
@@ -25,4 +25,8 @@ export class AppComponent {
   userDropdown(): void {
     this.userDropdownModal = !this.userDropdownModal;
   }
+
+  hasRoute(route: string) {
+    return this.router.url.includes(route);
+  }
 }
\ No newline at end of file
diff --git a/frontend/src/app/gameroom/gameroom.component.html b/frontend/src/app/gameroom/gameroom.component.html
index 7fc7963..fdb1511 100644
--- a/frontend/src/app/gameroom/gameroom.component.html
+++ b/frontend/src/app/gameroom/gameroom.component.html
@@ -1,6 +1,20 @@
-<p>gameroom works!</p>
+<div class="m-10">
+    <div *ngIf="!gameStart" class="bg-white flex flex-col items-center w-fit p-6 rounded-lg border-2 border-black">
+        <span class="w-fit">Player number : {{playerNumber}}/3</span>
+        
+        <button class="bg-white w-fit border-2 border-black rounded-lg px-2 hover:bg-gray-300 mt-2" *ngIf="!inRoom" (click)="joinRoom()">Join Room</button>
+        <button class="bg-white w-fit border-2 border-black rounded-lg px-2 hover:bg-gray-300 mt-2" *ngIf="inRoom" (click)="leaveRoom()">Leave Room</button>
+    </div>
+    <div *ngIf="gameStart">
+        {{question}}
 
-<span>Player number : {{playerNumber}}/3</span>
-
-<button *ngIf="!inRoom" (click)="joinRoom()">Join Room</button>
-<button *ngIf="inRoom" (click)="leaveRoom()">Leave Room</button>
\ No newline at end of file
+        <table>
+            <thead><th>Answers</th></thead>
+            <tbody>
+                <tr *ngFor="let answer of answers">
+                    <td><button (click)="sendAnswer(answer)">{{answer.text_answer}}</button></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+</div>
\ No newline at end of file
diff --git a/frontend/src/app/gameroom/gameroom.component.ts b/frontend/src/app/gameroom/gameroom.component.ts
index 6f59da2..55190c4 100644
--- a/frontend/src/app/gameroom/gameroom.component.ts
+++ b/frontend/src/app/gameroom/gameroom.component.ts
@@ -1,6 +1,8 @@
 import { Component, OnDestroy, OnInit } from '@angular/core';
 import { Socket } from 'ngx-socket-io';
 import { SocketService } from '../services/socket.service';
+import { QuestionsService } from '../services/questions.service';
+import { Answer } from '../Types/types';
 
 @Component({
   selector: 'app-gameroom',
@@ -10,17 +12,33 @@ import { SocketService } from '../services/socket.service';
 export class GameroomComponent implements OnInit, OnDestroy {
 
   playerNumber!: number;
-
+  gameStart: boolean = false;
+  questionID!: number;
+  question: string = "";
+  answers!: Answer[];
   inRoom: boolean = false;
 
-  constructor(private socket: SocketService) {}
+  constructor(
+    private socket: SocketService) {}
 
   ngOnInit(): void {
     this.socket.playerNumber.subscribe(number => {
       this.playerNumber = number;
     })
-  }
 
+    this.socket.gameStart.subscribe(status => {
+      this.gameStart = status;
+    })
+
+    this.socket.questionID.subscribe(id => {
+      this.question = id;
+    })
+    
+    this.socket.answers.subscribe(answers => {
+      this.answers = answers;
+    })
+  }
+  
   ngOnDestroy(): void {
     // this.socket.disconnectSocket();
   }
@@ -35,4 +53,8 @@ export class GameroomComponent implements OnInit, OnDestroy {
     this.inRoom = false;
   }
 
+  sendAnswer(answer: Answer) {
+    this.socket.sendAnswer(answer);
+  }
+
 }
diff --git a/frontend/src/app/services/authentication.service.ts b/frontend/src/app/services/authentication.service.ts
index ea45926..e8defea 100644
--- a/frontend/src/app/services/authentication.service.ts
+++ b/frontend/src/app/services/authentication.service.ts
@@ -25,9 +25,7 @@ export class AuthenticationService {
     this.http.post('http://0.0.0.0:30992/API/v1/login', body, {observe: 'response'})
     .subscribe(res => {
       if(res.ok) {
-        
         localStorage.setItem("token", res.body.toString());
-        this.socket.refreshSocketToken();
         this.router.navigateByUrl("/");
       }
       else {
@@ -42,7 +40,6 @@ export class AuthenticationService {
 
   logout(): void {
     localStorage.removeItem("token");
-    this.socket.refreshSocketToken();
     this.socket.leaveRoom();
     this.router.navigateByUrl("/");
   }
diff --git a/frontend/src/app/services/socket.service.ts b/frontend/src/app/services/socket.service.ts
index cae437e..42b7b6e 100644
--- a/frontend/src/app/services/socket.service.ts
+++ b/frontend/src/app/services/socket.service.ts
@@ -2,40 +2,64 @@ import { Injectable } from '@angular/core';
 import { Socket } from 'ngx-socket-io';
 import { AuthenticationService } from './authentication.service';
 import { BehaviorSubject } from 'rxjs';
+import { QuestionsService } from './questions.service';
+import { Answer, Question } from '../Types/types';
+import { HttpClient } from '@angular/common/http';
+
+const ROUTE = "http://0.0.0.0:30992/API/v1"
 
 @Injectable({
   providedIn: 'root'
 })
 export class SocketService {
 
-  private _playerNumber = new BehaviorSubject<number>(0);;
+  private _playerNumber = new BehaviorSubject<number>(0);
+  private _gameStart = new BehaviorSubject<boolean>(false);
+  private _currentQuestion = new BehaviorSubject<string>("");
+  private _currentAnswers = new BehaviorSubject<Answer[]>([]);
 
   constructor(
     private socket: Socket
   ) {
     this.socket.ioSocket.io.opts.query = { Authorization: localStorage.getItem("token")};
     this.recievePlayerNumber();
+    this.recieveGameStatus();
+    this.recieveQuestion();
   }
 
   get playerNumber() {
     return this._playerNumber.asObservable();
   }
 
+  get gameStart() {
+    return this._gameStart.asObservable();
+  }
+
+  get questionID() {
+    return this._currentQuestion.asObservable();
+  }
+
+  get answers() {
+    return this._currentAnswers.asObservable();
+  }
+
   refreshSocketToken(): void {
     this.socket.ioSocket.io.opts.query = { Authorization: localStorage.getItem("token")};
   }
 
   joinRoom(): void {
+    this.refreshSocketToken();
     this.socket.emit("Join Room");
   }
 
   leaveRoom(): void {
+    this.refreshSocketToken();
     this.socket.emit("Leave Room");
   }
 
-  recieveHelloWorld() {
-    this.socket.on("Bienvenue", ()=> {
-      console.log("Connected");
+  recieveGameStatus() {
+    this.socket.on("Game Start", ()=> {
+      this._gameStart.next(true);
     })
   }
 
@@ -46,12 +70,29 @@ export class SocketService {
     })
   }
 
+  recieveQuestion(): void {
+    this.socket.on("Question", question => {
+      
+      this._currentQuestion.next(question);
+    })
+
+    this.socket.on("Answers", answers => {
+      this._currentAnswers.next(answers);
+    })
+  }
+
   disconnectSocket() {
     this.socket.disconnect();
   }
 
   sendMessage(text: string): void {
+    this.refreshSocketToken();
     this.socket.emit(text);
   }
 
+  sendAnswer(answer: Answer): void {
+    this.refreshSocketToken();
+    this.socket.emit("Answer", answer);
+  }
+
 }
-- 
GitLab