Merge branch 'master' into hugo

This commit is contained in:
simplonco
2023-01-14 19:35:08 +01:00
19 changed files with 157 additions and 157 deletions

View File

@@ -1,5 +1,7 @@
DOCKERCOMPOSEPATH=./srcs/docker-compose.yml
all : up
#dev allow hot reload.
up:
@bash ./make_env.sh
@@ -11,8 +13,6 @@ start:
docker compose -f ${DOCKERCOMPOSEPATH} start
docker logs --follow nestjs
all : up
re: down up
down:

View File

@@ -26,7 +26,7 @@ services:
volumes:
- ./requirements/nestjs/api_back/src:/usr/app/src
- ./requirements/nestjs/api_back/test:/usr/app/test/
- nestjs_photos_volume:/usr/app/src/uploads/avatars
- nestjs_photos_volume:/usr/app/uploads/avatars
restart: unless-stopped
depends_on:
- postgresql

View File

@@ -6,6 +6,7 @@ import * as ev from "../../shared_js/class/Event.js"
import * as en from "../../shared_js/enums.js"
export class Client {
role: en.ClientRole;
socket: WebSocket;
id: string; // same as "socket.id"
isAlive: boolean = true;
@@ -23,9 +24,8 @@ export class ClientPlayer extends Client {
inputBuffer: ev.EventInput = new ev.EventInput();
lastInputId: number = 0;
racket: Racket;
constructor(socket: WebSocket, id: string, racket: Racket) {
constructor(socket: WebSocket, id: string) {
super(socket, id);
this.racket = racket;
}
}

View File

@@ -76,6 +76,8 @@ async function clientAnnounceListener(this: WebSocket, data: string)
if (msg.role === en.ClientRole.player)
{
const announce: ev.ClientAnnouncePlayer = <ev.ClientAnnouncePlayer>msg;
const player = clientsMap.get(this.id) as ClientPlayer;
player.role = msg.role;
const body = {
playerOneUsername: announce.username,
@@ -106,8 +108,6 @@ async function clientAnnounceListener(this: WebSocket, data: string)
clientTerminate(clientsMap.get(this.id));
return;
}
const player = clientsMap.get(this.id) as ClientPlayer;
player.matchOptions = announce.matchOptions;
player.token = announce.token;
player.username = announce.username;
@@ -126,13 +126,15 @@ async function clientAnnounceListener(this: WebSocket, data: string)
else if (msg.role === en.ClientRole.spectator)
{
const announce: ev.ClientAnnounceSpectator = <ev.ClientAnnounceSpectator>msg;
const spectator = clientsMap.get(this.id) as ClientSpectator;
spectator.role = msg.role;
const gameSession = gameSessionsMap.get(announce.gameSessionId);
if (!gameSession) {
this.send(JSON.stringify( new ev.EventError("invalid gameSessionId") ));
clientTerminate(clientsMap.get(this.id));
return;
}
const spectator = clientsMap.get(this.id) as ClientSpectator;
spectator.gameSession = gameSession;
gameSession.spectatorsMap.set(spectator.id, spectator);
spectator.socket.once("message", spectatorReadyConfirmationListener);
@@ -419,7 +421,7 @@ const pingInterval = setInterval( () => {
}, 4200);
export function clientTerminate(client: Client)
export async function clientTerminate(client: Client)
{
client.socket.terminate();
if (client.gameSession)
@@ -439,6 +441,23 @@ export function clientTerminate(client: Client)
else if (privateMatchmakingMap.has(client.id)) {
privateMatchmakingMap.delete(client.id);
}
if (client.role === en.ClientRole.player)
{
const player = client as ClientPlayer;
console.log("/resetuserstatus " + player.username);
const response = await fetch(c.addressBackEnd + "/game/gameserver/resetuserstatus",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({username: player.username})
});
if (!response.ok) {
console.log("/resetuserstatus " + player.username + " failed");
}
}
}

View File

@@ -5,6 +5,7 @@ import { Response } from 'express';
import { TwoFaDto } from './dto/2fa.dto';
import { UsersService } from 'src/users/users.service';
import { User } from 'src/users/entities/user.entity';
import { STATUS } from 'src/common/constants/constants';
@Controller('auth')
export class AuthenticationController {
@@ -36,6 +37,7 @@ export class AuthenticationController {
console.log('On redirige');
const user : User = request.user
if (user.isEnabledTwoFactorAuth === false || user.isTwoFactorAuthenticated === true){
this.userService.updateStatus(user.id, STATUS.CONNECTED)
console.log('ON VA VERS PROFILE');
return response.status(200).redirect('http://' + process.env.WEBSITE_HOST + ':' + process.env.WEBSITE_PORT + '/#/profile');
}
@@ -51,7 +53,7 @@ export class AuthenticationController {
@UseGuards(AuthenticateGuard)
logout(@Req() request, @Res() response, @Next() next) {
this.userService.setIsTwoFactorAuthenticatedWhenLogout(request.user.id);
this.userService.updateStatus(request.user.id, 'disconnected');
this.userService.updateStatus(request.user.id, STATUS.DISCONNECTED);
request.logout(function(err) {
if (err) { return next(err); }
response.redirect('/');
@@ -83,6 +85,7 @@ export class AuthenticationController {
throw new UnauthorizedException('Wrong Code.');
await this.userService.authenticateUserWith2FA(request.user.id);
console.log('ON REDIRIGE');
this.userService.updateStatus(user.id, STATUS.CONNECTED)
return response.status(200).redirect('http://' + process.env.WEBSITE_HOST + ':' + process.env.WEBSITE_PORT + '/#/profile');
}
}

View File

@@ -101,4 +101,9 @@ export class GameController {
{
return this.gameService.destroySession(token);
}
@Post('gameserver/resetuserstatus')
async resetUserStatus(@Body('username') username){
this.gameService.resetStatus(username);
}
}

View File

@@ -92,12 +92,17 @@ export class GameService {
}
this.userRepository.save(user);
}
// if (grantTicketDto.isGameIsWithInvitation === true && user.status !== STATUS.IN_GAME) // WIP: need to fix STATUS.IN_GAME
if (grantTicketDto.isGameIsWithInvitation === true)
{
const secondUser : Partial<User> = await this.userService.findOne(grantTicketDto.playerTwoUsername)
if (!secondUser || secondUser.username === user.username)
return res.status(HttpStatus.NOT_FOUND).json({message : "User not found OR you want to play with yourself."});
if (grantTicketDto.playerTwoUsername === user.username) {
return res.status(HttpStatus.BAD_REQUEST).json({message : "You cant play against yourself."});
}
const secondUser : User = await this.userRepository.createQueryBuilder('user')
.where("user.username = :username", {username : grantTicketDto.playerTwoUsername})
.getOne();
if (!secondUser) {
return res.status(HttpStatus.NOT_FOUND).json({message : "Invited user not found"});
}
const encryptedTextToReturn = await this.encryptToken(user.username + '_' + secondUser.username + '_'
+ grantTicketDto.gameOptions + '_' + grantTicketDto.isGameIsWithInvitation + '_' + new Date())
const tok = this.tokenGameRepository.create(grantTicketDto);
@@ -106,9 +111,9 @@ export class GameService {
tok.token = encryptedTextToReturn;
this.tokenGameRepository.save(tok);
this.userService.updateStatus(user.id, STATUS.IN_POOL)
this.userService.updateStatus(secondUser.id, STATUS.IN_POOL)
return res.status(HttpStatus.OK).json({ token : encryptedTextToReturn });
}
// else if (grantTicketDto.isGameIsWithInvitation === false && user.status !== STATUS.IN_GAME) { // WIP: need to fix STATUS.IN_GAME
else if (grantTicketDto.isGameIsWithInvitation === false) {
const encryptedTextToReturn = await this.encryptToken(user.username + '_'
+ grantTicketDto.gameOptions + '_' + grantTicketDto.isGameIsWithInvitation + '_' + new Date())
@@ -142,13 +147,11 @@ export class GameService {
const userOne : User = await this.userRepository.createQueryBuilder('user')
.where("user.username = :username", {username : tokenGame.playerOneUsername})
.getOne();
this.userService.updateStatus(userOne.id, STATUS.IN_GAME)
const userTwo : User = await this.userRepository.createQueryBuilder('user')
.where("user.username = :username", {username : tokenGame.playerTwoUsername})
.getOne();
this.deleteToken(userOne)
this.deleteToken(userTwo)
this.userService.updateStatus(userTwo.id, STATUS.IN_GAME)
}
return true;
}
@@ -168,7 +171,6 @@ export class GameService {
const user : User = await this.userRepository.createQueryBuilder('user')
.where("user.username = :username", {username : tokenGame.playerOneUsername})
.getOne();
this.userService.updateStatus(user.id, STATUS.IN_GAME)
this.deleteToken(user)
return true;
}
@@ -259,6 +261,14 @@ export class GameService {
this.gameRepository.save(game);
if (!game)
return HttpStatus.INTERNAL_SERVER_ERROR
const playerOne : User = await this.userRepository.createQueryBuilder('user')
.where("user.username = :username", {username : creategameDto.playerOneUsername})
.getOne();
const playerTwo : User = await this.userRepository.createQueryBuilder('user')
.where("user.username = :username", {username : creategameDto.playerTwoUsername})
.getOne();
this.userService.updateStatus(playerOne.id, STATUS.IN_GAME)
this.userService.updateStatus(playerTwo.id, STATUS.IN_GAME)
console.log("200 retourné pour la création de partie")
return HttpStatus.OK
}
@@ -280,6 +290,8 @@ export class GameService {
const playerTwo = await this.userRepository.findOneBy({username : game.playerTwoUsername})
if (!playerOne || !playerTwo)
return new HttpException("Internal Server Error. Impossible to update the database", HttpStatus.INTERNAL_SERVER_ERROR);
this.userService.updateStatus(playerOne.id, STATUS.CONNECTED);
this.userService.updateStatus(playerTwo.id, STATUS.CONNECTED);
if (game.playerOneUsernameResult === game.playerTwoUsernameResult)
{
this.userService.incrementDraws(playerOne.id)
@@ -296,9 +308,14 @@ export class GameService {
this.userService.incrementVictories(playerOne.id)
this.userService.incrementDefeats(playerTwo.id)
}
this.userService.updateStatus(playerOne.id, STATUS.CONNECTED)
this.userService.updateStatus(playerTwo.id, STATUS.CONNECTED)
return HttpStatus.OK
}
async resetStatus(username : string){
const user : User = await this.userRepository.findOneBy({username : username})
if (!user)
return HttpStatus.NOT_FOUND;
this.userService.updateStatus(user.id, STATUS.CONNECTED);
}
}

View File

@@ -13,11 +13,6 @@ body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
/* tmp? */
background: bisque;
/* overflow-x: hidden; */
/* This seems to have fixed my pages that are too long */
/* but now i can't scroll anywhere ... */
/* overflow-y: hidden; */
}
a {

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 675 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 KiB

View File

@@ -1 +0,0 @@
<svg id="visual" viewBox="0 0 900 150" width="900" height="150" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><path d="M0 36L21.5 33.7C43 31.3 86 26.7 128.8 32.5C171.7 38.3 214.3 54.7 257.2 63.5C300 72.3 343 73.7 385.8 65.7C428.7 57.7 471.3 40.3 514.2 30.5C557 20.7 600 18.3 642.8 25.8C685.7 33.3 728.3 50.7 771.2 59.5C814 68.3 857 68.7 878.5 68.8L900 69L900 0L878.5 0C857 0 814 0 771.2 0C728.3 0 685.7 0 642.8 0C600 0 557 0 514.2 0C471.3 0 428.7 0 385.8 0C343 0 300 0 257.2 0C214.3 0 171.7 0 128.8 0C86 0 43 0 21.5 0L0 0Z" fill="#618174" stroke-linecap="round" stroke-linejoin="miter"></path></svg>

Before

Width:  |  Height:  |  Size: 645 B

View File

@@ -9,22 +9,8 @@
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
.then((resp) => resp.json())
// i mean i could do a failed to load user or some shit, maybe with a .catch or something? but atm why bother
console.log('User var');
console.log(user);
// if (user && user.statusCode && user.statusCode === 403) {
// console.log('user not logged in')
// }
// if (user && user.username) {
// console.log('we have a user');
// }
// user === undefined doesn't work cuz we declared user in the scope of onMount
// if (user === undefined) {
if (user && user.statusCode && user.statusCode === 403) {
console.log('on mount no user, returned status code 403 so logging out of userStore')
// userLogout(); // which i think should delete any previous local storage
}
});
@@ -34,8 +20,6 @@
console.log('you are now logged in');
}
// i could prolly put this in it's own compoent, i seem to use it in several places... or maybe just some JS? like no need for html
// we could .then( () => replace('/') ) need the func so TS compatible...
const logout = async() => {
await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/auth/logout`, {
method: 'POST',
@@ -46,108 +30,71 @@
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<header class="grid-container">
<h1>Potato Pong</h1>
<nav>
<!-- {#if user !== undefined} -->
{#if user && user.username}
<div on:click={ () => (push('/profile')) }>Profile</div>
<div on:click={logout}>Logout</div>
{:else}
<div on:click={login}>Login</div>
{/if}
</nav>
<h2>
<div>Welcome to</div>
<div>Potato Pong</div>
</h2>
</header>
<Canvas/>
<!-- doesn't work :( -->
<!-- <svelte:body style="overflow-y: hidden"/> -->
<div class="container">
<div class="splash-page">
{#if user && user.username}
<button class="button-in" on:click={ () => (push('/profile')) }>Profile</button>
<button class="button-out" on:click={logout}>Logout</button>
{:else}
<button class="button-in" on:click={login}>Login</button>
{/if}
</div>
</div>
<style>
@font-face {
font-family: "Bit5x3";
src:
url("/fonts/Bit5x3.woff2") format("woff2"),
local("Bit5x3"),
url("/fonts/Bit5x3.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
/* :global(body) {
overflow-y: hidden;
} */
header {
/* didn't work... */
overflow-y: hidden;
}
.container {
height: 100%;
width: 100%;
position: relative;
background-image: url('/img/SPLASH_PAGE_BACKGROUND.png');
background-position: center center;
background-repeat: no-repeat;
background-attachment: fixed;
background-size: cover;
}
/* The actually important stuff */
.splash-page {
margin: 0;
position: absolute;
top: 80%;
-ms-transform: translateY(-80%);
transform: translateY(-80%);
left: 50%;
-ms-transform: translateX(-50%);
transform: translateX(-50%);
}
.grid-container{
position: absolute;
left: 0;
top: 0;
.button-in {
background-color: #8c0000;
border-color: black;
border-width: 4px;
color: white;
font-family: "Bit5x3";
font-size: x-large;
padding: 10px;
}
box-sizing: border-box;
width: 100%;
height: 100%;
/* max-height: 100%; */
white-space: nowrap;
/* padding-bottom: 0; */
margin-bottom: 0px;
overflow: hidden;
padding: 20px 40px;
margin: 0px;
.button-out {
background-color: #008c8c;
border-color: black;
border-width: 4px;
color: white;
font-family: "Bit5x3";
font-size: x-large;
padding: 10px;
}
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 1fr 1fr 1fr 1fr 1fr;
align-items: center;
}
header h1{
grid-column: 1 / 7;
grid-row: 1;
/* grid-column: span 6; */
/* tmp? */
padding: 20px;
border: 1px solid bisque;
}
header nav{
/* make it a flexbox? */
grid-column: 7 / 13;
grid-row: 1;
justify-self: end;
/* tmp? */
padding: 20px;
border: 1px solid bisque;
}
header h2{
grid-row: 3;
grid-column: 5 / span 4;
justify-self: center;
/* tmp */
border: 1px solid black;
z-index: 3;
}
header h2 div{
font-size: 2em;
/* color: red; */
}
nav div {
display: inline;
color: bisque;
font-weight: bold;
}
nav > div {
padding-left: 1em;
/* didn't quite work, applies to both for some reason */
/* nav:first-child doesn't work either*/
}
nav div:hover{
text-decoration: underline;
cursor: pointer;
}
</style>

View File

@@ -268,25 +268,34 @@
<button class="pong_button" on:click={fetchInvitations}>Show invitations</button>
<fieldset in:fly="{{ y: 10, duration: 1000 }}">
<legend>game options</legend>
<div>
<label for="multi_balls">
<input type="checkbox" id="multi_balls" name="multi_balls" bind:checked={options.multi_balls}>
<label for="multi_balls">Multiples balls</label>
</div>
<div>
Multiples balls
</label>
<label for="moving_walls">
<input type="checkbox" id="moving_walls" name="moving_walls" bind:checked={options.moving_walls}>
<label for="moving_walls">Moving walls</label>
</div>
Moving walls
</label>
<div>
<p>sound :</p>
<input type="radio" id="sound_on" name="sound_selector" bind:group={options.sound} value="on">
<label for="sound_on">on</label>
<input type="radio" id="sound_off" name="sound_selector" bind:group={options.sound} value="off">
<label for="sound_off">off</label>
</div>
<div>
<input type="checkbox" id="isSomeoneIsInvited" bind:checked={options.isSomeoneIsInvited}>
<label for="moving_walls">Invite a friend</label>
sound :
<label for="sound_on">
<input type="radio" id="sound_on" name="sound_selector" bind:group={options.sound} value="on">
on
</label>
<label for="sound_off">
<input type="radio" id="sound_off" name="sound_selector" bind:group={options.sound} value="off">
off
</label>
</div>
<label for="invitation_checkbox">
<input type="checkbox" id="invitation_checkbox" bind:checked={options.isSomeoneIsInvited}>
Invite a friend
</label>
{#if options.isSomeoneIsInvited}
<select bind:value={options.playerTwoUsername}>
{#each allUsers as user }

View File

@@ -131,13 +131,19 @@
<fieldset>
<legend>options</legend>
<button class="pong_button" on:click={fetchMatchList}>Reload</button>
<div>
<p>sound :</p>
<input type="radio" id="sound_on" name="sound_selector" bind:group={sound} value="on">
<label for="sound_on">on</label>
<input type="radio" id="sound_off" name="sound_selector" bind:group={sound} value="off">
<label for="sound_off">off</label>
sound :
<label for="sound_on">
<input type="radio" id="sound_on" name="sound_selector" bind:group={sound} value="on">
on
</label>
<label for="sound_off">
<input type="radio" id="sound_off" name="sound_selector" bind:group={sound} value="off">
off
</label>
</div>
</fieldset>
{#if matchList.length !== 0}
<menu id="match_list">