diff --git a/API/db/app.db b/API/db/app.db index a1e13e4fb81d71b67d2b35525e3b901708a8f4f0..0b24d66b013e0f14002ec1b06dd426f5e50d6afd 100644 Binary files a/API/db/app.db and b/API/db/app.db differ diff --git a/API/src/database/Database.ts b/API/src/database/Database.ts index e7d0f9ac984c1b60c5fd30471d0213dbab96d373..a831a01114ffe7b5ed4c2bfb344f8bef914c9c37 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 0b7dd5312b0a22635084f95e6ab968b7c4cd37ba..1479e16e3417a5d948c449f58f72222bd1f1e66a 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 504ca90591ca93f370f6e14690c1289e70d87902..829fb6ea838bb60eb0f34aaf5e5c5a3940756f40 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 ea1657fef6f43d2abb9aacfebc1d4f1f18483176..c4e90085de2afee864fcf64c2a69f9f1890635c5 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 d4efe2a51cbb92e7a341e0d6e7ba8e10591d3a26..a07147730a22ce3dc68c8e8db5871cffa966ca5e 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 7fc7963e3c52c76fb0cf93bc5f5ca976d76c192c..fdb15118ab4443f2f86cf0743864c2728b3e0fbd 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 6f59da2747511d6ce215c4e963a7534d667ce26c..55190c486773877bae9b865c15cb06581a2d1993 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 ea45926b44f89204a6f5062b36a2a1e927d38835..e8defea600f38d3ae57fd60ca87dda5007d5ea7e 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 cae437ea411f396991b7196f8aa73831b263b82d..42b7b6e6a764ff3fe2edb049be85977418a224e5 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); + } + }