From 4bb10ffb276f2cf679f174e88c3b340f0772b075 Mon Sep 17 00:00:00 2001 From: nicolas-arnaud Date: Wed, 15 Mar 2023 21:07:08 +0100 Subject: [PATCH] fixed format --- .env_sample | 25 + back/volume/.eslintrc.js | 16 +- back/volume/src/app.module.ts | 44 +- back/volume/src/auth/42-auth.guard.ts | 26 +- back/volume/src/auth/42.decorator.ts | 10 +- back/volume/src/auth/42.strategy.ts | 58 +- back/volume/src/auth/auth.controller.ts | 74 +- back/volume/src/auth/auth.module.ts | 52 +- back/volume/src/auth/auth.service.ts | 54 +- back/volume/src/auth/session.serializer.ts | 14 +- back/volume/src/chat/chat.controller.ts | 190 ++--- back/volume/src/chat/chat.gateway.ts | 106 +-- back/volume/src/chat/chat.module.ts | 26 +- back/volume/src/chat/chat.service.ts | 182 ++--- back/volume/src/chat/dto/connection.dto.ts | 8 +- .../volume/src/chat/dto/create-channel.dto.ts | 18 +- .../volume/src/chat/dto/create-message.dto.ts | 8 +- .../volume/src/chat/dto/update-channel.dto.ts | 20 +- back/volume/src/chat/dto/updateUser.dto.ts | 8 +- back/volume/src/chat/entity/channel.entity.ts | 40 +- .../src/chat/entity/connection.entity.ts | 14 +- back/volume/src/chat/entity/dm.entity.ts | 12 +- back/volume/src/chat/entity/message.entity.ts | 18 +- back/volume/src/chat/message.service.ts | 46 +- back/volume/src/main.ts | 56 +- .../src/pong/dtos/GameCreationDtoValidated.ts | 20 +- back/volume/src/pong/dtos/GameInfo.ts | 18 +- back/volume/src/pong/dtos/GameUpdate.ts | 10 +- back/volume/src/pong/dtos/MapDtoValidated.ts | 14 +- back/volume/src/pong/dtos/MatchmakingDto.ts | 2 +- .../src/pong/dtos/MatchmakingDtoValidated.ts | 6 +- .../volume/src/pong/dtos/PointDtoValidated.ts | 8 +- back/volume/src/pong/dtos/RectDtoValidated.ts | 12 +- back/volume/src/pong/dtos/StringDto.ts | 2 +- .../src/pong/dtos/StringDtoValidated.ts | 6 +- back/volume/src/pong/dtos/UserDto.ts | 8 +- back/volume/src/pong/entity/result.entity.ts | 18 +- back/volume/src/pong/game/Ball.ts | 106 +-- back/volume/src/pong/game/Game.ts | 158 ++-- back/volume/src/pong/game/Games.ts | 96 +-- back/volume/src/pong/game/MatchmakingQueue.ts | 58 +- back/volume/src/pong/game/Paddle.ts | 30 +- back/volume/src/pong/game/Player.ts | 46 +- back/volume/src/pong/game/constants.ts | 38 +- back/volume/src/pong/game/utils.ts | 72 +- back/volume/src/pong/pong.controller.ts | 32 +- back/volume/src/pong/pong.gateway.spec.ts | 24 +- back/volume/src/pong/pong.gateway.ts | 178 ++--- back/volume/src/pong/pong.module.ts | 16 +- back/volume/src/pong/pong.service.ts | 96 +-- back/volume/src/pong/pong.spec.ts | 24 +- back/volume/src/types.d.ts | 10 +- back/volume/src/users/dto/user.dto.ts | 22 +- back/volume/src/users/entity/user.entity.ts | 62 +- back/volume/src/users/users.controller.ts | 208 +++-- back/volume/src/users/users.module.ts | 16 +- back/volume/src/users/users.service.ts | 210 ++--- front/volume/src/components/Chat.svelte | 746 +++++++++--------- 58 files changed, 1757 insertions(+), 1740 deletions(-) create mode 100644 .env_sample diff --git a/.env_sample b/.env_sample new file mode 100644 index 0000000..1e5aaa2 --- /dev/null +++ b/.env_sample @@ -0,0 +1,25 @@ +POSTGRES_HOST=postgres +POSTGRES_PORT=5432 +POSTGRES_USER=postgres_usr +POSTGRES_PASSWORD=postgres_pw +POSTGRES_DB=transcendence + +PGADMIN_DEFAULT_EMAIL=admin@pg.com +PGADMIN_DEFAULT_PASSWORD=admin + +MAIL_USER=vaganiwast@gmail.com +MAIL_PASSWORD= + +FRONT_FPS=144 + +HOST=localhost +FRONT_PORT=80 +BACK_PORT=3001 +HASH_SALT=10 + +JWT_SECRET=test +JWT_EXPIRATION_TIME=900 + +FT_OAUTH_CLIENT_ID= +FT_OAUTH_CLIENT_SECRET= +FT_OAUTH_CALLBACK_URL=http://$HOST:$BACK_PORT/log/inReturn diff --git a/back/volume/.eslintrc.js b/back/volume/.eslintrc.js index 651eeec..68e0778 100644 --- a/back/volume/.eslintrc.js +++ b/back/volume/.eslintrc.js @@ -1,13 +1,13 @@ module.exports = { env: { browser: true, - es2021: true, + es2021: true }, - extends: "standard-with-typescript", + extends: 'standard-with-typescript', parserOptions: { - ecmaVersion: "latest", - sourceType: "module", - project: ["./tsconfig.json"], - tsconfigRootDir: __dirname, - }, -}; + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json'], + tsconfigRootDir: __dirname + } +} diff --git a/back/volume/src/app.module.ts b/back/volume/src/app.module.ts index 7d00622..2e363df 100644 --- a/back/volume/src/app.module.ts +++ b/back/volume/src/app.module.ts @@ -1,13 +1,13 @@ -import { Module } from "@nestjs/common"; -import { ConfigModule, ConfigService } from "@nestjs/config"; -import { TypeOrmModule } from "@nestjs/typeorm"; -import * as Joi from "joi"; -import { ScheduleModule } from "@nestjs/schedule"; +import { Module } from '@nestjs/common' +import { ConfigModule, ConfigService } from '@nestjs/config' +import { TypeOrmModule } from '@nestjs/typeorm' +import * as Joi from 'joi' +import { ScheduleModule } from '@nestjs/schedule' -import { AuthModule } from "./auth/auth.module"; -import { ChatModule } from "./chat/chat.module"; -import { PongModule } from "./pong/pong.module"; -import { UsersModule } from "./users/users.module"; +import { AuthModule } from './auth/auth.module' +import { ChatModule } from './chat/chat.module' +import { PongModule } from './pong/pong.module' +import { UsersModule } from './users/users.module' @Module({ imports: [ @@ -26,28 +26,28 @@ import { UsersModule } from "./users/users.module"; HOST: Joi.string().required(), FRONT_PORT: Joi.number().required(), BACK_PORT: Joi.number().required(), - HASH_SALT: Joi.number().required(), - }), + HASH_SALT: Joi.number().required() + }) }), TypeOrmModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService) => ({ - type: "postgres", - host: configService.get("POSTGRES_HOST"), - port: configService.get("POSTGRES_PORT"), - username: configService.get("POSTGRES_USER"), - password: configService.get("POSTGRES_PASSWORD"), - database: configService.get("POSTGRES_DB"), - jwt_secret: configService.get("JWT_SECRET"), + type: 'postgres', + host: configService.get('POSTGRES_HOST'), + port: configService.get('POSTGRES_PORT'), + username: configService.get('POSTGRES_USER'), + password: configService.get('POSTGRES_PASSWORD'), + database: configService.get('POSTGRES_DB'), + jwt_secret: configService.get('JWT_SECRET'), autoLoadEntities: true, - synchronize: true, - }), + synchronize: true + }) }), AuthModule, ChatModule, PongModule, - UsersModule, - ], + UsersModule + ] }) export class AppModule {} diff --git a/back/volume/src/auth/42-auth.guard.ts b/back/volume/src/auth/42-auth.guard.ts index 1187b3b..3f5f530 100644 --- a/back/volume/src/auth/42-auth.guard.ts +++ b/back/volume/src/auth/42-auth.guard.ts @@ -1,25 +1,25 @@ import { type ExecutionContext, Injectable, - type CanActivate, -} from "@nestjs/common"; -import { AuthGuard } from "@nestjs/passport"; -import { type Request } from "express"; + type CanActivate +} from '@nestjs/common' +import { AuthGuard } from '@nestjs/passport' +import { type Request } from 'express' @Injectable() -export class FtOauthGuard extends AuthGuard("42") { - async canActivate(context: ExecutionContext): Promise { - const activate: boolean = (await super.canActivate(context)) as boolean; - const request: Request = context.switchToHttp().getRequest(); - await super.logIn(request); - return activate; +export class FtOauthGuard extends AuthGuard('42') { + async canActivate (context: ExecutionContext): Promise { + const activate: boolean = (await super.canActivate(context)) as boolean + const request: Request = context.switchToHttp().getRequest() + await super.logIn(request) + return activate } } @Injectable() export class AuthenticatedGuard implements CanActivate { - async canActivate(context: ExecutionContext): Promise { - const req: Request = context.switchToHttp().getRequest(); - return req.isAuthenticated(); + async canActivate (context: ExecutionContext): Promise { + const req: Request = context.switchToHttp().getRequest() + return req.isAuthenticated() } } diff --git a/back/volume/src/auth/42.decorator.ts b/back/volume/src/auth/42.decorator.ts index 639c85f..912cee6 100644 --- a/back/volume/src/auth/42.decorator.ts +++ b/back/volume/src/auth/42.decorator.ts @@ -1,9 +1,9 @@ -import { createParamDecorator, type ExecutionContext } from "@nestjs/common"; -import { type Profile } from "passport-42"; +import { createParamDecorator, type ExecutionContext } from '@nestjs/common' +import { type Profile } from 'passport-42' export const Profile42 = createParamDecorator( (data: unknown, ctx: ExecutionContext): Profile => { - const request = ctx.switchToHttp().getRequest(); - return request.user; + const request = ctx.switchToHttp().getRequest() + return request.user } -); +) diff --git a/back/volume/src/auth/42.strategy.ts b/back/volume/src/auth/42.strategy.ts index 461096c..7842580 100644 --- a/back/volume/src/auth/42.strategy.ts +++ b/back/volume/src/auth/42.strategy.ts @@ -1,49 +1,49 @@ -import { Injectable } from "@nestjs/common"; -import { ConfigService } from "@nestjs/config"; -import { PassportStrategy } from "@nestjs/passport"; -import { Strategy, type Profile, type VerifyCallback } from "passport-42"; -import { get } from "https"; -import { createWriteStream } from "fs"; +import { Injectable } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' +import { PassportStrategy } from '@nestjs/passport' +import { Strategy, type Profile, type VerifyCallback } from 'passport-42' +import { get } from 'https' +import { createWriteStream } from 'fs' -import { UsersService } from "src/users/users.service"; -import { User } from "src/users/entity/user.entity"; +import { UsersService } from 'src/users/users.service' +import { User } from 'src/users/entity/user.entity' @Injectable() -export class FtStrategy extends PassportStrategy(Strategy, "42") { - constructor( +export class FtStrategy extends PassportStrategy(Strategy, '42') { + constructor ( private readonly configService: ConfigService, private readonly usersService: UsersService ) { super({ - clientID: configService.get("FT_OAUTH_CLIENT_ID"), - clientSecret: configService.get("FT_OAUTH_CLIENT_SECRET"), - callbackURL: configService.get("FT_OAUTH_CALLBACK_URL"), - passReqToCallback: true, - }); + clientID: configService.get('FT_OAUTH_CLIENT_ID'), + clientSecret: configService.get('FT_OAUTH_CLIENT_SECRET'), + callbackURL: configService.get('FT_OAUTH_CALLBACK_URL'), + passReqToCallback: true + }) } - async validate( + async validate ( request: { session: { accessToken: string } }, accessToken: string, refreshToken: string, profile: Profile, cb: VerifyCallback ): Promise { - request.session.accessToken = accessToken; - const ftId = profile.id as number; - console.log("Validated ", profile.username); + request.session.accessToken = accessToken + const ftId = profile.id as number + console.log('Validated ', profile.username) if ((await this.usersService.findUser(ftId)) === null) { - const newUser = new User(); - newUser.ftId = profile.id as number; - newUser.username = profile.username; - newUser.avatar = `${ftId}.jpg`; - newUser.email = profile.emails[0].value; - void this.usersService.create(newUser); - const file = createWriteStream(`avatars/${ftId}.jpg`); + const newUser = new User() + newUser.ftId = profile.id as number + newUser.username = profile.username + newUser.avatar = `${ftId}.jpg` + newUser.email = profile.emails[0].value + void this.usersService.create(newUser) + const file = createWriteStream(`avatars/${ftId}.jpg`) get(profile._json.image.versions.small, function (response) { - response.pipe(file); - }); + response.pipe(file) + }) } - return cb(null, profile); + return cb(null, profile) } } diff --git a/back/volume/src/auth/auth.controller.ts b/back/volume/src/auth/auth.controller.ts index fc30fcb..a380cad 100644 --- a/back/volume/src/auth/auth.controller.ts +++ b/back/volume/src/auth/auth.controller.ts @@ -6,75 +6,75 @@ import { Res, Req, Post, - Body, -} from "@nestjs/common"; -import { Response, Request } from "express"; + Body +} from '@nestjs/common' +import { Response, Request } from 'express' -import { FtOauthGuard, AuthenticatedGuard } from "./42-auth.guard"; -import { Profile } from "passport-42"; -import { Profile42 } from "./42.decorator"; +import { FtOauthGuard, AuthenticatedGuard } from './42-auth.guard' +import { Profile } from 'passport-42' +import { Profile42 } from './42.decorator' -import { AuthService } from "./auth.service"; -import { UsersService } from "src/users/users.service"; +import { AuthService } from './auth.service' +import { UsersService } from 'src/users/users.service' const frontHost = - process.env.HOST !== undefined && process.env.HOST !== "" + process.env.HOST !== undefined && process.env.HOST !== '' ? process.env.HOST - : "localhost"; + : 'localhost' const frontPort = - process.env.PORT !== undefined && process.env.HOST !== "" + process.env.PORT !== undefined && process.env.HOST !== '' ? process.env.PORT - : "80"; + : '80' -@Controller("log") +@Controller('log') export class AuthController { - constructor( + constructor ( private readonly authService: AuthService, private readonly usersService: UsersService ) {} - @Get("in") + @Get('in') @UseGuards(FtOauthGuard) - ftAuth(): void {} + ftAuth (): void {} - @Get("inReturn") + @Get('inReturn') @UseGuards(FtOauthGuard) @Redirect(`http://${frontHost}:${frontPort}`) - ftAuthCallback( + ftAuthCallback ( @Res({ passthrough: true }) response: Response, - @Req() request: Request + @Req() request: Request ): any { - console.log("cookie:", request.cookies["connect.sid"]); - response.cookie("connect.sid", request.cookies["connect.sid"]); + console.log('cookie:', request.cookies['connect.sid']) + response.cookie('connect.sid', request.cookies['connect.sid']) } - @Get("/verify") + @Get('/verify') @UseGuards(AuthenticatedGuard) @Redirect(`http://${frontHost}:${frontPort}`) - async VerifyEmail(@Profile42() profile: Profile): Promise { - const ftId: number = profile.id; - const user = await this.usersService.findUser(ftId); - if (user == null) throw new Error("User not found"); - await this.authService.sendConfirmationEmail(user); + async VerifyEmail (@Profile42() profile: Profile): Promise { + const ftId: number = profile.id + const user = await this.usersService.findUser(ftId) + if (user == null) throw new Error('User not found') + await this.authService.sendConfirmationEmail(user) } - @Post("/verify") + @Post('/verify') @Redirect(`http://${frontHost}:${frontPort}`) - async Verify(@Body() body: any): Promise { - await this.authService.verifyAccount(body.code); + async Verify (@Body() body: any): Promise { + await this.authService.verifyAccount(body.code) } - @Get("profile") + @Get('profile') @UseGuards(AuthenticatedGuard) - profile(@Profile42() user: Profile): any { - return { user }; + profile (@Profile42() user: Profile): any { + return { user } } - @Get("out") + @Get('out') @Redirect(`http://${frontHost}:${frontPort}`) - logOut(@Req() req: Request): any { + logOut (@Req() req: Request): any { req.logOut(function (err) { - if (err != null) return err; - }); + if (err != null) return err + }) } } diff --git a/back/volume/src/auth/auth.module.ts b/back/volume/src/auth/auth.module.ts index 1077eb4..d3715f0 100644 --- a/back/volume/src/auth/auth.module.ts +++ b/back/volume/src/auth/auth.module.ts @@ -1,23 +1,23 @@ -import { Module } from "@nestjs/common"; -import { UsersModule } from "src/users/users.module"; -import { PassportModule } from "@nestjs/passport"; -import { ConfigModule, ConfigService } from "@nestjs/config"; -import { AuthController } from "./auth.controller"; -import { FtStrategy } from "./42.strategy"; -import { SessionSerializer } from "./session.serializer"; -import { JwtModule } from "@nestjs/jwt"; -import { MailerModule } from "@nestjs-modules/mailer"; -import { AuthService } from "./auth.service"; -import { HandlebarsAdapter } from "@nestjs-modules/mailer/dist/adapters/handlebars.adapter"; +import { Module } from '@nestjs/common' +import { UsersModule } from 'src/users/users.module' +import { PassportModule } from '@nestjs/passport' +import { ConfigModule, ConfigService } from '@nestjs/config' +import { AuthController } from './auth.controller' +import { FtStrategy } from './42.strategy' +import { SessionSerializer } from './session.serializer' +import { JwtModule } from '@nestjs/jwt' +import { MailerModule } from '@nestjs-modules/mailer' +import { AuthService } from './auth.service' +import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter' const mailUser = - process.env.MAIL_USER !== null && process.env.MAIL_USER !== "" + process.env.MAIL_USER !== null && process.env.MAIL_USER !== '' ? process.env.MAIL_USER - : ""; + : '' const mailPass = - process.env.MAIL_PASSWORD !== null && process.env.MAIL_PASSWORD !== "" + process.env.MAIL_PASSWORD !== null && process.env.MAIL_PASSWORD !== '' ? process.env.MAIL_PASSWORD - : ""; + : '' @Module({ imports: [ @@ -26,29 +26,29 @@ const mailPass = ConfigModule.forRoot(), JwtModule.register({ secret: process.env.JWT_SECRET, - signOptions: { expiresIn: "60s" }, + signOptions: { expiresIn: '60s' } }), MailerModule.forRoot({ transport: { - service: "gmail", + service: 'gmail', auth: { user: mailUser, - pass: mailPass, - }, + pass: mailPass + } }, template: { - dir: "src/auth/mails", + dir: 'src/auth/mails', adapter: new HandlebarsAdapter(), options: { - strict: true, - }, + strict: true + } }, defaults: { - from: '"No Reply" vaganiwast@gmail.com', - }, - }), + from: '"No Reply" vaganiwast@gmail.com' + } + }) ], providers: [ConfigService, FtStrategy, SessionSerializer, AuthService], - controllers: [AuthController], + controllers: [AuthController] }) export class AuthModule {} diff --git a/back/volume/src/auth/auth.service.ts b/back/volume/src/auth/auth.service.ts index 21b0a8b..0db7907 100644 --- a/back/volume/src/auth/auth.service.ts +++ b/back/volume/src/auth/auth.service.ts @@ -1,48 +1,48 @@ -import { Injectable } from "@nestjs/common"; -import { type User } from "src/users/entity/user.entity"; -import { UsersService } from "src/users/users.service"; -import { MailerService } from "@nestjs-modules/mailer"; +import { Injectable } from '@nestjs/common' +import { type User } from 'src/users/entity/user.entity' +import { UsersService } from 'src/users/users.service' +import { MailerService } from '@nestjs-modules/mailer' @Injectable() export class AuthService { - constructor( + constructor ( private readonly usersService: UsersService, private readonly mailerService: MailerService ) {} - async sendConfirmedEmail(user: User): Promise { - const { email, username } = user; + async sendConfirmedEmail (user: User): Promise { + const { email, username } = user await this.mailerService.sendMail({ to: email, - subject: "Welcome to ft_transcendence! Email Confirmed", - template: "confirmed", + subject: 'Welcome to ft_transcendence! Email Confirmed', + template: 'confirmed', context: { username, - email, - }, - }); + email + } + }) } - async sendConfirmationEmail(user: User): Promise { - user.authToken = Math.floor(10000 + Math.random() * 90000).toString(); - await this.usersService.save(user); + async sendConfirmationEmail (user: User): Promise { + user.authToken = Math.floor(10000 + Math.random() * 90000).toString() + await this.usersService.save(user) await this.mailerService.sendMail({ to: user.email, - subject: "Welcome to ft_transcendence! Confirm Email", - template: "confirm", + subject: 'Welcome to ft_transcendence! Confirm Email', + template: 'confirm', context: { username: user.username, - code: user.authToken, - }, - }); + code: user.authToken + } + }) } - async verifyAccount(code: string): Promise { - const user = await this.usersService.findByCode(code); - user.authToken = ""; - user.isVerified = true; - await this.usersService.save(user); - await this.sendConfirmedEmail(user); - return true; + async verifyAccount (code: string): Promise { + const user = await this.usersService.findByCode(code) + user.authToken = '' + user.isVerified = true + await this.usersService.save(user) + await this.sendConfirmedEmail(user) + return true } } diff --git a/back/volume/src/auth/session.serializer.ts b/back/volume/src/auth/session.serializer.ts index d6c9fa0..7698561 100644 --- a/back/volume/src/auth/session.serializer.ts +++ b/back/volume/src/auth/session.serializer.ts @@ -1,20 +1,20 @@ -import { Injectable } from "@nestjs/common"; -import { PassportSerializer } from "@nestjs/passport"; -import { type Profile } from "passport-42"; +import { Injectable } from '@nestjs/common' +import { PassportSerializer } from '@nestjs/passport' +import { type Profile } from 'passport-42' @Injectable() export class SessionSerializer extends PassportSerializer { - serializeUser( + serializeUser ( user: Profile, done: (err: Error | null, user: Profile) => void ): any { - done(null, user); + done(null, user) } - deserializeUser( + deserializeUser ( payload: Profile, done: (err: Error | null, user: Profile) => void ): any { - done(null, payload); + done(null, payload) } } diff --git a/back/volume/src/chat/chat.controller.ts b/back/volume/src/chat/chat.controller.ts index e487885..2c2576c 100644 --- a/back/volume/src/chat/chat.controller.ts +++ b/back/volume/src/chat/chat.controller.ts @@ -7,211 +7,211 @@ import { NotFoundException, Param, Post, - UseGuards, -} from "@nestjs/common"; -import { AuthenticatedGuard } from "src/auth/42-auth.guard"; -import { UsersService } from "src/users/users.service"; -import { ChatService } from "./chat.service"; + UseGuards +} from '@nestjs/common' +import { AuthenticatedGuard } from 'src/auth/42-auth.guard' +import { UsersService } from 'src/users/users.service' +import { ChatService } from './chat.service' -import { CreateChannelDto } from "./dto/create-channel.dto"; -import { IdDto, PasswordDto, MuteDto } from "./dto/updateUser.dto"; +import { CreateChannelDto } from './dto/create-channel.dto' +import { IdDto, PasswordDto, MuteDto } from './dto/updateUser.dto' -import type User from "src/users/entity/user.entity"; -import type Channel from "./entity/channel.entity"; -import { Profile42 } from "src/auth/42.decorator"; -import { Profile } from "passport-42"; +import type User from 'src/users/entity/user.entity' +import type Channel from './entity/channel.entity' +import { Profile42 } from 'src/auth/42.decorator' +import { Profile } from 'passport-42' -@Controller("channels") +@Controller('channels') export class ChatController { - constructor( + constructor ( private readonly channelService: ChatService, private readonly usersService: UsersService ) {} - @Post(":id/invite") + @Post(':id/invite') @UseGuards(AuthenticatedGuard) - async addUser( - @Param("id") id: number, + async addUser ( + @Param('id') id: number, @Body() target: IdDto, @Profile42() profile: Profile ) { - const channel = await this.channelService.getFullChannel(id); - const user: User | null = await this.usersService.findUser(target.id); + const channel = await this.channelService.getFullChannel(id) + const user: User | null = await this.usersService.findUser(target.id) if (user == null) { - throw new NotFoundException(`User #${target.id} not found`); + throw new NotFoundException(`User #${target.id} not found`) } if (!(await this.channelService.isUser(channel.id, +profile.id))) { throw new BadRequestException( - "You are not allowed to invite users to this channel" - ); + 'You are not allowed to invite users to this channel' + ) } if (await this.channelService.isUser(channel.id, target.id)) { - throw new BadRequestException("User is already in this channel"); + throw new BadRequestException('User is already in this channel') } if (await this.channelService.isBanned(channel.id, target.id)) { - throw new BadRequestException("User is banned from this channel"); + throw new BadRequestException('User is banned from this channel') } - channel.users.push(user); - this.channelService.save(channel); + channel.users.push(user) + this.channelService.save(channel) } - @Delete(":id/kick") + @Delete(':id/kick') @UseGuards(AuthenticatedGuard) - async removeUser( - @Param("id") id: number, + async removeUser ( + @Param('id') id: number, @Body() target: IdDto, @Profile42() profile: Profile ) { - const channel = await this.channelService.getFullChannel(id); + const channel = await this.channelService.getFullChannel(id) if (!(await this.channelService.isAdmin(channel.id, +profile.id))) { throw new BadRequestException( - "You are not allowed to kick users from this channel" - ); + 'You are not allowed to kick users from this channel' + ) } if (!(await this.channelService.isUser(channel.id, target.id))) { - throw new BadRequestException("User is not in this channel"); + throw new BadRequestException('User is not in this channel') } if (await this.channelService.isOwner(channel.id, target.id)) { - throw new BadRequestException("You cannot kick the owner of the channel"); + throw new BadRequestException('You cannot kick the owner of the channel') } channel.users = channel.users.filter((usr: User) => { - return usr.ftId !== target.id; - }); - this.channelService.save(channel); + return usr.ftId !== target.id + }) + this.channelService.save(channel) } - @Post(":id/admin") + @Post(':id/admin') @UseGuards(AuthenticatedGuard) - async addAdmin( - @Param("id") id: number, + async addAdmin ( + @Param('id') id: number, @Body() target: IdDto, @Profile42() profile: Profile ) { - const channel = await this.channelService.getFullChannel(id); - const user: User | null = await this.usersService.findUser(target.id); + const channel = await this.channelService.getFullChannel(id) + const user: User | null = await this.usersService.findUser(target.id) if (user == null) { - throw new NotFoundException(`User #${target.id} not found`); + throw new NotFoundException(`User #${target.id} not found`) } if (!(await this.channelService.isOwner(channel.id, +profile.id))) { - throw new BadRequestException("You are not the owner of this channel"); + throw new BadRequestException('You are not the owner of this channel') } if (!(await this.channelService.isUser(channel.id, target.id))) { - throw new BadRequestException("User is not in this channel"); + throw new BadRequestException('User is not in this channel') } if (await this.channelService.isAdmin(channel.id, target.id)) { - throw new BadRequestException("User is already an admin of this channel"); + throw new BadRequestException('User is already an admin of this channel') } - channel.admins.push(user); - this.channelService.save(channel); + channel.admins.push(user) + this.channelService.save(channel) } - @Delete(":id/admin") + @Delete(':id/admin') @UseGuards(AuthenticatedGuard) - async removeAdmin( - @Param("id") id: number, + async removeAdmin ( + @Param('id') id: number, @Body() target: IdDto, @Profile42() profile: Profile ) { - const channel = await this.channelService.getFullChannel(id); + const channel = await this.channelService.getFullChannel(id) if (!(await this.channelService.isOwner(channel.id, +profile.id))) { - throw new BadRequestException("You are not the owner of this channel"); + throw new BadRequestException('You are not the owner of this channel') } if (!(await this.channelService.isAdmin(channel.id, target.id))) { - throw new BadRequestException("User is not an admin of this channel"); + throw new BadRequestException('User is not an admin of this channel') } channel.admins = channel.admins.filter((usr: User) => { - return usr.ftId !== target.id; - }); - this.channelService.save(channel); + return usr.ftId !== target.id + }) + this.channelService.save(channel) } - @Post(":id/ban") + @Post(':id/ban') @UseGuards(AuthenticatedGuard) - async addBan( - @Param("id") id: number, + async addBan ( + @Param('id') id: number, @Body() target: IdDto, @Profile42() profile: Profile ) { - const channel = await this.channelService.getFullChannel(id); - const user: User | null = await this.usersService.findUser(target.id); + const channel = await this.channelService.getFullChannel(id) + const user: User | null = await this.usersService.findUser(target.id) if (user == null) { - throw new NotFoundException(`User #${target.id} not found`); + throw new NotFoundException(`User #${target.id} not found`) } if (!(await this.channelService.isAdmin(channel.id, +profile.id))) { throw new BadRequestException( - "You are not allowed to ban users from this channel" - ); + 'You are not allowed to ban users from this channel' + ) } if (await this.channelService.isOwner(channel.id, target.id)) { - throw new BadRequestException("You cannot ban the owner of the channel"); + throw new BadRequestException('You cannot ban the owner of the channel') } if (await this.channelService.isBanned(channel.id, target.id)) { - throw new BadRequestException("User is already banned from this channel"); + throw new BadRequestException('User is already banned from this channel') } - channel.banned.push(user); - this.channelService.save(channel); + channel.banned.push(user) + this.channelService.save(channel) } - @Post(":id/mute") + @Post(':id/mute') @UseGuards(AuthenticatedGuard) - async addMute( - @Param("id") id: number, + async addMute ( + @Param('id') id: number, @Body() mute: MuteDto, // [userId, duration] @Profile42() profile: Profile ) { - const channel = await this.channelService.getFullChannel(id); - const user: User | null = await this.usersService.findUser(mute.data[0]); + const channel = await this.channelService.getFullChannel(id) + const user: User | null = await this.usersService.findUser(mute.data[0]) if (user == null) { - throw new NotFoundException(`User #${mute.data[0]} not found`); + throw new NotFoundException(`User #${mute.data[0]} not found`) } if (!(await this.channelService.isAdmin(channel.id, +profile.id))) { throw new BadRequestException( - "You are not allowed to mute users from this channel" - ); + 'You are not allowed to mute users from this channel' + ) } if (await this.channelService.isOwner(channel.id, mute.data[0])) { - throw new BadRequestException("You cannot mute the owner of the channel"); + throw new BadRequestException('You cannot mute the owner of the channel') } if ( (await this.channelService.getMuteDuration(channel.id, mute.data[0])) > 0 ) { - throw new BadRequestException("User is already muted from this channel"); + throw new BadRequestException('User is already muted from this channel') } - const newMute: number[] = [mute.data[0], Date.now() + mute.data[1] * 1000]; - channel.muted.push(newMute); - this.channelService.save(channel); + const newMute: number[] = [mute.data[0], Date.now() + mute.data[1] * 1000] + channel.muted.push(newMute) + this.channelService.save(channel) } - @Delete(":id") + @Delete(':id') @UseGuards(AuthenticatedGuard) - async deleteChannel(@Profile42() profile: Profile, @Param("id") id: number) { + async deleteChannel (@Profile42() profile: Profile, @Param('id') id: number) { if (!(await this.channelService.isOwner(id, +profile.id))) { - throw new BadRequestException("You are not the owner of this channel"); + throw new BadRequestException('You are not the owner of this channel') } - await this.channelService.removeChannel(id); + await this.channelService.removeChannel(id) } - @Post(":id/password") + @Post(':id/password') @UseGuards(AuthenticatedGuard) - async updatePassword( - @Profile42() profile: Profile, - @Param("id") id: number, + async updatePassword ( + @Profile42() profile: Profile, + @Param('id') id: number, @Body() data: PasswordDto ) { if (await this.channelService.isOwner(id, +profile.id)) { - throw new BadRequestException("You are not the owner of this channel"); + throw new BadRequestException('You are not the owner of this channel') } - await this.channelService.updatePassword(id, data.password); + await this.channelService.updatePassword(id, data.password) } @Get() @UseGuards(AuthenticatedGuard) - async getChannelsForUser(@Profile42() profile: Profile): Promise { - return await this.channelService.getChannelsForUser(+profile.id); + async getChannelsForUser (@Profile42() profile: Profile): Promise { + return await this.channelService.getChannelsForUser(+profile.id) } @Post() - async createChannel(@Body() channel: CreateChannelDto) { - return await this.channelService.createChannel(channel); + async createChannel (@Body() channel: CreateChannelDto) { + return await this.channelService.createChannel(channel) } } diff --git a/back/volume/src/chat/chat.gateway.ts b/back/volume/src/chat/chat.gateway.ts index 8904838..141d8cd 100644 --- a/back/volume/src/chat/chat.gateway.ts +++ b/back/volume/src/chat/chat.gateway.ts @@ -4,31 +4,31 @@ import { SubscribeMessage, WebSocketGateway, WebSocketServer, - WsException, -} from "@nestjs/websockets"; -import { Socket, Server } from "socket.io"; + WsException +} from '@nestjs/websockets' +import { Socket, Server } from 'socket.io' // import { User } from 'users/user.entity'; -import { UsersService } from "src/users/users.service"; -import { BadRequestException } from "@nestjs/common"; -import { ChatService } from "./chat.service"; -import type Message from "./entity/message.entity"; -import * as bcrypt from "bcrypt"; -import { MessageService } from "./message.service"; -import { type User } from "src/users/entity/user.entity"; -import { CreateMessageDto } from "./dto/create-message.dto"; -import { InjectRepository } from "@nestjs/typeorm"; -import { Repository } from "typeorm"; -import ConnectedUser from "./entity/connection.entity"; -import { ConnectionDto } from "./dto/connection.dto"; +import { UsersService } from 'src/users/users.service' +import { BadRequestException } from '@nestjs/common' +import { ChatService } from './chat.service' +import type Message from './entity/message.entity' +import * as bcrypt from 'bcrypt' +import { MessageService } from './message.service' +import { type User } from 'src/users/entity/user.entity' +import { CreateMessageDto } from './dto/create-message.dto' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import ConnectedUser from './entity/connection.entity' +import { ConnectionDto } from './dto/connection.dto' @WebSocketGateway({ - cors: { origin: /^(http|ws):\/\/localhost(:\d+)?$/ }, + cors: { origin: /^(http|ws):\/\/localhost(:\d+)?$/ } }) export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect { @WebSocketServer() - server: Server; + server: Server - constructor( + constructor ( private readonly userService: UsersService, private readonly messageService: MessageService, private readonly chatService: ChatService, @@ -36,7 +36,7 @@ export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect { private readonly connectedUserRepository: Repository ) {} - async handleConnection(socket: Socket): Promise { + async handleConnection (socket: Socket): Promise { // console.log(socket.handshake.headers) // const cookie = socket.handshake.headers.cookie as string // const { authentication: authenticationToken } = parse(cookie) @@ -49,76 +49,76 @@ export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect { // return user } - handleDisconnect(socket: Socket): void { - socket.disconnect(); + handleDisconnect (socket: Socket): void { + socket.disconnect() } - @SubscribeMessage("joinChannel") - async onJoinChannel(socket: Socket, connect: ConnectionDto): Promise { - const channel = await this.chatService.getChannel(connect.ChannelId); + @SubscribeMessage('joinChannel') + async onJoinChannel (socket: Socket, connect: ConnectionDto): Promise { + const channel = await this.chatService.getChannel(connect.ChannelId) if (channel.banned.find((e) => e.id == connect.UserId) != null) { - throw new WsException("You are banned from entering this channel"); + throw new WsException('You are banned from entering this channel') } - const user = (await this.userService.findUser(connect.UserId)) as User; + const user = (await this.userService.findUser(connect.UserId)) as User if ( channel.users.find((e) => e.id === user.id) == null && - channel.password !== "" + channel.password !== '' ) { if (!(await bcrypt.compare(channel.password, connect.pwd))) { - throw new BadRequestException(); + throw new BadRequestException() } - } else await this.chatService.addUserToChannel(channel, user); + } else await this.chatService.addUserToChannel(channel, user) // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// { - const conUser = new ConnectedUser(); - conUser.user = user; - conUser.channel = channel; - conUser.socket = socket.id; - await this.connectedUserRepository.save(conUser); + const conUser = new ConnectedUser() + conUser.user = user + conUser.channel = channel + conUser.socket = socket.id + await this.connectedUserRepository.save(conUser) } const messages = await this.messageService.findMessagesInChannelForUser( channel, user - ); - this.server.to(socket.id).emit("messages", messages); - await socket.join(channel.name); + ) + this.server.to(socket.id).emit('messages', messages) + await socket.join(channel.name) } - @SubscribeMessage("leaveChannel") - async onLeaveChannel(socket: Socket): Promise { - const id = socket.id as any; - await this.connectedUserRepository.delete({ socket: id }); - socket.disconnect(); + @SubscribeMessage('leaveChannel') + async onLeaveChannel (socket: Socket): Promise { + const id = socket.id as any + await this.connectedUserRepository.delete({ socket: id }) + socket.disconnect() } - @SubscribeMessage("addMessage") - async onAddMessage(socket: Socket, message: CreateMessageDto): Promise { - const channel = await this.chatService.getChannel(message.ChannelId); + @SubscribeMessage('addMessage') + async onAddMessage (socket: Socket, message: CreateMessageDto): Promise { + const channel = await this.chatService.getChannel(message.ChannelId) if ( (await this.chatService.getMuteDuration(channel.id, message.UserId)) > 0 ) { - throw new WsException("You are muted"); + throw new WsException('You are muted') } const createdMessage: Message = await this.messageService.createMessage( message - ); - socket.in(channel.name).emit("newMessage", createdMessage); + ) + socket.in(channel.name).emit('newMessage', createdMessage) } - @SubscribeMessage("kickUser") - async onKickUser( + @SubscribeMessage('kickUser') + async onKickUser ( socket: Socket, chan: number, from: number, to: number ): Promise { - const channel = await this.chatService.getChannel(chan); + const channel = await this.chatService.getChannel(chan) if ( channel.owner.id !== from || channel.admins.find((e) => e.id === from) == null ) { - throw new WsException("You do not have the required privileges"); + throw new WsException('You do not have the required privileges') } - await this.onLeaveChannel(socket); + await this.onLeaveChannel(socket) } } diff --git a/back/volume/src/chat/chat.module.ts b/back/volume/src/chat/chat.module.ts index 4abae63..381ca03 100644 --- a/back/volume/src/chat/chat.module.ts +++ b/back/volume/src/chat/chat.module.ts @@ -1,25 +1,25 @@ -import { forwardRef, Module } from "@nestjs/common"; -import { TypeOrmModule } from "@nestjs/typeorm"; +import { forwardRef, Module } from '@nestjs/common' +import { TypeOrmModule } from '@nestjs/typeorm' -import { AuthModule } from "src/auth/auth.module"; -import { UsersModule } from "src/users/users.module"; -import { ChatGateway } from "./chat.gateway"; -import { ChatController } from "./chat.controller"; -import { ChatService } from "./chat.service"; -import { MessageService } from "./message.service"; +import { AuthModule } from 'src/auth/auth.module' +import { UsersModule } from 'src/users/users.module' +import { ChatGateway } from './chat.gateway' +import { ChatController } from './chat.controller' +import { ChatService } from './chat.service' +import { MessageService } from './message.service' -import Channel from "./entity/channel.entity"; -import Message from "./entity/message.entity"; -import ConnectedUser from "./entity/connection.entity"; +import Channel from './entity/channel.entity' +import Message from './entity/message.entity' +import ConnectedUser from './entity/connection.entity' @Module({ imports: [ UsersModule, AuthModule, - TypeOrmModule.forFeature([Channel, Message, ConnectedUser]), + TypeOrmModule.forFeature([Channel, Message, ConnectedUser]) ], controllers: [ChatController], providers: [ChatService, ChatGateway, MessageService], - exports: [ChatService], + exports: [ChatService] }) export class ChatModule {} diff --git a/back/volume/src/chat/chat.service.ts b/back/volume/src/chat/chat.service.ts index bfd25b6..2b05397 100644 --- a/back/volume/src/chat/chat.service.ts +++ b/back/volume/src/chat/chat.service.ts @@ -1,173 +1,173 @@ -import { Inject, Injectable, NotFoundException } from "@nestjs/common"; -import { InjectRepository } from "@nestjs/typeorm"; -import { Repository } from "typeorm"; +import { Inject, Injectable, NotFoundException } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' -import { type CreateChannelDto } from "./dto/create-channel.dto"; -import { UsersService } from "src/users/users.service"; +import { type CreateChannelDto } from './dto/create-channel.dto' +import { UsersService } from 'src/users/users.service' -import type User from "src/users/entity/user.entity"; -import Channel from "./entity/channel.entity"; -import { Cron } from "@nestjs/schedule"; +import type User from 'src/users/entity/user.entity' +import Channel from './entity/channel.entity' +import { Cron } from '@nestjs/schedule' @Injectable() export class ChatService { - constructor( + constructor ( @InjectRepository(Channel) private readonly ChannelRepository: Repository, private readonly usersService: UsersService ) {} - async createChannel(channel: CreateChannelDto): Promise { - const user: User | null = await this.usersService.findUser(channel.owner); + async createChannel (channel: CreateChannelDto): Promise { + const user: User | null = await this.usersService.findUser(channel.owner) if (user == null) { - throw new NotFoundException(`User #${channel.owner} not found`); + throw new NotFoundException(`User #${channel.owner} not found`) } - const newChannel = new Channel(); - newChannel.owner = user; - newChannel.users = [user]; - newChannel.admins = [user]; - newChannel.name = channel.name; - newChannel.isPrivate = channel.isPrivate; - newChannel.password = channel.password; - return await this.ChannelRepository.save(newChannel); + const newChannel = new Channel() + newChannel.owner = user + newChannel.users = [user] + newChannel.admins = [user] + newChannel.name = channel.name + newChannel.isPrivate = channel.isPrivate + newChannel.password = channel.password + return await this.ChannelRepository.save(newChannel) } - async updatePassword(id: number, password: string) { + async updatePassword (id: number, password: string) { const channel: Channel | null = await this.ChannelRepository.findOneBy({ - id, - }); + id + }) if (channel === null) { - throw new NotFoundException(`Channel #${id} not found`); + throw new NotFoundException(`Channel #${id} not found`) } - channel.password = password; - await this.ChannelRepository.save(channel); + channel.password = password + await this.ChannelRepository.save(channel) } - async getChannelsForUser(ftId: number): Promise { - let rooms: Channel[] = []; + async getChannelsForUser (ftId: number): Promise { + let rooms: Channel[] = [] rooms = [ - ...(await this.ChannelRepository.createQueryBuilder("room") - .where("room.isPrivate = false") - .getMany()), - ]; + ...(await this.ChannelRepository.createQueryBuilder('room') + .where('room.isPrivate = false') + .getMany()) + ] rooms = [ ...rooms, - ...(await this.ChannelRepository.createQueryBuilder("room") - .innerJoin("room.users", "users") - .where("room.isPrivate = true") - .andWhere("users.ftId = :ftId", { ftId }) - .getMany()), - ]; - return rooms; + ...(await this.ChannelRepository.createQueryBuilder('room') + .innerJoin('room.users', 'users') + .where('room.isPrivate = true') + .andWhere('users.ftId = :ftId', { ftId }) + .getMany()) + ] + return rooms } - @Cron("*/6 * * * * *") - async updateMutelists(): Promise { - const channels = await this.ChannelRepository.find({}); + @Cron('*/6 * * * * *') + async updateMutelists (): Promise { + const channels = await this.ChannelRepository.find({}) channels.forEach((channel) => { channel.muted = channel.muted.filter((data) => { - return data[0] - Date.now() > 0; - }); - this.ChannelRepository.save(channel); - }); + return data[0] - Date.now() > 0 + }) + this.ChannelRepository.save(channel) + }) } - async addUserToChannel(channel: Channel, user: User): Promise { - channel.owner = user; - return await this.ChannelRepository.save(channel); + async addUserToChannel (channel: Channel, user: User): Promise { + channel.owner = user + return await this.ChannelRepository.save(channel) } - async getChannel(id: number): Promise { - const channel = await this.ChannelRepository.findOneBy({ id }); + async getChannel (id: number): Promise { + const channel = await this.ChannelRepository.findOneBy({ id }) if (channel == null) { - throw new NotFoundException(`Channel #${id} not found`); + throw new NotFoundException(`Channel #${id} not found`) } - return channel; + return channel } - async getFullChannel(id: number): Promise { + async getFullChannel (id: number): Promise { const channel = await this.ChannelRepository.findOne({ where: { id }, - relations: ["users", "admins", "banned", "muted", "owner"], - }); + relations: ['users', 'admins', 'banned', 'muted', 'owner'] + }) if (channel == null) { - throw new NotFoundException(`Channel #${id} not found`); + throw new NotFoundException(`Channel #${id} not found`) } - return channel; + return channel } - async update(channel: Channel) { - await this.ChannelRepository.update(channel.id, channel); + async update (channel: Channel) { + await this.ChannelRepository.update(channel.id, channel) } - async save(channel: Channel) { - await this.ChannelRepository.save(channel); + async save (channel: Channel) { + await this.ChannelRepository.save(channel) } - async removeChannel(channelId: number) { - await this.ChannelRepository.delete(channelId); + async removeChannel (channelId: number) { + await this.ChannelRepository.delete(channelId) } - async isOwner(id: number, userId: number): Promise { + async isOwner (id: number, userId: number): Promise { const channel = await this.ChannelRepository.findOne({ where: { id }, - relations: { owner: true }, - }); + relations: { owner: true } + }) if (channel == null) { - throw new NotFoundException(`Channel #${id} not found`); + throw new NotFoundException(`Channel #${id} not found`) } - return channel.owner.ftId === userId; + return channel.owner.ftId === userId } - async isAdmin(id: number, userId: number): Promise { + async isAdmin (id: number, userId: number): Promise { const channel = await this.ChannelRepository.findOne({ where: { id }, - relations: { admins: true }, - }); + relations: { admins: true } + }) if (channel == null) { - throw new NotFoundException(`Channel #${id} not found`); + throw new NotFoundException(`Channel #${id} not found`) } - return channel.admins.findIndex((user) => user.ftId === userId) != -1; + return channel.admins.findIndex((user) => user.ftId === userId) != -1 } - async isUser(id: number, userId: number): Promise { + async isUser (id: number, userId: number): Promise { const channel = await this.ChannelRepository.findOne({ where: { id }, - relations: { users: true }, - }); + relations: { users: true } + }) if (channel == null) { - throw new NotFoundException(`Channel #${id} not found`); + throw new NotFoundException(`Channel #${id} not found`) } - return channel.users.findIndex((user) => user.ftId === userId) != -1; + return channel.users.findIndex((user) => user.ftId === userId) != -1 } - async isBanned(id: number, userId: number): Promise { + async isBanned (id: number, userId: number): Promise { const channel = await this.ChannelRepository.findOne({ where: { id }, - relations: { banned: true }, - }); + relations: { banned: true } + }) if (channel == null) { - throw new NotFoundException(`Channel #${id} not found`); + throw new NotFoundException(`Channel #${id} not found`) } - return channel.banned.findIndex((user) => user.ftId === userId) != -1; + return channel.banned.findIndex((user) => user.ftId === userId) != -1 } - async getMuteDuration(id: number, userId: number): Promise { + async getMuteDuration (id: number, userId: number): Promise { const channel = await this.ChannelRepository.findOne({ where: { id }, - relations: { muted: true }, - }); + relations: { muted: true } + }) if (channel == null) { - throw new NotFoundException(`Channel #${id} not found`); + throw new NotFoundException(`Channel #${id} not found`) } const mutation: number[] | undefined = channel.muted.find( (mutation) => mutation[0] === userId - ); + ) if (mutation == null) { - return 0; + return 0 } - return mutation[1]; + return mutation[1] } } diff --git a/back/volume/src/chat/dto/connection.dto.ts b/back/volume/src/chat/dto/connection.dto.ts index 551e545..c70f38c 100644 --- a/back/volume/src/chat/dto/connection.dto.ts +++ b/back/volume/src/chat/dto/connection.dto.ts @@ -1,13 +1,13 @@ -import { IsNumber, IsOptional, IsString } from "class-validator"; +import { IsNumber, IsOptional, IsString } from 'class-validator' export class ConnectionDto { @IsNumber() - UserId: number; + UserId: number @IsNumber() - ChannelId: number; + ChannelId: number @IsString() @IsOptional() - pwd: string; + pwd: string } diff --git a/back/volume/src/chat/dto/create-channel.dto.ts b/back/volume/src/chat/dto/create-channel.dto.ts index 042e6ce..af1f03a 100644 --- a/back/volume/src/chat/dto/create-channel.dto.ts +++ b/back/volume/src/chat/dto/create-channel.dto.ts @@ -1,28 +1,28 @@ -import { Transform } from "class-transformer"; +import { Transform } from 'class-transformer' import { IsPositive, IsAlpha, IsString, IsOptional, IsNumber, - IsBoolean, -} from "class-validator"; + IsBoolean +} from 'class-validator' export class CreateChannelDto { @IsOptional() @IsPositive() - id: number; + id: number @IsString() - name: string; + name: string @IsNumber() - owner: number; + owner: number @IsOptional() - password: string; + password: string @IsBoolean() - @Transform(({ value }) => value === "true") - isPrivate: boolean; + @Transform(({ value }) => value === 'true') + isPrivate: boolean } diff --git a/back/volume/src/chat/dto/create-message.dto.ts b/back/volume/src/chat/dto/create-message.dto.ts index 167d1ea..56419a0 100644 --- a/back/volume/src/chat/dto/create-message.dto.ts +++ b/back/volume/src/chat/dto/create-message.dto.ts @@ -1,12 +1,12 @@ -import { IsNumber, IsString } from "class-validator"; +import { IsNumber, IsString } from 'class-validator' export class CreateMessageDto { @IsString() - text: string; + text: string @IsNumber() - UserId: number; + UserId: number @IsNumber() - ChannelId: number; + ChannelId: number } diff --git a/back/volume/src/chat/dto/update-channel.dto.ts b/back/volume/src/chat/dto/update-channel.dto.ts index 6b4da58..c9cb3a3 100644 --- a/back/volume/src/chat/dto/update-channel.dto.ts +++ b/back/volume/src/chat/dto/update-channel.dto.ts @@ -1,30 +1,30 @@ -import { PartialType } from "@nestjs/mapped-types"; -import { CreateChannelDto } from "./create-channel.dto"; -import { IsNumber, IsOptional, IsString } from "class-validator"; +import { PartialType } from '@nestjs/mapped-types' +import { CreateChannelDto } from './create-channel.dto' +import { IsNumber, IsOptional, IsString } from 'class-validator' export class UpdateChannelDto extends PartialType(CreateChannelDto) { - id: number; + id: number @IsOptional() @IsNumber() - users: [number]; + users: [number] @IsOptional() @IsNumber() - messages: [number]; + messages: [number] @IsOptional() @IsNumber() - owners: [number]; // user id + owners: [number] // user id @IsOptional() @IsNumber() - banned: [number]; // user id + banned: [number] // user id @IsOptional() @IsNumber() - muted: [number]; // user id + muted: [number] // user id @IsString() @IsOptional() - password: string; + password: string } diff --git a/back/volume/src/chat/dto/updateUser.dto.ts b/back/volume/src/chat/dto/updateUser.dto.ts index f1ef1b9..d857de0 100644 --- a/back/volume/src/chat/dto/updateUser.dto.ts +++ b/back/volume/src/chat/dto/updateUser.dto.ts @@ -1,15 +1,15 @@ -import { IsNumber, IsString } from "class-validator"; +import { IsNumber, IsString } from 'class-validator' export class IdDto { @IsNumber() - id: number; + id: number } export class PasswordDto { @IsString() - password: string; + password: string } export class MuteDto { - data: number[]; + data: number[] } diff --git a/back/volume/src/chat/entity/channel.entity.ts b/back/volume/src/chat/entity/channel.entity.ts index 4b9ecc9..dac1dcd 100644 --- a/back/volume/src/chat/entity/channel.entity.ts +++ b/back/volume/src/chat/entity/channel.entity.ts @@ -8,54 +8,54 @@ import { ManyToOne, OneToMany, OneToOne, - PrimaryGeneratedColumn, -} from "typeorm"; -import User from "src/users/entity/user.entity"; -import Message from "./message.entity"; -import * as bcrypt from "bcrypt"; + PrimaryGeneratedColumn +} from 'typeorm' +import User from 'src/users/entity/user.entity' +import Message from './message.entity' +import * as bcrypt from 'bcrypt' @Entity() export default class Channel { @PrimaryGeneratedColumn() - id: number; + id: number @Column() - name: string; + name: string @Column({ default: false }) - isPrivate: boolean; + isPrivate: boolean - @Column({ select: false, default: "" }) - password: string; + @Column({ select: false, default: '' }) + password: string @BeforeInsert() - async hashPassword() { - if (this.password === "") return; + async hashPassword () { + if (this.password === '') return this.password = await bcrypt.hash( this.password, Number(process.env.HASH_SALT) - ); + ) } @ManyToMany(() => User) @JoinTable() - users: User[]; + users: User[] @OneToMany(() => Message, (message: Message) => message.channel) - messages: Message[]; + messages: Message[] @ManyToOne(() => User) @JoinColumn() - owner: User; + owner: User @ManyToMany(() => User) @JoinTable() - admins: User[]; + admins: User[] @ManyToMany(() => User) // refuse connection @JoinTable() - banned: User[]; + banned: User[] - @Column("text", { array: true }) - muted: number[][]; + @Column('text', { array: true }) + muted: number[][] } diff --git a/back/volume/src/chat/entity/connection.entity.ts b/back/volume/src/chat/entity/connection.entity.ts index 16dc4d0..afe45e8 100644 --- a/back/volume/src/chat/entity/connection.entity.ts +++ b/back/volume/src/chat/entity/connection.entity.ts @@ -3,21 +3,21 @@ import { Entity, JoinColumn, OneToOne, - PrimaryGeneratedColumn, -} from "typeorm"; + PrimaryGeneratedColumn +} from 'typeorm' -import Channel from "./channel.entity"; -import User from "src/users/entity/user.entity"; +import Channel from './channel.entity' +import User from 'src/users/entity/user.entity' @Entity() export default class ConnectedUser { @OneToOne(() => User) - user: User; + user: User @OneToOne(() => Channel) @JoinColumn() - channel: Channel; + channel: Channel @PrimaryGeneratedColumn() - socket: string; + socket: string } diff --git a/back/volume/src/chat/entity/dm.entity.ts b/back/volume/src/chat/entity/dm.entity.ts index 9181791..d1a344c 100644 --- a/back/volume/src/chat/entity/dm.entity.ts +++ b/back/volume/src/chat/entity/dm.entity.ts @@ -1,15 +1,15 @@ -import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm"; -import Message from "./message.entity"; -import type User from "src/users/entity/user.entity"; +import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm' +import Message from './message.entity' +import type User from 'src/users/entity/user.entity' @Entity() export class Channel { @PrimaryGeneratedColumn() - id: number; + id: number @Column() - users: User[]; + users: User[] @OneToMany(() => Message, (message) => message.channel) - messages: Message[]; + messages: Message[] } diff --git a/back/volume/src/chat/entity/message.entity.ts b/back/volume/src/chat/entity/message.entity.ts index c705c23..e44b4a3 100644 --- a/back/volume/src/chat/entity/message.entity.ts +++ b/back/volume/src/chat/entity/message.entity.ts @@ -5,27 +5,27 @@ import { JoinColumn, JoinTable, ManyToOne, - PrimaryGeneratedColumn, -} from "typeorm"; -import User from "src/users/entity/user.entity"; -import Channel from "./channel.entity"; + PrimaryGeneratedColumn +} from 'typeorm' +import User from 'src/users/entity/user.entity' +import Channel from './channel.entity' @Entity() export default class Message { @PrimaryGeneratedColumn() - id: number; + id: number @Column() - text: string; + text: string @ManyToOne(() => User) @JoinColumn() - author: User; + author: User @ManyToOne(() => Channel, (channel) => channel.messages, { cascade: true }) @JoinTable() - channel: Channel; + channel: Channel @CreateDateColumn() - created_at: Date; + created_at: Date } diff --git a/back/volume/src/chat/message.service.ts b/back/volume/src/chat/message.service.ts index d329e24..6f08684 100644 --- a/back/volume/src/chat/message.service.ts +++ b/back/volume/src/chat/message.service.ts @@ -1,43 +1,43 @@ -import { Injectable } from "@nestjs/common"; -import { InjectRepository } from "@nestjs/typeorm"; -import { Repository } from "typeorm"; -import { ChatService } from "./chat.service"; -import { UsersService } from "src/users/users.service"; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { ChatService } from './chat.service' +import { UsersService } from 'src/users/users.service' -import { type CreateMessageDto } from "./dto/create-message.dto"; -import type User from "src/users/entity/user.entity"; -import type Channel from "./entity/channel.entity"; -import Message from "./entity/message.entity"; +import { type CreateMessageDto } from './dto/create-message.dto' +import type User from 'src/users/entity/user.entity' +import type Channel from './entity/channel.entity' +import Message from './entity/message.entity' @Injectable() export class MessageService { - constructor( + constructor ( @InjectRepository(Message) private readonly MessageRepository: Repository, private readonly channelService: ChatService, private readonly usersService: UsersService ) {} - async createMessage(message: CreateMessageDto): Promise { - const msg = new Message(); - msg.text = message.text; - msg.channel = await this.channelService.getChannel(message.ChannelId); - msg.author = (await this.usersService.findUser(message.UserId)) as User; - msg.channel.messages.push(msg); + async createMessage (message: CreateMessageDto): Promise { + const msg = new Message() + msg.text = message.text + msg.channel = await this.channelService.getChannel(message.ChannelId) + msg.author = (await this.usersService.findUser(message.UserId)) as User + msg.channel.messages.push(msg) return await this.MessageRepository.save( this.MessageRepository.create(msg) - ); + ) } - async findMessagesInChannelForUser( + async findMessagesInChannelForUser ( channel: Channel, user: User ): Promise { - return await this.MessageRepository.createQueryBuilder("message") - .where("message.channel = :chan", { chan: channel }) - .andWhere("message.author NOT IN (:...blocked)", { - blocked: user.blocked, + return await this.MessageRepository.createQueryBuilder('message') + .where('message.channel = :chan', { chan: channel }) + .andWhere('message.author NOT IN (:...blocked)', { + blocked: user.blocked }) - .getMany(); + .getMany() } } diff --git a/back/volume/src/main.ts b/back/volume/src/main.ts index dc87b9d..88efdea 100644 --- a/back/volume/src/main.ts +++ b/back/volume/src/main.ts @@ -1,45 +1,45 @@ -import { InternalServerErrorException, Logger } from "@nestjs/common"; -import { NestFactory } from "@nestjs/core"; -import { AppModule } from "./app.module"; -import * as session from "express-session"; -import * as passport from "passport"; -import { type NestExpressApplication } from "@nestjs/platform-express"; -import * as cookieParser from "cookie-parser"; -import { IoAdapter } from "@nestjs/platform-socket.io"; +import { InternalServerErrorException, Logger } from '@nestjs/common' +import { NestFactory } from '@nestjs/core' +import { AppModule } from './app.module' +import * as session from 'express-session' +import * as passport from 'passport' +import { type NestExpressApplication } from '@nestjs/platform-express' +import * as cookieParser from 'cookie-parser' +import { IoAdapter } from '@nestjs/platform-socket.io' -async function bootstrap(): Promise { - const logger = new Logger(); - const app = await NestFactory.create(AppModule); +async function bootstrap (): Promise { + const logger = new Logger() + const app = await NestFactory.create(AppModule) const port = - process.env.BACK_PORT !== undefined && process.env.BACK_PORT !== "" + process.env.BACK_PORT !== undefined && process.env.BACK_PORT !== '' ? +process.env.BACK_PORT - : 3001; + : 3001 const cors = { origin: /^(http|ws):\/\/localhost(:\d+)?$/, - methods: "GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS", + methods: 'GET, HEAD, PUT, PATCH, POST, DELETE, OPTIONS', preflightContinue: false, optionsSuccessStatus: 204, credentials: true, - allowedHeaders: ["Accept", "Content-Type", "Authorization"], - }; + allowedHeaders: ['Accept', 'Content-Type', 'Authorization'] + } app.use( session({ resave: false, saveUninitialized: false, secret: - process.env.JWT_SECRET !== undefined && process.env.JWT_SECRET !== "" + process.env.JWT_SECRET !== undefined && process.env.JWT_SECRET !== '' ? process.env.JWT_SECRET - : "secret", + : 'secret' }) - ); - app.use(cookieParser()); - app.use(passport.initialize()); - app.use(passport.session()); - app.enableCors(cors); - app.useWebSocketAdapter(new IoAdapter(app)); - await app.listen(port); - logger.log(`Application listening on port ${port}`); + ) + app.use(cookieParser()) + app.use(passport.initialize()) + app.use(passport.session()) + app.enableCors(cors) + app.useWebSocketAdapter(new IoAdapter(app)) + await app.listen(port) + logger.log(`Application listening on port ${port}`) } bootstrap().catch((e) => { - throw new InternalServerErrorException(e); -}); + throw new InternalServerErrorException(e) +}) diff --git a/back/volume/src/pong/dtos/GameCreationDtoValidated.ts b/back/volume/src/pong/dtos/GameCreationDtoValidated.ts index d68bbac..3b55da4 100644 --- a/back/volume/src/pong/dtos/GameCreationDtoValidated.ts +++ b/back/volume/src/pong/dtos/GameCreationDtoValidated.ts @@ -1,4 +1,4 @@ -import { Type } from "class-transformer"; +import { Type } from 'class-transformer' import { ArrayMaxSize, ArrayMinSize, @@ -7,32 +7,32 @@ import { IsString, Max, Min, - ValidateNested, -} from "class-validator"; + ValidateNested +} from 'class-validator' import { DEFAULT_BALL_INITIAL_SPEED, - DEFAULT_MAX_BALL_SPEED, -} from "../game/constants"; -import { MapDtoValidated } from "./MapDtoValidated"; + DEFAULT_MAX_BALL_SPEED +} from '../game/constants' +import { MapDtoValidated } from './MapDtoValidated' export class GameCreationDtoValidated { @IsString({ each: true }) @ArrayMaxSize(2) @ArrayMinSize(2) - playerNames!: string[]; + playerNames!: string[] @IsNotEmptyObject() @ValidateNested() @Type(() => MapDtoValidated) - map!: MapDtoValidated; + map!: MapDtoValidated @IsNumber() @Min(DEFAULT_BALL_INITIAL_SPEED.x) @Max(DEFAULT_MAX_BALL_SPEED.x) - initialBallSpeedX!: number; + initialBallSpeedX!: number @IsNumber() @Min(DEFAULT_BALL_INITIAL_SPEED.y) @Max(DEFAULT_MAX_BALL_SPEED.y) - initialBallSpeedY!: number; + initialBallSpeedY!: number } diff --git a/back/volume/src/pong/dtos/GameInfo.ts b/back/volume/src/pong/dtos/GameInfo.ts index 818246e..95f36f7 100644 --- a/back/volume/src/pong/dtos/GameInfo.ts +++ b/back/volume/src/pong/dtos/GameInfo.ts @@ -1,12 +1,12 @@ -import { type Point, type Rect } from "../game/utils"; +import { type Point, type Rect } from '../game/utils' export class GameInfo { - mapSize!: Point; - yourPaddleIndex!: number; - gameId!: string; - walls!: Rect[]; - paddleSize!: Point; - ballSize!: Point; - winScore!: number; - ranked!: boolean; + mapSize!: Point + yourPaddleIndex!: number + gameId!: string + walls!: Rect[] + paddleSize!: Point + ballSize!: Point + winScore!: number + ranked!: boolean } diff --git a/back/volume/src/pong/dtos/GameUpdate.ts b/back/volume/src/pong/dtos/GameUpdate.ts index d291400..4804119 100644 --- a/back/volume/src/pong/dtos/GameUpdate.ts +++ b/back/volume/src/pong/dtos/GameUpdate.ts @@ -1,8 +1,8 @@ -import { type Point } from "../game/utils"; +import { type Point } from '../game/utils' export class GameUpdate { - paddlesPositions!: Point[]; - ballSpeed!: Point; - ballPosition!: Point; - scores!: number[]; + paddlesPositions!: Point[] + ballSpeed!: Point + ballPosition!: Point + scores!: number[] } diff --git a/back/volume/src/pong/dtos/MapDtoValidated.ts b/back/volume/src/pong/dtos/MapDtoValidated.ts index bc6115c..716e883 100644 --- a/back/volume/src/pong/dtos/MapDtoValidated.ts +++ b/back/volume/src/pong/dtos/MapDtoValidated.ts @@ -1,23 +1,23 @@ -import { Type } from "class-transformer"; +import { Type } from 'class-transformer' import { ArrayMaxSize, IsArray, IsDefined, IsObject, - ValidateNested, -} from "class-validator"; -import { PointDtoValidated } from "./PointDtoValidated"; -import { RectDtoValidated } from "./RectDtoValidated"; + ValidateNested +} from 'class-validator' +import { PointDtoValidated } from './PointDtoValidated' +import { RectDtoValidated } from './RectDtoValidated' export class MapDtoValidated { @IsObject() @IsDefined() @Type(() => PointDtoValidated) - size!: PointDtoValidated; + size!: PointDtoValidated @IsArray() @ArrayMaxSize(5) @ValidateNested({ each: true }) @Type(() => RectDtoValidated) - walls!: RectDtoValidated[]; + walls!: RectDtoValidated[] } diff --git a/back/volume/src/pong/dtos/MatchmakingDto.ts b/back/volume/src/pong/dtos/MatchmakingDto.ts index 0d8b6ea..580c222 100644 --- a/back/volume/src/pong/dtos/MatchmakingDto.ts +++ b/back/volume/src/pong/dtos/MatchmakingDto.ts @@ -1,3 +1,3 @@ export class MatchmakingDto { - matchmaking!: boolean; + matchmaking!: boolean } diff --git a/back/volume/src/pong/dtos/MatchmakingDtoValidated.ts b/back/volume/src/pong/dtos/MatchmakingDtoValidated.ts index 048befe..d83286c 100644 --- a/back/volume/src/pong/dtos/MatchmakingDtoValidated.ts +++ b/back/volume/src/pong/dtos/MatchmakingDtoValidated.ts @@ -1,7 +1,7 @@ -import { IsBoolean } from "class-validator"; -import { MatchmakingDto } from "./MatchmakingDto"; +import { IsBoolean } from 'class-validator' +import { MatchmakingDto } from './MatchmakingDto' export class MatchmakingDtoValidated extends MatchmakingDto { @IsBoolean() - matchmaking!: boolean; + matchmaking!: boolean } diff --git a/back/volume/src/pong/dtos/PointDtoValidated.ts b/back/volume/src/pong/dtos/PointDtoValidated.ts index 49405ea..8a8cbf6 100644 --- a/back/volume/src/pong/dtos/PointDtoValidated.ts +++ b/back/volume/src/pong/dtos/PointDtoValidated.ts @@ -1,10 +1,10 @@ -import { IsNumber } from "class-validator"; -import { Point } from "../game/utils"; +import { IsNumber } from 'class-validator' +import { Point } from '../game/utils' export class PointDtoValidated extends Point { @IsNumber() - x!: number; + x!: number @IsNumber() - y!: number; + y!: number } diff --git a/back/volume/src/pong/dtos/RectDtoValidated.ts b/back/volume/src/pong/dtos/RectDtoValidated.ts index fec9f6d..d24a682 100644 --- a/back/volume/src/pong/dtos/RectDtoValidated.ts +++ b/back/volume/src/pong/dtos/RectDtoValidated.ts @@ -1,14 +1,14 @@ -import { Type } from "class-transformer"; -import { ValidateNested } from "class-validator"; -import { Rect } from "../game/utils"; -import { PointDtoValidated } from "./PointDtoValidated"; +import { Type } from 'class-transformer' +import { ValidateNested } from 'class-validator' +import { Rect } from '../game/utils' +import { PointDtoValidated } from './PointDtoValidated' export class RectDtoValidated extends Rect { @ValidateNested() @Type(() => PointDtoValidated) - center!: PointDtoValidated; + center!: PointDtoValidated @ValidateNested() @Type(() => PointDtoValidated) - size!: PointDtoValidated; + size!: PointDtoValidated } diff --git a/back/volume/src/pong/dtos/StringDto.ts b/back/volume/src/pong/dtos/StringDto.ts index 1aa81ce..62283b6 100644 --- a/back/volume/src/pong/dtos/StringDto.ts +++ b/back/volume/src/pong/dtos/StringDto.ts @@ -1,3 +1,3 @@ export class StringDto { - value!: string; + value!: string } diff --git a/back/volume/src/pong/dtos/StringDtoValidated.ts b/back/volume/src/pong/dtos/StringDtoValidated.ts index 289655c..0211e22 100644 --- a/back/volume/src/pong/dtos/StringDtoValidated.ts +++ b/back/volume/src/pong/dtos/StringDtoValidated.ts @@ -1,7 +1,7 @@ -import { IsString } from "class-validator"; -import { StringDto } from "./StringDto"; +import { IsString } from 'class-validator' +import { StringDto } from './StringDto' export class StringDtoValidated extends StringDto { @IsString() - value!: string; + value!: string } diff --git a/back/volume/src/pong/dtos/UserDto.ts b/back/volume/src/pong/dtos/UserDto.ts index 27a0bed..10880a7 100644 --- a/back/volume/src/pong/dtos/UserDto.ts +++ b/back/volume/src/pong/dtos/UserDto.ts @@ -1,12 +1,12 @@ -import { IsString } from "class-validator"; +import { IsString } from 'class-validator' export class UserDto { @IsString() - username!: string; + username!: string @IsString() - avatar!: string; + avatar!: string @IsString() - status!: string; + status!: string } diff --git a/back/volume/src/pong/entity/result.entity.ts b/back/volume/src/pong/entity/result.entity.ts index 8c65124..037dc33 100644 --- a/back/volume/src/pong/entity/result.entity.ts +++ b/back/volume/src/pong/entity/result.entity.ts @@ -3,25 +3,25 @@ import { PrimaryGeneratedColumn, Column, ManyToMany, - CreateDateColumn, -} from "typeorm"; + CreateDateColumn +} from 'typeorm' -import User from "src/users/entity/user.entity"; +import User from 'src/users/entity/user.entity' @Entity() export default class Result { @PrimaryGeneratedColumn() - id: number; + id: number @Column({ default: false }) - ranked: boolean; + ranked: boolean @ManyToMany(() => User, (player: User) => player.results, { cascade: true }) - players: Array; // TODO: change to User[] for final version + players: Array // TODO: change to User[] for final version - @Column("text", { array: true }) - public score: number[]; + @Column('text', { array: true }) + public score: number[] @CreateDateColumn() - date: Date; + date: Date } diff --git a/back/volume/src/pong/game/Ball.ts b/back/volume/src/pong/game/Ball.ts index 63cbd86..a93b330 100644 --- a/back/volume/src/pong/game/Ball.ts +++ b/back/volume/src/pong/game/Ball.ts @@ -1,114 +1,114 @@ -import { type Paddle } from "./Paddle"; -import { type Point, Rect } from "./utils"; -import { type MapDtoValidated } from "../dtos/MapDtoValidated"; +import { type Paddle } from './Paddle' +import { type Point, Rect } from './utils' +import { type MapDtoValidated } from '../dtos/MapDtoValidated' import { DEFAULT_BALL_SIZE, GAME_TICKS, DEFAULT_BALL_SPEED_INCREMENT, - DEFAULT_MAX_BALL_SPEED, -} from "./constants"; + DEFAULT_MAX_BALL_SPEED +} from './constants' export class Ball { - rect: Rect; - initial_speed: Point; - speed: Point; - spawn: Point; - indexPlayerScored: number; - timeoutTime: number; + rect: Rect + initial_speed: Point + speed: Point + spawn: Point + indexPlayerScored: number + timeoutTime: number - constructor( + constructor ( spawn: Point, initialSpeed: Point, size: Point = DEFAULT_BALL_SIZE.clone() ) { - this.rect = new Rect(spawn, size); - this.speed = initialSpeed.clone(); - this.initial_speed = initialSpeed.clone(); - this.spawn = spawn.clone(); - this.indexPlayerScored = -1; - this.timeoutTime = 0; + this.rect = new Rect(spawn, size) + this.speed = initialSpeed.clone() + this.initial_speed = initialSpeed.clone() + this.spawn = spawn.clone() + this.indexPlayerScored = -1 + this.timeoutTime = 0 } - getIndexPlayerScored(): number { - return this.indexPlayerScored; + getIndexPlayerScored (): number { + return this.indexPlayerScored } - update(canvasRect: Rect, paddles: Paddle[], map: MapDtoValidated): void { + update (canvasRect: Rect, paddles: Paddle[], map: MapDtoValidated): void { if (!canvasRect.contains_x(this.rect)) { - this.indexPlayerScored = this.playerScored(); - this.timeoutTime = 2000; + this.indexPlayerScored = this.playerScored() + this.timeoutTime = 2000 } else { - this.indexPlayerScored = -1; + this.indexPlayerScored = -1 if (this.timeoutTime <= 0) { - this.move(canvasRect, paddles, map); + this.move(canvasRect, paddles, map) } else { - this.timeoutTime -= 1000 / GAME_TICKS; + this.timeoutTime -= 1000 / GAME_TICKS } } } - move(canvasRect: Rect, paddles: Paddle[], map: MapDtoValidated): void { + move (canvasRect: Rect, paddles: Paddle[], map: MapDtoValidated): void { for (const paddle of paddles) { if (paddle.rect.collides(this.rect)) { if (this.speed.x < 0) { - this.rect.center.x = paddle.rect.center.x + paddle.rect.size.x; - } else this.rect.center.x = paddle.rect.center.x - paddle.rect.size.x; - this.speed.x = this.speed.x * -1; + this.rect.center.x = paddle.rect.center.x + paddle.rect.size.x + } else this.rect.center.x = paddle.rect.center.x - paddle.rect.size.x + this.speed.x = this.speed.x * -1 this.speed.y = ((this.rect.center.y - paddle.rect.center.y) / paddle.rect.size.y) * - 20; - break; + 20 + break } } for (const wall of map.walls) { if (wall.collides(this.rect)) { if (this.speed.x < 0) { - this.rect.center.x = wall.center.x + wall.size.x; - } else this.rect.center.x = wall.center.x - wall.size.x; - this.speed.x = this.speed.x * -1; + this.rect.center.x = wall.center.x + wall.size.x + } else this.rect.center.x = wall.center.x - wall.size.x + this.speed.x = this.speed.x * -1 this.speed.y = - ((this.rect.center.y - wall.center.y) / wall.size.y) * 20; - break; + ((this.rect.center.y - wall.center.y) / wall.size.y) * 20 + break } } - if (!canvasRect.contains_y(this.rect)) this.speed.y = this.speed.y * -1; + if (!canvasRect.contains_y(this.rect)) this.speed.y = this.speed.y * -1 if (this.speed.x > 0 && this.speed.x < DEFAULT_MAX_BALL_SPEED.x) { - this.speed.x += DEFAULT_BALL_SPEED_INCREMENT.x; + this.speed.x += DEFAULT_BALL_SPEED_INCREMENT.x } if (this.speed.x < 0 && this.speed.x > -DEFAULT_MAX_BALL_SPEED.x) { - this.speed.x -= DEFAULT_BALL_SPEED_INCREMENT.x; + this.speed.x -= DEFAULT_BALL_SPEED_INCREMENT.x } if (this.speed.y > 0 && this.speed.y > DEFAULT_MAX_BALL_SPEED.y) { - this.speed.y += DEFAULT_MAX_BALL_SPEED.y; + this.speed.y += DEFAULT_MAX_BALL_SPEED.y } if (this.speed.y < 0 && this.speed.y < -DEFAULT_MAX_BALL_SPEED.y) { - this.speed.y -= DEFAULT_MAX_BALL_SPEED.y; + this.speed.y -= DEFAULT_MAX_BALL_SPEED.y } - this.rect.center.add_inplace(this.speed); + this.rect.center.add_inplace(this.speed) } - playerScored(): number { - let indexPlayerScored: number; + playerScored (): number { + let indexPlayerScored: number if (this.rect.center.x <= this.spawn.x) { - indexPlayerScored = 1; - this.speed.x = this.initial_speed.x; + indexPlayerScored = 1 + this.speed.x = this.initial_speed.x } else { - indexPlayerScored = 0; - this.speed.x = -this.initial_speed.x; + indexPlayerScored = 0 + this.speed.x = -this.initial_speed.x } if (this.speed.y < 0) { - this.speed.y = this.initial_speed.y; + this.speed.y = this.initial_speed.y } else { - this.speed.y = -this.initial_speed.y; + this.speed.y = -this.initial_speed.y } - this.rect.center = this.spawn.clone(); + this.rect.center = this.spawn.clone() - return indexPlayerScored; + return indexPlayerScored } } diff --git a/back/volume/src/pong/game/Game.ts b/back/volume/src/pong/game/Game.ts index 6a63861..16db48c 100644 --- a/back/volume/src/pong/game/Game.ts +++ b/back/volume/src/pong/game/Game.ts @@ -1,33 +1,33 @@ -import { Ball } from "./Ball"; -import { type Socket } from "socket.io"; -import { Point, Rect } from "./utils"; -import { Player } from "./Player"; +import { Ball } from './Ball' +import { type Socket } from 'socket.io' +import { Point, Rect } from './utils' +import { Player } from './Player' import { DEFAULT_BALL_INITIAL_SPEED, DEFAULT_BALL_SIZE, DEFAULT_PADDLE_SIZE, DEFAULT_WIN_SCORE, GAME_EVENTS, - GAME_TICKS, -} from "./constants"; -import { randomUUID } from "crypto"; -import { type MapDtoValidated } from "../dtos/MapDtoValidated"; -import { type GameUpdate } from "../dtos/GameUpdate"; -import { type GameInfo } from "../dtos/GameInfo"; -import { type PongService } from "../pong.service"; + GAME_TICKS +} from './constants' +import { randomUUID } from 'crypto' +import { type MapDtoValidated } from '../dtos/MapDtoValidated' +import { type GameUpdate } from '../dtos/GameUpdate' +import { type GameInfo } from '../dtos/GameInfo' +import { type PongService } from '../pong.service' export class Game { - id: string; - timer: NodeJS.Timer | null; - map: MapDtoValidated; - ball: Ball; - players: Player[] = []; - ranked: boolean; - initialBallSpeed: Point; - waitingForTimeout: boolean; - gameStoppedCallback: (name: string) => void; + id: string + timer: NodeJS.Timer | null + map: MapDtoValidated + ball: Ball + players: Player[] = [] + ranked: boolean + initialBallSpeed: Point + waitingForTimeout: boolean + gameStoppedCallback: (name: string) => void - constructor( + constructor ( sockets: Socket[], uuids: string[], names: string[], @@ -37,24 +37,24 @@ export class Game { ranked: boolean, initialBallSpeed: Point = DEFAULT_BALL_INITIAL_SPEED.clone() ) { - this.id = randomUUID(); - this.timer = null; - this.ranked = ranked; - this.waitingForTimeout = false; - this.map = map; - this.gameStoppedCallback = gameStoppedCallback; - this.initialBallSpeed = initialBallSpeed; + this.id = randomUUID() + this.timer = null + this.ranked = ranked + this.waitingForTimeout = false + this.map = map + this.gameStoppedCallback = gameStoppedCallback + this.initialBallSpeed = initialBallSpeed this.ball = new Ball( new Point(this.map.size.x / 2, this.map.size.y / 2), initialBallSpeed - ); + ) for (let i = 0; i < uuids.length; i++) { - this.addPlayer(sockets[i], uuids[i], names[i]); + this.addPlayer(sockets[i], uuids[i], names[i]) } } - getGameInfo(name: string): GameInfo { - const yourPaddleIndex = this.players.findIndex((p) => p.name === name); + getGameInfo (name: string): GameInfo { + const yourPaddleIndex = this.players.findIndex((p) => p.name === name) return { mapSize: this.map.size, yourPaddleIndex, @@ -63,112 +63,112 @@ export class Game { paddleSize: DEFAULT_PADDLE_SIZE, ballSize: DEFAULT_BALL_SIZE, winScore: DEFAULT_WIN_SCORE, - ranked: this.ranked, - }; + ranked: this.ranked + } } - private addPlayer(socket: Socket, uuid: string, name: string): void { + private addPlayer (socket: Socket, uuid: string, name: string): void { let paddleCoords = new Point( DEFAULT_PADDLE_SIZE.x / 2, this.map.size.y / 2 - ); + ) if (this.players.length === 1) { paddleCoords = new Point( this.map.size.x - DEFAULT_PADDLE_SIZE.x / 2, this.map.size.y / 2 - ); + ) } this.players.push( new Player(socket, uuid, name, paddleCoords, this.map.size) - ); + ) if (this.ranked) { - this.ready(name); + this.ready(name) } } - ready(name: string): void { - const playerIndex: number = this.players.findIndex((p) => p.name === name); + ready (name: string): void { + const playerIndex: number = this.players.findIndex((p) => p.name === name) if (playerIndex !== -1 && !this.players[playerIndex].ready) { - this.players[playerIndex].ready = true; - console.log(`${this.players[playerIndex].name} is ready`); + this.players[playerIndex].ready = true + console.log(`${this.players[playerIndex].name} is ready`) if (this.players.length === 2 && this.players.every((p) => p.ready)) { - this.start(); + this.start() } } } - private start(): void { + private start (): void { if (this.timer === null && this.players.length === 2) { this.ball = new Ball( new Point(this.map.size.x / 2, this.map.size.y / 2), this.initialBallSpeed - ); + ) this.players.forEach((p) => { - void this.pongService.setInGame(p.name); - p.newGame(); - }); - this.broadcastGame(GAME_EVENTS.START_GAME); - this.timer = setInterval(this.gameLoop.bind(this), 1000 / GAME_TICKS); - console.log(`Game ${this.id} starting in 3 seconds`); - this.waitingForTimeout = true; + void this.pongService.setInGame(p.name) + p.newGame() + }) + this.broadcastGame(GAME_EVENTS.START_GAME) + this.timer = setInterval(this.gameLoop.bind(this), 1000 / GAME_TICKS) + console.log(`Game ${this.id} starting in 3 seconds`) + this.waitingForTimeout = true new Promise((resolve) => setTimeout(resolve, 3000)) .then(() => (this.waitingForTimeout = false)) - .catch(() => {}); + .catch(() => {}) } } - stop(): void { + stop (): void { if (this.timer !== null) { - clearInterval(this.timer); + clearInterval(this.timer) } - this.timer = null; + this.timer = null this.pongService .saveResult(this.players, this.ranked, DEFAULT_WIN_SCORE) .then(() => { - this.gameStoppedCallback(this.players[0].name); - this.players = []; + this.gameStoppedCallback(this.players[0].name) + this.players = [] }) .catch(() => { - this.gameStoppedCallback(this.players[0].name); - this.players = []; - }); + this.gameStoppedCallback(this.players[0].name) + this.players = [] + }) } - movePaddle(name: string | undefined, position: Point): void { - const playerIndex: number = this.players.findIndex((p) => p.name === name); + movePaddle (name: string | undefined, position: Point): void { + const playerIndex: number = this.players.findIndex((p) => p.name === name) if (this.timer !== null && playerIndex !== -1) { - this.players[playerIndex].paddle.move(position.y); + this.players[playerIndex].paddle.move(position.y) } } - private broadcastGame(event: string, data?: any): void { + private broadcastGame (event: string, data?: any): void { this.players.forEach((p) => { - p.socket.emit(event, data); - }); + p.socket.emit(event, data) + }) } - private gameLoop(): void { + private gameLoop (): void { if (this.waitingForTimeout) { - return; + return } const canvasRect: Rect = new Rect( new Point(this.map.size.x / 2, this.map.size.y / 2), new Point(this.map.size.x, this.map.size.y) - ); + ) this.ball.update( canvasRect, this.players.map((p) => p.paddle), this.map - ); - const indexPlayerScored: number = this.ball.getIndexPlayerScored(); + ) + const indexPlayerScored: number = this.ball.getIndexPlayerScored() if (indexPlayerScored !== -1) { - this.players[indexPlayerScored].score += 1; + this.players[indexPlayerScored].score += 1 if (this.players[indexPlayerScored].score >= DEFAULT_WIN_SCORE) { - console.log(`${this.players[indexPlayerScored].name} won`); - this.stop(); + console.log(`${this.players[indexPlayerScored].name} won`) + this.stop() } } @@ -176,8 +176,8 @@ export class Game { paddlesPositions: this.players.map((p) => p.paddle.rect.center), ballSpeed: this.ball.speed, ballPosition: this.ball.rect.center, - scores: this.players.map((p) => p.score), - }; - this.broadcastGame(GAME_EVENTS.GAME_TICK, data); + scores: this.players.map((p) => p.score) + } + this.broadcastGame(GAME_EVENTS.GAME_TICK, data) } } diff --git a/back/volume/src/pong/game/Games.ts b/back/volume/src/pong/game/Games.ts index 8cecf94..fdd5efc 100644 --- a/back/volume/src/pong/game/Games.ts +++ b/back/volume/src/pong/game/Games.ts @@ -1,33 +1,33 @@ -import { type Socket } from "socket.io"; -import { Game } from "./Game"; -import { Point } from "./utils"; -import { type MapDtoValidated as GameMap } from "../dtos/MapDtoValidated"; -import { type GameCreationDtoValidated } from "../dtos/GameCreationDtoValidated"; -import { type GameInfo } from "../dtos/GameInfo"; -import { type PongService } from "../pong.service"; +import { type Socket } from 'socket.io' +import { Game } from './Game' +import { Point } from './utils' +import { type MapDtoValidated as GameMap } from '../dtos/MapDtoValidated' +import { type GameCreationDtoValidated } from '../dtos/GameCreationDtoValidated' +import { type GameInfo } from '../dtos/GameInfo' +import { type PongService } from '../pong.service' import { DEFAULT_BALL_SIZE, DEFAULT_MAP_SIZE, DEFAULT_PADDLE_SIZE, - DEFAULT_WIN_SCORE, -} from "./constants"; + DEFAULT_WIN_SCORE +} from './constants' export class Games { - constructor(private readonly pongService: PongService) {} - private readonly playerNameToGameIndex = new Map(); - private readonly games = new Array(); + constructor (private readonly pongService: PongService) {} + private readonly playerNameToGameIndex = new Map() + private readonly games = new Array() - newGame( + newGame ( sockets: Socket[], uuids: string[], gameCreationDto: GameCreationDtoValidated, ranked: boolean ): void { - const names: string[] = gameCreationDto.playerNames; + const names: string[] = gameCreationDto.playerNames const map: GameMap = { size: DEFAULT_MAP_SIZE, - walls: gameCreationDto.map.walls, - }; + walls: gameCreationDto.map.walls + } if (!this.isInAGame(names[0]) && !this.isInAGame(names[1])) { this.games.push( new Game( @@ -43,76 +43,76 @@ export class Games { gameCreationDto.initialBallSpeedY ) ) - ); - this.playerNameToGameIndex.set(names[0], this.games.length - 1); - this.playerNameToGameIndex.set(names[1], this.games.length - 1); + ) + this.playerNameToGameIndex.set(names[0], this.games.length - 1) + this.playerNameToGameIndex.set(names[1], this.games.length - 1) console.log( `Created game ${names[0]} vs ${names[1]} (${ this.games[this.games.length - 1].id })` - ); + ) } } - ready(name: string): void { - const game: Game | undefined = this.playerGame(name); + ready (name: string): void { + const game: Game | undefined = this.playerGame(name) if (game !== undefined) { - game.ready(name); + game.ready(name) } } - private deleteGame(name: string): void { - const game: Game | undefined = this.playerGame(name); + private deleteGame (name: string): void { + const game: Game | undefined = this.playerGame(name) if (game !== undefined) { - this.games.splice(this.games.indexOf(game), 1); + this.games.splice(this.games.indexOf(game), 1) game.players.forEach((player) => { - this.playerNameToGameIndex.delete(player.name); - }); - console.log(`Game stopped: ${game.id}`); + this.playerNameToGameIndex.delete(player.name) + }) + console.log(`Game stopped: ${game.id}`) } } - getGameInfo(name: string): GameInfo { - const game: Game | undefined = this.playerGame(name); + getGameInfo (name: string): GameInfo { + const game: Game | undefined = this.playerGame(name) if (game !== undefined) { - return game.getGameInfo(name); + return game.getGameInfo(name) } return { yourPaddleIndex: -2, - gameId: "", + gameId: '', mapSize: new Point(0, 0), walls: [], paddleSize: DEFAULT_PADDLE_SIZE, ballSize: DEFAULT_BALL_SIZE, winScore: DEFAULT_WIN_SCORE, - ranked: false, - }; + ranked: false + } } - movePlayer(name: string | undefined, position: Point): void { - const game: Game | undefined = this.playerGame(name); + movePlayer (name: string | undefined, position: Point): void { + const game: Game | undefined = this.playerGame(name) if (game !== undefined) { - game.movePaddle(name, position); + game.movePaddle(name, position) } } - isInAGame(name: string | undefined): boolean { - if (name === undefined) return false; - return this.playerNameToGameIndex.get(name) !== undefined; + isInAGame (name: string | undefined): boolean { + if (name === undefined) return false + return this.playerNameToGameIndex.get(name) !== undefined } - playerGame(name: string | undefined): Game | undefined { + playerGame (name: string | undefined): Game | undefined { const game: Game | undefined = this.games.find((game) => game.players.some((player) => player.name === name) - ); - return game; + ) + return game } - async leaveGame(name: string): Promise { - const game: Game | undefined = this.playerGame(name); + async leaveGame (name: string): Promise { + const game: Game | undefined = this.playerGame(name) if (game !== undefined && !game.ranked) { - game.stop(); - this.deleteGame(name); + game.stop() + this.deleteGame(name) } } } diff --git a/back/volume/src/pong/game/MatchmakingQueue.ts b/back/volume/src/pong/game/MatchmakingQueue.ts index 2918bec..a475dc6 100644 --- a/back/volume/src/pong/game/MatchmakingQueue.ts +++ b/back/volume/src/pong/game/MatchmakingQueue.ts @@ -1,64 +1,64 @@ -import { type Socket } from "socket.io"; -import { type GameCreationDtoValidated } from "../dtos/GameCreationDtoValidated"; -import { DEFAULT_BALL_INITIAL_SPEED, DEFAULT_MAP_SIZE } from "./constants"; -import { type Games } from "./Games"; +import { type Socket } from 'socket.io' +import { type GameCreationDtoValidated } from '../dtos/GameCreationDtoValidated' +import { DEFAULT_BALL_INITIAL_SPEED, DEFAULT_MAP_SIZE } from './constants' +import { type Games } from './Games' export class MatchmakingQueue { - games: Games; - queue: Array<{ name: string; socket: Socket; uuid: string }>; + games: Games + queue: Array<{ name: string, socket: Socket, uuid: string }> - constructor(games: Games) { - this.games = games; - this.queue = []; + constructor (games: Games) { + this.games = games + this.queue = [] } - addPlayer(name: string, socket: Socket, uuid: string): void { + addPlayer (name: string, socket: Socket, uuid: string): void { if (!this.isInQueue(name)) { - console.log("Adding player to queue: ", name); - this.queue.push({ name, socket, uuid }); + console.log('Adding player to queue: ', name) + this.queue.push({ name, socket, uuid }) if (this.canCreateGame()) { - this.createGame(); + this.createGame() } } } - removePlayer(name: string): void { + removePlayer (name: string): void { if (this.isInQueue(name)) { - console.log("Removing player from queue: ", name); - this.queue = this.queue.filter((player) => player.name !== name); + console.log('Removing player from queue: ', name) + this.queue = this.queue.filter((player) => player.name !== name) } } - isInQueue(name: string): boolean { - return this.queue.some((player) => player.name === name); + isInQueue (name: string): boolean { + return this.queue.some((player) => player.name === name) } - canCreateGame(): boolean { - return this.queue.length >= 2; + canCreateGame (): boolean { + return this.queue.length >= 2 } - createGame(): void { - const player1 = this.queue.shift(); - const player2 = this.queue.shift(); + createGame (): void { + const player1 = this.queue.shift() + const player2 = this.queue.shift() if (player1 === undefined || player2 === undefined) { - return; + return } const gameCreationDto: GameCreationDtoValidated = { playerNames: [player1.name, player2.name], map: { size: DEFAULT_MAP_SIZE, - walls: [], + walls: [] }, initialBallSpeedX: DEFAULT_BALL_INITIAL_SPEED.x, - initialBallSpeedY: DEFAULT_BALL_INITIAL_SPEED.y, - }; - const ranked = true; + initialBallSpeedY: DEFAULT_BALL_INITIAL_SPEED.y + } + const ranked = true this.games.newGame( [player1.socket, player2.socket], [player1.uuid, player2.uuid], gameCreationDto, ranked - ); + ) } } diff --git a/back/volume/src/pong/game/Paddle.ts b/back/volume/src/pong/game/Paddle.ts index cfb38b6..324a819 100644 --- a/back/volume/src/pong/game/Paddle.ts +++ b/back/volume/src/pong/game/Paddle.ts @@ -1,32 +1,32 @@ -import { DEFAULT_PADDLE_SIZE } from "./constants"; -import { type Point, Rect } from "./utils"; +import { DEFAULT_PADDLE_SIZE } from './constants' +import { type Point, Rect } from './utils' export class Paddle { - rect: Rect; - color: string | CanvasGradient | CanvasPattern = "white"; - mapSize: Point; + rect: Rect + color: string | CanvasGradient | CanvasPattern = 'white' + mapSize: Point - constructor( + constructor ( spawn: Point, gameSize: Point, size: Point = DEFAULT_PADDLE_SIZE ) { - this.rect = new Rect(spawn, size); - this.mapSize = gameSize; + this.rect = new Rect(spawn, size) + this.mapSize = gameSize } - draw(context: CanvasRenderingContext2D): void { - this.rect.draw(context, this.color); + draw (context: CanvasRenderingContext2D): void { + this.rect.draw(context, this.color) } - move(newY: number): void { - const offset: number = this.rect.size.y / 2; + move (newY: number): void { + const offset: number = this.rect.size.y / 2 if (newY - offset < 0) { - this.rect.center.y = offset; + this.rect.center.y = offset } else if (newY + offset > this.mapSize.y) { - this.rect.center.y = this.mapSize.y - offset; + this.rect.center.y = this.mapSize.y - offset } else { - this.rect.center.y = newY; + this.rect.center.y = newY } } } diff --git a/back/volume/src/pong/game/Player.ts b/back/volume/src/pong/game/Player.ts index cbcad17..ee9b6da 100644 --- a/back/volume/src/pong/game/Player.ts +++ b/back/volume/src/pong/game/Player.ts @@ -1,36 +1,36 @@ -import { type Socket } from "socket.io"; -import { Paddle } from "./Paddle"; -import { type Point } from "./utils"; +import { type Socket } from 'socket.io' +import { Paddle } from './Paddle' +import { type Point } from './utils' export class Player { - socket: Socket; - uuid: string; - name: string; - ready: boolean; - paddle: Paddle; - paddleCoords: Point; - mapSize: Point; - score: number; + socket: Socket + uuid: string + name: string + ready: boolean + paddle: Paddle + paddleCoords: Point + mapSize: Point + score: number - constructor( + constructor ( socket: Socket, uuid: string, name: string, paddleCoords: Point, mapSize: Point ) { - this.socket = socket; - this.uuid = uuid; - this.name = name; - this.ready = false; - this.paddle = new Paddle(paddleCoords, mapSize); - this.paddleCoords = paddleCoords; - this.mapSize = mapSize; - this.score = 0; + this.socket = socket + this.uuid = uuid + this.name = name + this.ready = false + this.paddle = new Paddle(paddleCoords, mapSize) + this.paddleCoords = paddleCoords + this.mapSize = mapSize + this.score = 0 } - newGame(): void { - this.score = 0; - this.paddle = new Paddle(this.paddleCoords, this.mapSize); + newGame (): void { + this.score = 0 + this.paddle = new Paddle(this.paddleCoords, this.mapSize) } } diff --git a/back/volume/src/pong/game/constants.ts b/back/volume/src/pong/game/constants.ts index 867dd03..4516899 100644 --- a/back/volume/src/pong/game/constants.ts +++ b/back/volume/src/pong/game/constants.ts @@ -1,22 +1,22 @@ -import { Point } from "./utils"; +import { Point } from './utils' export const GAME_EVENTS = { - START_GAME: "START_GAME", - READY: "READY", - GAME_TICK: "GAME_TICK", - PLAYER_MOVE: "PLAYER_MOVE", - GET_GAME_INFO: "GET_GAME_INFO", - CREATE_GAME: "CREATE_GAME", - REGISTER_PLAYER: "REGISTER_PLAYER", - MATCHMAKING: "MATCHMAKING", - LEAVE_GAME: "LEAVE_GAME", -}; + START_GAME: 'START_GAME', + READY: 'READY', + GAME_TICK: 'GAME_TICK', + PLAYER_MOVE: 'PLAYER_MOVE', + GET_GAME_INFO: 'GET_GAME_INFO', + CREATE_GAME: 'CREATE_GAME', + REGISTER_PLAYER: 'REGISTER_PLAYER', + MATCHMAKING: 'MATCHMAKING', + LEAVE_GAME: 'LEAVE_GAME' +} -export const DEFAULT_MAP_SIZE = new Point(500, 400); -export const DEFAULT_PADDLE_SIZE = new Point(30, 50); -export const DEFAULT_BALL_SIZE = new Point(10, 10); -export const DEFAULT_BALL_INITIAL_SPEED = new Point(10, 2); -export const DEFAULT_MAX_BALL_SPEED = new Point(30, 20); -export const DEFAULT_BALL_SPEED_INCREMENT = new Point(0.05, 0); -export const DEFAULT_WIN_SCORE = 5; -export const GAME_TICKS = 30; +export const DEFAULT_MAP_SIZE = new Point(500, 400) +export const DEFAULT_PADDLE_SIZE = new Point(30, 50) +export const DEFAULT_BALL_SIZE = new Point(10, 10) +export const DEFAULT_BALL_INITIAL_SPEED = new Point(10, 2) +export const DEFAULT_MAX_BALL_SPEED = new Point(30, 20) +export const DEFAULT_BALL_SPEED_INCREMENT = new Point(0.05, 0) +export const DEFAULT_WIN_SCORE = 5 +export const GAME_TICKS = 30 diff --git a/back/volume/src/pong/game/utils.ts b/back/volume/src/pong/game/utils.ts index 081c9c5..d26ea43 100644 --- a/back/volume/src/pong/game/utils.ts +++ b/back/volume/src/pong/game/utils.ts @@ -1,83 +1,83 @@ export class Point { - x: number; - y: number; + x: number + y: number - constructor(x: number, y: number) { - this.x = x; - this.y = y; + constructor (x: number, y: number) { + this.x = x + this.y = y } // Returns a new point - add(other: Point): Point { - return new Point(this.x + other.x, this.y + other.y); + add (other: Point): Point { + return new Point(this.x + other.x, this.y + other.y) } // Modifies `this` point - add_inplace(other: Point): void { - this.x += other.x; - this.y += other.y; + add_inplace (other: Point): void { + this.x += other.x + this.y += other.y } - clone(): Point { - return new Point(this.x, this.y); + clone (): Point { + return new Point(this.x, this.y) } } export class Rect { - center: Point; - size: Point; + center: Point + size: Point - constructor(center: Point, size: Point) { - this.center = center; - this.size = size; + constructor (center: Point, size: Point) { + this.center = center + this.size = size } - draw( + draw ( context: CanvasRenderingContext2D, color: string | CanvasGradient | CanvasPattern ): void { - const offset: Point = new Point(this.size.x / 2, this.size.y / 2); + const offset: Point = new Point(this.size.x / 2, this.size.y / 2) - context.fillStyle = color; + context.fillStyle = color context.fillRect( this.center.x - offset.x, this.center.y - offset.y, this.size.x, this.size.y - ); + ) } // True if `this` rect contains `other` rect in the x-axis - contains_x(other: Rect): boolean { - const offset: number = this.size.x / 2; - const offsetOther: number = other.size.x / 2; + contains_x (other: Rect): boolean { + const offset: number = this.size.x / 2 + const offsetOther: number = other.size.x / 2 if ( this.center.x - offset <= other.center.x - offsetOther && this.center.x + offset >= other.center.x + offsetOther ) { - return true; + return true } - return false; + return false } // True if `this` rect contains `other` rect in the y-axis - contains_y(other: Rect): boolean { - const offset: number = this.size.y / 2; - const offsetOther: number = other.size.y / 2; + contains_y (other: Rect): boolean { + const offset: number = this.size.y / 2 + const offsetOther: number = other.size.y / 2 if ( this.center.y - offset <= other.center.y - offsetOther && this.center.y + offset >= other.center.y + offsetOther ) { - return true; + return true } - return false; + return false } - collides(other: Rect): boolean { - const offset: Point = new Point(this.size.x / 2, this.size.y / 2); - const offsetOther: Point = new Point(other.size.x / 2, other.size.y / 2); + collides (other: Rect): boolean { + const offset: Point = new Point(this.size.x / 2, this.size.y / 2) + const offsetOther: Point = new Point(other.size.x / 2, other.size.y / 2) if ( this.center.x - offset.x < other.center.x + offsetOther.x && @@ -85,8 +85,8 @@ export class Rect { this.center.y - offset.y < other.center.y + offsetOther.y && this.center.y + offset.y > other.center.y - offsetOther.y ) { - return true; + return true } - return false; + return false } } diff --git a/back/volume/src/pong/pong.controller.ts b/back/volume/src/pong/pong.controller.ts index 5016cac..809880d 100644 --- a/back/volume/src/pong/pong.controller.ts +++ b/back/volume/src/pong/pong.controller.ts @@ -3,31 +3,31 @@ import { Get, Param, ParseIntPipe, - UseGuards, -} from "@nestjs/common"; -import { Paginate, type Paginated, PaginateQuery } from "nestjs-paginate"; -import { AuthenticatedGuard } from "src/auth/42-auth.guard"; -import type Result from "./entity/result.entity"; -import { PongService } from "./pong.service"; + UseGuards +} from '@nestjs/common' +import { Paginate, type Paginated, PaginateQuery } from 'nestjs-paginate' +import { AuthenticatedGuard } from 'src/auth/42-auth.guard' +import type Result from './entity/result.entity' +import { PongService } from './pong.service' -@Controller("results") +@Controller('results') export class PongController { - constructor(private readonly pongService: PongService) {} + constructor (private readonly pongService: PongService) {} - @Get("global") + @Get('global') @UseGuards(AuthenticatedGuard) - async getGlobalHistory( + async getGlobalHistory ( @Paginate() query: PaginateQuery ): Promise> { - return await this.pongService.getHistory(query, 0); + return await this.pongService.getHistory(query, 0) } - @Get(":id") + @Get(':id') @UseGuards(AuthenticatedGuard) - async getHistoryById( - @Param("id", ParseIntPipe) id: number, - @Paginate() query: PaginateQuery + async getHistoryById ( + @Param('id', ParseIntPipe) id: number, + @Paginate() query: PaginateQuery ): Promise> { - return await this.pongService.getHistory(query, id); + return await this.pongService.getHistory(query, id) } } diff --git a/back/volume/src/pong/pong.gateway.spec.ts b/back/volume/src/pong/pong.gateway.spec.ts index 1283d5c..f779c23 100644 --- a/back/volume/src/pong/pong.gateway.spec.ts +++ b/back/volume/src/pong/pong.gateway.spec.ts @@ -1,18 +1,18 @@ -import { Test, type TestingModule } from "@nestjs/testing"; -import { PongGateway } from "./pong.gateway"; +import { Test, type TestingModule } from '@nestjs/testing' +import { PongGateway } from './pong.gateway' -describe("PongGateway", () => { - let gateway: PongGateway; +describe('PongGateway', () => { + let gateway: PongGateway beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [PongGateway], - }).compile(); + providers: [PongGateway] + }).compile() - gateway = module.get(PongGateway); - }); + gateway = module.get(PongGateway) + }) - it("should be defined", () => { - expect(gateway).toBeDefined(); - }); -}); + it('should be defined', () => { + expect(gateway).toBeDefined() + }) +}) diff --git a/back/volume/src/pong/pong.gateway.ts b/back/volume/src/pong/pong.gateway.ts index 1fc0671..f2df12b 100644 --- a/back/volume/src/pong/pong.gateway.ts +++ b/back/volume/src/pong/pong.gateway.ts @@ -1,119 +1,119 @@ -import { UsePipes, ValidationPipe } from "@nestjs/common"; -import { Socket } from "socket.io"; +import { UsePipes, ValidationPipe } from '@nestjs/common' +import { Socket } from 'socket.io' import { ConnectedSocket, MessageBody, type OnGatewayConnection, type OnGatewayDisconnect, SubscribeMessage, - WebSocketGateway, -} from "@nestjs/websockets"; - -import { Games } from "./game/Games"; -import { GAME_EVENTS } from "./game/constants"; -import { GameCreationDtoValidated } from "./dtos/GameCreationDtoValidated"; -import { type Game } from "./game/Game"; -import { plainToClass } from "class-transformer"; -import { PointDtoValidated } from "./dtos/PointDtoValidated"; -import { StringDtoValidated } from "./dtos/StringDtoValidated"; -import { MatchmakingQueue } from "./game/MatchmakingQueue"; -import { MatchmakingDtoValidated } from "./dtos/MatchmakingDtoValidated"; -import { PongService } from "./pong.service"; -import { UsersService } from "src/users/users.service"; + WebSocketGateway +} from '@nestjs/websockets' + +import { Games } from './game/Games' +import { GAME_EVENTS } from './game/constants' +import { GameCreationDtoValidated } from './dtos/GameCreationDtoValidated' +import { type Game } from './game/Game' +import { plainToClass } from 'class-transformer' +import { PointDtoValidated } from './dtos/PointDtoValidated' +import { StringDtoValidated } from './dtos/StringDtoValidated' +import { MatchmakingQueue } from './game/MatchmakingQueue' +import { MatchmakingDtoValidated } from './dtos/MatchmakingDtoValidated' +import { PongService } from './pong.service' +import { UsersService } from 'src/users/users.service' @WebSocketGateway({ - cors: { origin: /^(http|ws):\/\/localhost(:\d+)?$/ }, + cors: { origin: /^(http|ws):\/\/localhost(:\d+)?$/ } }) export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect { - constructor( + constructor ( private readonly pongService: PongService, private readonly usersService: UsersService ) {} - private readonly games: Games = new Games(this.pongService); - private readonly socketToPlayerName = new Map(); - private readonly matchmakingQueue = new MatchmakingQueue(this.games); + private readonly games: Games = new Games(this.pongService) + private readonly socketToPlayerName = new Map() + private readonly matchmakingQueue = new MatchmakingQueue(this.games) - playerIsRegistered(name: string): boolean { - return Array.from(this.socketToPlayerName.values()).includes(name); + playerIsRegistered (name: string): boolean { + return Array.from(this.socketToPlayerName.values()).includes(name) } - handleConnection(): void {} + handleConnection (): void {} - handleDisconnect( + handleDisconnect ( @ConnectedSocket() - client: Socket + client: Socket ): void { - const name: string | undefined = this.socketToPlayerName.get(client); - const game: Game | undefined = this.games.playerGame(name); + const name: string | undefined = this.socketToPlayerName.get(client) + const game: Game | undefined = this.games.playerGame(name) if (game !== undefined) { - game.stop(); + game.stop() } if (name !== undefined) { - console.log("Disconnected ", this.socketToPlayerName.get(client)); - this.matchmakingQueue.removePlayer(name); - this.socketToPlayerName.delete(client); + console.log('Disconnected ', this.socketToPlayerName.get(client)) + this.matchmakingQueue.removePlayer(name) + this.socketToPlayerName.delete(client) } } @UsePipes(new ValidationPipe({ whitelist: true })) @SubscribeMessage(GAME_EVENTS.REGISTER_PLAYER) - async registerPlayer( + async registerPlayer ( @ConnectedSocket() - client: Socket, - @MessageBody("playerName") playerName: StringDtoValidated, - @MessageBody("socketKey") socketKey: StringDtoValidated - ): Promise<{ event: string; data: boolean }> { - let succeeded: boolean = false; - const user = await this.usersService.findUserByName(playerName.value); + client: Socket, + @MessageBody('playerName') playerName: StringDtoValidated, + @MessageBody('socketKey') socketKey: StringDtoValidated + ): Promise<{ event: string, data: boolean }> { + let succeeded: boolean = false + const user = await this.usersService.findUserByName(playerName.value) if ( user !== null && user.socketKey === socketKey.value && !this.playerIsRegistered(playerName.value) ) { - this.socketToPlayerName.set(client, playerName.value); - succeeded = true; - console.log("Registered player", playerName.value); + this.socketToPlayerName.set(client, playerName.value) + succeeded = true + console.log('Registered player', playerName.value) } else { - console.log("Failed to register player", playerName.value); + console.log('Failed to register player', playerName.value) } - return { event: GAME_EVENTS.REGISTER_PLAYER, data: succeeded }; + return { event: GAME_EVENTS.REGISTER_PLAYER, data: succeeded } } @SubscribeMessage(GAME_EVENTS.GET_GAME_INFO) - getPlayerCount(@ConnectedSocket() client: Socket): void { - const name: string | undefined = this.socketToPlayerName.get(client); + getPlayerCount (@ConnectedSocket() client: Socket): void { + const name: string | undefined = this.socketToPlayerName.get(client) if (name !== undefined) { - client.emit(GAME_EVENTS.GET_GAME_INFO, this.games.getGameInfo(name)); + client.emit(GAME_EVENTS.GET_GAME_INFO, this.games.getGameInfo(name)) } } @UsePipes(new ValidationPipe({ whitelist: true })) @SubscribeMessage(GAME_EVENTS.PLAYER_MOVE) - movePlayer( + movePlayer ( @ConnectedSocket() - client: Socket, - @MessageBody() position: PointDtoValidated + client: Socket, + @MessageBody() position: PointDtoValidated ): void { const realPosition: PointDtoValidated = plainToClass( PointDtoValidated, position - ); - const name: string | undefined = this.socketToPlayerName.get(client); - this.games.movePlayer(name, realPosition); + ) + const name: string | undefined = this.socketToPlayerName.get(client) + this.games.movePlayer(name, realPosition) } @UsePipes(new ValidationPipe({ whitelist: true })) @SubscribeMessage(GAME_EVENTS.CREATE_GAME) - createGame( + createGame ( @ConnectedSocket() - client: Socket, - @MessageBody() gameCreationDto: GameCreationDtoValidated - ): { event: string; data: boolean } { + client: Socket, + @MessageBody() gameCreationDto: GameCreationDtoValidated + ): { event: string, data: boolean } { const realGameCreationDto: GameCreationDtoValidated = plainToClass( GameCreationDtoValidated, gameCreationDto - ); + ) if (this.socketToPlayerName.size >= 2) { const player1Socket: Socket | undefined = Array.from( @@ -122,14 +122,14 @@ export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect { (key) => this.socketToPlayerName.get(key) === realGameCreationDto.playerNames[0] - ); + ) const player2Socket: Socket | undefined = Array.from( this.socketToPlayerName.keys() ).find( (key) => this.socketToPlayerName.get(key) === realGameCreationDto.playerNames[1] - ); + ) if ( player1Socket !== undefined && @@ -137,68 +137,68 @@ export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect { (client.id === player1Socket.id || client.id === player2Socket.id) && player1Socket.id !== player2Socket.id ) { - this.matchmakingQueue.removePlayer(realGameCreationDto.playerNames[0]); - this.matchmakingQueue.removePlayer(realGameCreationDto.playerNames[1]); + this.matchmakingQueue.removePlayer(realGameCreationDto.playerNames[0]) + this.matchmakingQueue.removePlayer(realGameCreationDto.playerNames[1]) - const ranked = false; + const ranked = false this.games.newGame( [player1Socket, player2Socket], [player1Socket.id, player2Socket.id], realGameCreationDto, ranked - ); - return { event: GAME_EVENTS.CREATE_GAME, data: true }; + ) + return { event: GAME_EVENTS.CREATE_GAME, data: true } } } - return { event: GAME_EVENTS.CREATE_GAME, data: false }; + return { event: GAME_EVENTS.CREATE_GAME, data: false } } @SubscribeMessage(GAME_EVENTS.READY) - ready( + ready ( @ConnectedSocket() - client: Socket - ): { event: string; data: boolean } { - let succeeded: boolean = false; - const name: string | undefined = this.socketToPlayerName.get(client); + client: Socket + ): { event: string, data: boolean } { + let succeeded: boolean = false + const name: string | undefined = this.socketToPlayerName.get(client) if (name !== undefined) { - this.games.ready(name); - succeeded = true; + this.games.ready(name) + succeeded = true } - return { event: GAME_EVENTS.READY, data: succeeded }; + return { event: GAME_EVENTS.READY, data: succeeded } } @UsePipes(new ValidationPipe({ whitelist: true })) @SubscribeMessage(GAME_EVENTS.MATCHMAKING) - updateMatchmaking( + updateMatchmaking ( @ConnectedSocket() - client: Socket, - @MessageBody() matchmakingUpdateData: MatchmakingDtoValidated - ): { event: string; data: MatchmakingDtoValidated } { - let matchmaking: boolean = false; - const name: string | undefined = this.socketToPlayerName.get(client); + client: Socket, + @MessageBody() matchmakingUpdateData: MatchmakingDtoValidated + ): { event: string, data: MatchmakingDtoValidated } { + let matchmaking: boolean = false + const name: string | undefined = this.socketToPlayerName.get(client) if (name !== undefined) { if (matchmakingUpdateData.matchmaking && !this.games.isInAGame(name)) { - this.matchmakingQueue.addPlayer(name, client, client.id); + this.matchmakingQueue.addPlayer(name, client, client.id) } else { - this.matchmakingQueue.removePlayer(name); + this.matchmakingQueue.removePlayer(name) } - matchmaking = this.matchmakingQueue.isInQueue(name); + matchmaking = this.matchmakingQueue.isInQueue(name) } return { event: GAME_EVENTS.MATCHMAKING, - data: { matchmaking }, - }; + data: { matchmaking } + } } @UsePipes(new ValidationPipe({ whitelist: true })) @SubscribeMessage(GAME_EVENTS.LEAVE_GAME) - leaveGame( + leaveGame ( @ConnectedSocket() - client: Socket + client: Socket ): void { - const name: string | undefined = this.socketToPlayerName.get(client); + const name: string | undefined = this.socketToPlayerName.get(client) if (name !== undefined) { - void this.games.leaveGame(name); + void this.games.leaveGame(name) } } } diff --git a/back/volume/src/pong/pong.module.ts b/back/volume/src/pong/pong.module.ts index 72b257d..df862a7 100644 --- a/back/volume/src/pong/pong.module.ts +++ b/back/volume/src/pong/pong.module.ts @@ -1,15 +1,15 @@ -import { forwardRef, Module } from "@nestjs/common"; -import { PongGateway } from "./pong.gateway"; -import Result from "./entity/result.entity"; -import { TypeOrmModule } from "@nestjs/typeorm"; -import { PongService } from "./pong.service"; -import { UsersModule } from "src/users/users.module"; -import { PongController } from "./pong.controller"; +import { forwardRef, Module } from '@nestjs/common' +import { PongGateway } from './pong.gateway' +import Result from './entity/result.entity' +import { TypeOrmModule } from '@nestjs/typeorm' +import { PongService } from './pong.service' +import { UsersModule } from 'src/users/users.module' +import { PongController } from './pong.controller' @Module({ imports: [forwardRef(() => UsersModule), TypeOrmModule.forFeature([Result])], providers: [PongGateway, PongService], controllers: [PongController], - exports: [PongService], + exports: [PongService] }) export class PongModule {} diff --git a/back/volume/src/pong/pong.service.ts b/back/volume/src/pong/pong.service.ts index 0160551..d64b78a 100644 --- a/back/volume/src/pong/pong.service.ts +++ b/back/volume/src/pong/pong.service.ts @@ -1,89 +1,89 @@ -import { Injectable } from "@nestjs/common"; -import { InjectRepository } from "@nestjs/typeorm"; -import { Repository } from "typeorm"; -import { UsersService } from "src/users/users.service"; -import Result from "./entity/result.entity"; -import type User from "src/users/entity/user.entity"; -import { type Player } from "./game/Player"; -import { type PaginateQuery, paginate, type Paginated } from "nestjs-paginate"; +import { Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { Repository } from 'typeorm' +import { UsersService } from 'src/users/users.service' +import Result from './entity/result.entity' +import type User from 'src/users/entity/user.entity' +import { type Player } from './game/Player' +import { type PaginateQuery, paginate, type Paginated } from 'nestjs-paginate' @Injectable() export class PongService { - constructor( + constructor ( @InjectRepository(Result) private readonly resultsRepository: Repository, private readonly usersService: UsersService ) {} - async updateStats( + async updateStats ( player: User, i: number, result: Result, maxScore: number ): Promise { - player.matchs++; - if (result.score[i] === maxScore) player.wins++; - else player.looses++; - player.winrate = (100 * player.wins) / player.matchs; + player.matchs++ + if (result.score[i] === maxScore) player.wins++ + else player.looses++ + player.winrate = (100 * player.wins) / player.matchs } - async updatePlayer( + async updatePlayer ( i: number, result: Result, maxScore: number ): Promise { - const player: User | null = result.players[i]; - if (player == null) return; - if (result.ranked) await this.updateStats(player, i, result, maxScore); - player.results.push(result); - player.status = "online"; - await this.usersService.save(player); + const player: User | null = result.players[i] + if (player == null) return + if (result.ranked) await this.updateStats(player, i, result, maxScore) + player.results.push(result) + player.status = 'online' + await this.usersService.save(player) } - async setInGame(playerName: string): Promise { - const player = await this.usersService.findUserByName(playerName); - player.status = "in-game"; - await this.usersService.save(player); + async setInGame (playerName: string): Promise { + const player = await this.usersService.findUserByName(playerName) + player.status = 'in-game' + await this.usersService.save(player) } - async saveResult( + async saveResult ( players: Player[], ranked: boolean, maxScore: number ): Promise { - const result = new Result(); - const ply = new Array(); - ply.push(await this.usersService.findUserByName(players[0].name)); - ply.push(await this.usersService.findUserByName(players[1].name)); - result.ranked = ranked; - result.players = ply; - result.score = [players[0].score, players[1].score]; - await this.resultsRepository.save(result); - await this.updatePlayer(0, result, maxScore); - await this.updatePlayer(1, result, maxScore); + const result = new Result() + const ply = new Array() + ply.push(await this.usersService.findUserByName(players[0].name)) + ply.push(await this.usersService.findUserByName(players[1].name)) + result.ranked = ranked + result.players = ply + result.score = [players[0].score, players[1].score] + await this.resultsRepository.save(result) + await this.updatePlayer(0, result, maxScore) + await this.updatePlayer(1, result, maxScore) } - async getHistory( + async getHistory ( query: PaginateQuery, ftId: number ): Promise> { - let queryBuilder; + let queryBuilder if (ftId !== 0) { queryBuilder = this.resultsRepository - .createQueryBuilder("result") - .innerJoin("result.players", "player", "player.ftId = :ftId", { ftId }); + .createQueryBuilder('result') + .innerJoin('result.players', 'player', 'player.ftId = :ftId', { ftId }) } else { queryBuilder = this.resultsRepository - .createQueryBuilder("result") - .where("result.ranked = :ranked", { ranked: true }); + .createQueryBuilder('result') + .where('result.ranked = :ranked', { ranked: true }) } return await paginate(query, queryBuilder, { - nullSort: "last", - relations: ["players"], - defaultSortBy: [["date", "DESC"]], - sortableColumns: ["date"], - maxLimit: 10, - }); + nullSort: 'last', + relations: ['players'], + defaultSortBy: [['date', 'DESC']], + sortableColumns: ['date'], + maxLimit: 10 + }) } } diff --git a/back/volume/src/pong/pong.spec.ts b/back/volume/src/pong/pong.spec.ts index 522c941..b11fd5b 100644 --- a/back/volume/src/pong/pong.spec.ts +++ b/back/volume/src/pong/pong.spec.ts @@ -1,18 +1,18 @@ -import { Test, type TestingModule } from "@nestjs/testing"; -import { Games } from "./game/Games"; +import { Test, type TestingModule } from '@nestjs/testing' +import { Games } from './game/Games' -describe("Pong", () => { - let provider: Games; +describe('Pong', () => { + let provider: Games beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [Games], - }).compile(); + providers: [Games] + }).compile() - provider = module.get(Games); - }); + provider = module.get(Games) + }) - it("should be defined", () => { - expect(provider).toBeDefined(); - }); -}); + it('should be defined', () => { + expect(provider).toBeDefined() + }) +}) diff --git a/back/volume/src/types.d.ts b/back/volume/src/types.d.ts index 65f3ee9..48e3dde 100644 --- a/back/volume/src/types.d.ts +++ b/back/volume/src/types.d.ts @@ -1,8 +1,8 @@ -declare module "passport-42" { - export type Profile = any; - export type VerifyCallback = any; +declare module 'passport-42' { + export type Profile = any + export type VerifyCallback = any export class Strategy { - constructor(options: any, verify: any); - authenticate(req: any, options: any): any; + constructor (options: any, verify: any) + authenticate (req: any, options: any): any } } diff --git a/back/volume/src/users/dto/user.dto.ts b/back/volume/src/users/dto/user.dto.ts index a521ce8..fe60681 100644 --- a/back/volume/src/users/dto/user.dto.ts +++ b/back/volume/src/users/dto/user.dto.ts @@ -1,31 +1,31 @@ -import { IsString, IsNotEmpty, IsPositive, IsOptional } from "class-validator"; +import { IsString, IsNotEmpty, IsPositive, IsOptional } from 'class-validator' -import { ApiProperty } from "@nestjs/swagger"; -import { Express } from "express"; +import { ApiProperty } from '@nestjs/swagger' +import { Express } from 'express' export class UserDto { @IsPositive() @IsOptional() - readonly ftId: number; + readonly ftId: number @IsString() @IsNotEmpty() - readonly username: string; + readonly username: string @IsOptional() - readonly status: string; + readonly status: string @IsOptional() - readonly avatar: string; + readonly avatar: string @IsOptional() - readonly authToken: string; + readonly authToken: string @IsOptional() - readonly isVerified: boolean; + readonly isVerified: boolean } export class AvatarUploadDto { - @ApiProperty({ type: "string", format: "binary" }) - file: Express.Multer.File; + @ApiProperty({ type: 'string', format: 'binary' }) + file: Express.Multer.File } diff --git a/back/volume/src/users/entity/user.entity.ts b/back/volume/src/users/entity/user.entity.ts index dfffb30..a52ce7f 100644 --- a/back/volume/src/users/entity/user.entity.ts +++ b/back/volume/src/users/entity/user.entity.ts @@ -4,78 +4,78 @@ import { Column, OneToMany, ManyToMany, - JoinTable, -} from "typeorm"; + JoinTable +} from 'typeorm' -import Message from "src/chat/entity/message.entity"; -import Channel from "src/chat/entity/channel.entity"; -import Result from "src/pong/entity/result.entity"; +import Message from 'src/chat/entity/message.entity' +import Channel from 'src/chat/entity/channel.entity' +import Result from 'src/pong/entity/result.entity' @Entity() export class User { @PrimaryGeneratedColumn() - id: number; + id: number - @Column({ type: "bigint", default: Date.now() }) - lastAccess: number; + @Column({ type: 'bigint', default: Date.now() }) + lastAccess: number @Column({ unique: true }) - ftId: number; + ftId: number @Column({ unique: true, nullable: true }) - email: string; + email: string @Column({ select: false, nullable: true }) - authToken: string; + authToken: string @Column({ default: false }) - twoFA: boolean; + twoFA: boolean @Column({ default: false, nullable: true }) - isVerified: boolean; + isVerified: boolean - @Column("uuid", { unique: true }) - socketKey: string; + @Column('uuid', { unique: true }) + socketKey: string @Column({ unique: true }) - username: string; + username: string - @Column({ default: "online" }) - status: string; + @Column({ default: 'online' }) + status: string - @Column({ name: "avatar" }) - avatar: string; + @Column({ name: 'avatar' }) + avatar: string @Column({ default: 0 }) - wins: number; + wins: number @Column({ default: 0 }) - looses: number; + looses: number @Column({ default: 0 }) - matchs: number; + matchs: number @Column({ default: 0 }) - rank: number; + rank: number - @Column({ default: 0, type: "double precision" }) - winrate: number; + @Column({ default: 0, type: 'double precision' }) + winrate: number @ManyToMany(() => Result, (result: Result) => result.players) @JoinTable() - results: Result[]; + results: Result[] @ManyToMany(() => User) @JoinTable() - blocked: User[]; + blocked: User[] @ManyToMany(() => User) @JoinTable() - followers: User[]; + followers: User[] @ManyToMany(() => User) @JoinTable() - friends: User[]; + friends: User[] } -export default User; +export default User diff --git a/back/volume/src/users/users.controller.ts b/back/volume/src/users/users.controller.ts index f4c34ab..e47c302 100644 --- a/back/volume/src/users/users.controller.ts +++ b/back/volume/src/users/users.controller.ts @@ -11,46 +11,48 @@ import { Res, StreamableFile, BadRequestException, - Redirect, -} from "@nestjs/common"; + Redirect +} from '@nestjs/common' -import { FileInterceptor } from "@nestjs/platform-express"; -import { diskStorage } from "multer"; +import { FileInterceptor } from '@nestjs/platform-express' +import { diskStorage } from 'multer' -import { type User } from "./entity/user.entity"; -import { UsersService } from "./users.service"; -import { UserDto, AvatarUploadDto } from "./dto/user.dto"; -import { PongService } from "src/pong/pong.service"; +import { type User } from './entity/user.entity' +import { UsersService } from './users.service' +import { UserDto, AvatarUploadDto } from './dto/user.dto' -import { AuthenticatedGuard } from "src/auth/42-auth.guard"; -import { Profile42 } from "src/auth/42.decorator"; -import { Profile } from "passport-42"; +import { AuthenticatedGuard } from 'src/auth/42-auth.guard' +import { Profile42 } from 'src/auth/42.decorator' +import { Profile } from 'passport-42' -import { ApiBody, ApiConsumes } from "@nestjs/swagger"; -import { type Request, Response } from "express"; -import { createReadStream } from "fs"; -import { join } from "path"; +import { ApiBody, ApiConsumes } from '@nestjs/swagger' +import { type Request, Response } from 'express' +import { createReadStream } from 'fs' +import { join } from 'path' -@Controller("users") +@Controller('users') export class UsersController { - constructor(private readonly usersService: UsersService) {} + constructor (private readonly usersService: UsersService) {} + @Post('block/:id') @UseGuards(AuthenticatedGuard) - @Post("block/:id") - async blockUser(@Profile42() profile :Profile, @Param('id') id:number) { - const user = await this.usersService.findUser(id) as User + async blockUser ( + @Profile42() profile: Profile, + @Param('id', ParseIntPipe) id: number + ) { + const user = (await this.usersService.findUser(id)) as User user.blocked.push((await this.usersService.findUser(+profile.id)) as User) - this.usersService.save(user); + this.usersService.save(user) } + @Post('unblock/:id') @UseGuards(AuthenticatedGuard) - @Post("unblock/:id") - async unblockUser(@Profile42() profile :Profile, @Param('id') id:number) { - const user = await this.usersService.findUser(id) as User - user.blocked = user.blocked.filter((usr: User) => { + async unblockUser (@Param('id', ParseIntPipe) id: number) { + const user = (await this.usersService.findUser(id)) as User + user.blocked = user.blocked.filter((usr: User) => { return usr.id !== id }) - this.usersService.save(user); + this.usersService.save(user) } @Get('all') @@ -58,151 +60,145 @@ export class UsersController { return await this.usersService.findUsers() } - @Get("online") - async getOnlineUsers(): Promise { - return await this.usersService.findOnlineUsers(); + @Get('online') + async getOnlineUsers (): Promise { + return await this.usersService.findOnlineUsers() } - @Get("friends") + @Get('friends') @UseGuards(AuthenticatedGuard) - async getFriends(@Profile42() profile: Profile): Promise { - return await this.usersService.getFriends(profile.id); + async getFriends (@Profile42() profile: Profile): Promise { + return await this.usersService.getFriends(profile.id) } - @Get("invits") + @Get('invits') @UseGuards(AuthenticatedGuard) - async getInvits(@Profile42() profile: Profile): Promise { - return await this.usersService.getInvits(profile.id); + async getInvits (@Profile42() profile: Profile): Promise { + return await this.usersService.getInvits(profile.id) } - @Get("leaderboard") + @Get('leaderboard') @UseGuards(AuthenticatedGuard) - async getLeaderboard(): Promise { - return await this.usersService.getLeaderboard(); + async getLeaderboard (): Promise { + return await this.usersService.getLeaderboard() } - @Post("avatar") + @Post('avatar') @UseGuards(AuthenticatedGuard) - @Redirect("http://localhost") + @Redirect('http://localhost') @UseInterceptors( - FileInterceptor("avatar", { + FileInterceptor('avatar', { storage: diskStorage({ - destination: "avatars/", + destination: 'avatars/' }), fileFilter: (request: Request, file: Express.Multer.File, callback) => { -<<<<<<< HEAD if (!file.mimetype.includes('image')) { callback(null, false) - return -======= - if (!file.mimetype.includes("image")) { - callback(null, false); - return; ->>>>>>> ouai c un peu la merde mais bon + return } - callback(null, true); - }, + callback(null, true) + } }) ) - @ApiConsumes("multipart/form-data") + @ApiConsumes('multipart/form-data') @ApiBody({ - description: "A new avatar for the user", - type: AvatarUploadDto, + description: 'A new avatar for the user', + type: AvatarUploadDto }) - async changeAvatar( + async changeAvatar ( @Profile42() profile: Profile, - @UploadedFile() file: Express.Multer.File + @UploadedFile() file: Express.Multer.File ): Promise { - if (file === undefined) return; - await this.usersService.addAvatar(profile.id, file.filename); + if (file === undefined) return + await this.usersService.addAvatar(profile.id, file.filename) } - @Get("avatar") + @Get('avatar') @UseGuards(AuthenticatedGuard) - async getAvatar( + async getAvatar ( @Profile42() profile: Profile, - @Res({ passthrough: true }) response: Response + @Res({ passthrough: true }) response: Response ): Promise { - return await this.getAvatarById(profile.id, response); + return await this.getAvatarById(profile.id, response) } - @Get(":name/byname") - async getUserByName(@Param("name") username: string): Promise { - const user = await this.usersService.findUserByName(username); - user.socketKey = ""; - return user; + @Get(':name/byname') + async getUserByName (@Param('name') username: string): Promise { + const user = await this.usersService.findUserByName(username) + user.socketKey = '' + return user } - @Get("invit/:username") + @Get('invit/:username') @UseGuards(AuthenticatedGuard) - async invitUser( + async invitUser ( @Profile42() profile: Profile, - @Param("username") username: string + @Param('username') username: string ): Promise { const target: User | null = await this.usersService.findUserByName( username - ); + ) if (target === null) { - throw new BadRequestException(`User ${username} not found.`); + throw new BadRequestException(`User ${username} not found.`) } if (+profile.id === +target.ftId) { - throw new BadRequestException("You can't invite yourself."); + throw new BadRequestException("You can't invite yourself.") } - const ret: string = await this.usersService.invit(profile.id, target.ftId); - if (ret !== "OK") throw new BadRequestException(ret); + const ret: string = await this.usersService.invit(profile.id, target.ftId) + if (ret !== 'OK') throw new BadRequestException(ret) } - @Get(":id/avatar") - async getAvatarById( - @Param("id", ParseIntPipe) ftId: number, - @Res({ passthrough: true }) response: Response + @Get(':id/avatar') + async getAvatarById ( + @Param('id', ParseIntPipe) ftId: number, + @Res({ passthrough: true }) response: Response ): Promise { - const user: User | null = await this.usersService.findUser(ftId); - if (user === null) throw new BadRequestException("User unknown."); - const filename = user.avatar; - const stream = createReadStream(join(process.cwd(), "avatars/" + filename)); + const user: User | null = await this.usersService.findUser(ftId) + if (user === null) throw new BadRequestException('User unknown.') + const filename = user.avatar + const stream = createReadStream(join(process.cwd(), 'avatars/' + filename)) response.set({ - "Content-Diposition": `inline; filename='${filename}'`, - "Content-Type": "image/jpg", - }); - return new StreamableFile(stream); + 'Content-Diposition': `inline; filename='${filename}'`, + 'Content-Type': 'image/jpg' + }) + return new StreamableFile(stream) } - @Get(":id") - async getUserById( - @Param("id", ParseIntPipe) ftId: number + @Get(':id') + async getUserById ( + @Param('id', ParseIntPipe) ftId: number ): Promise { - const user = await this.usersService.findUser(ftId); - if (user == null) throw new BadRequestException("User unknown."); - user.socketKey = ""; - return user; + const user = await this.usersService.findUser(ftId) + if (user == null) throw new BadRequestException('User unknown.') + user.socketKey = '' + return user } - @Post(":id") + @Post(':id') @UseGuards(AuthenticatedGuard) - async createById(@Body() payload: UserDto): Promise { - const user = await this.usersService.findUser(payload.ftId); + async createById (@Body() payload: UserDto): Promise { + const user = await this.usersService.findUser(payload.ftId) if (user != null) { - await this.usersService.update(user, payload); + await this.usersService.update(user, payload) } else { - await this.usersService.create(payload); + await this.usersService.create(payload) } } @Get() @UseGuards(AuthenticatedGuard) - async getUser(@Profile42() profile: Profile): Promise { - return await this.usersService.findUser(profile.id); + async getUser (@Profile42() profile: Profile): Promise { + return await this.usersService.findUser(profile.id) } @Post() @UseGuards(AuthenticatedGuard) - async updateUser( + async updateUser ( @Body() payload: UserDto, - @Profile42() profile: Profile + @Profile42() profile: Profile ): Promise { - const user = await this.usersService.findUser(profile.id); - if (user == null) throw new BadRequestException("User not found."); - return await this.usersService.update(user, payload); + const user = await this.usersService.findUser(profile.id) + if (user == null) throw new BadRequestException('User not found.') + return await this.usersService.update(user, payload) } } diff --git a/back/volume/src/users/users.module.ts b/back/volume/src/users/users.module.ts index cd0e3d7..f0cf838 100644 --- a/back/volume/src/users/users.module.ts +++ b/back/volume/src/users/users.module.ts @@ -1,15 +1,15 @@ -import { forwardRef, Module } from "@nestjs/common"; -import { TypeOrmModule } from "@nestjs/typeorm"; -import { User } from "./entity/user.entity"; -import { UsersController } from "./users.controller"; -import { UsersService } from "./users.service"; -import { PongModule } from "src/pong/pong.module"; -import { ChatModule } from "src/chat/chat.module"; +import { forwardRef, Module } from '@nestjs/common' +import { TypeOrmModule } from '@nestjs/typeorm' +import { User } from './entity/user.entity' +import { UsersController } from './users.controller' +import { UsersService } from './users.service' +import { PongModule } from 'src/pong/pong.module' +import { ChatModule } from 'src/chat/chat.module' @Module({ imports: [forwardRef(() => PongModule), TypeOrmModule.forFeature([User])], controllers: [UsersController], providers: [UsersService], - exports: [UsersService], + exports: [UsersService] }) export class UsersModule {} diff --git a/back/volume/src/users/users.service.ts b/back/volume/src/users/users.service.ts index 5c3e897..6db23a3 100644 --- a/back/volume/src/users/users.service.ts +++ b/back/volume/src/users/users.service.ts @@ -1,184 +1,184 @@ -import { BadRequestException, Catch, Injectable } from "@nestjs/common"; -import { InjectRepository } from "@nestjs/typeorm"; -import { EntityNotFoundError, QueryFailedError, Repository } from "typeorm"; -import { Cron } from "@nestjs/schedule"; -import { randomUUID } from "crypto"; +import { BadRequestException, Catch, Injectable } from '@nestjs/common' +import { InjectRepository } from '@nestjs/typeorm' +import { EntityNotFoundError, QueryFailedError, Repository } from 'typeorm' +import { Cron } from '@nestjs/schedule' +import { randomUUID } from 'crypto' -import { type UserDto } from "./dto/user.dto"; -import type Channel from "src/chat/entity/channel.entity"; -import User from "./entity/user.entity"; +import { type UserDto } from './dto/user.dto' +import type Channel from 'src/chat/entity/channel.entity' +import User from './entity/user.entity' @Injectable() @Catch(QueryFailedError, EntityNotFoundError) export class UsersService { - constructor( + constructor ( @InjectRepository(User) private readonly usersRepository: Repository ) {} - async save(user: User): Promise { - await this.usersRepository.save(user); + async save (user: User): Promise { + await this.usersRepository.save(user) } - async findUsers(): Promise { - const users = await this.usersRepository.find({}); - users.forEach((usr) => (usr.socketKey = "")); - return users; + async findUsers (): Promise { + const users = await this.usersRepository.find({}) + users.forEach((usr) => (usr.socketKey = '')) + return users } - async findUserByName(username: string): Promise { + async findUserByName (username: string): Promise { const user = await this.usersRepository.findOne({ where: { username }, - relations: { results: true }, - }); - if (user == null) throw new BadRequestException("User not found."); - return user; + relations: { results: true } + }) + if (user == null) throw new BadRequestException('User not found.') + return user } - @Cron("0 * * * * *") - async updateStatus(): Promise { - const users = await this.usersRepository.find({}); + @Cron('0 * * * * *') + async updateStatus (): Promise { + const users = await this.usersRepository.find({}) users.forEach((usr) => { if (Date.now() - usr.lastAccess > 60000) { - usr.isVerified = false; - usr.status = "offline"; + usr.isVerified = false + usr.status = 'offline' this.usersRepository.save(usr).catch((err) => { - console.log(err); - }); + console.log(err) + }) } - }); - this.getLeaderboard(); + }) + this.getLeaderboard() } - async findUser(ftId: number): Promise { - const user = await this.usersRepository.findOneBy({ ftId }); - if (user == null) return null; - user.lastAccess = Date.now(); - if (user.status === "offline") user.status = "online"; - await this.usersRepository.save(user); - return user; + async findUser (ftId: number): Promise { + const user = await this.usersRepository.findOneBy({ ftId }) + if (user == null) return null + user.lastAccess = Date.now() + if (user.status === 'offline') user.status = 'online' + await this.usersRepository.save(user) + return user } - async findOnlineUsers(): Promise { + async findOnlineUsers (): Promise { const users = await this.usersRepository.find({ - where: { status: "online" }, - }); - users.forEach((usr) => (usr.socketKey = "")); - return users; + where: { status: 'online' } + }) + users.forEach((usr) => (usr.socketKey = '')) + return users } - async create(userData: UserDto): Promise { + async create (userData: UserDto): Promise { try { - const newUser = this.usersRepository.create(userData); - newUser.socketKey = randomUUID(); - return await this.usersRepository.save(newUser); + const newUser = this.usersRepository.create(userData) + newUser.socketKey = randomUUID() + return await this.usersRepository.save(newUser) } catch (err) { - throw new BadRequestException("User already exists."); + throw new BadRequestException('User already exists.') } } - async findOnlineInChannel(channel: Channel): Promise { + async findOnlineInChannel (channel: Channel): Promise { return await this.usersRepository - .createQueryBuilder("user") - .where("user.channel = :chan", { chan: channel }) - .andWhere("user.status := status)", { status: "online" }) - .getMany(); + .createQueryBuilder('user') + .where('user.channel = :chan', { chan: channel }) + .andWhere('user.status := status)', { status: 'online' }) + .getMany() } - async update(user: User, changes: UserDto): Promise { - this.usersRepository.merge(user, changes); - return await this.usersRepository.save(user); + async update (user: User, changes: UserDto): Promise { + this.usersRepository.merge(user, changes) + return await this.usersRepository.save(user) } - async addAvatar(ftId: number, filename: string): Promise { - await this.usersRepository.update({ ftId }, { avatar: filename }); + async addAvatar (ftId: number, filename: string): Promise { + await this.usersRepository.update({ ftId }, { avatar: filename }) } - async getFriends(ftId: number): Promise { + async getFriends (ftId: number): Promise { const user = await this.usersRepository.findOne({ where: { ftId }, - relations: { friends: true }, - }); - if (user == null) throw new BadRequestException("User not found."); - user.friends.forEach((friend) => (friend.socketKey = "")); - return user.friends; + relations: { friends: true } + }) + if (user == null) throw new BadRequestException('User not found.') + user.friends.forEach((friend) => (friend.socketKey = '')) + return user.friends } - async getInvits(ftId: number): Promise { + async getInvits (ftId: number): Promise { const user = await this.usersRepository.findOne({ where: { ftId }, relations: { - followers: true, - }, - }); - if (user == null) throw new BadRequestException("User not found."); - user.followers.forEach((follower) => (follower.socketKey = "")); - return user.followers; + followers: true + } + }) + if (user == null) throw new BadRequestException('User not found.') + user.followers.forEach((follower) => (follower.socketKey = '')) + return user.followers } - async getLeaderboard(): Promise { + async getLeaderboard (): Promise { const leaderboard = await this.usersRepository.find({ order: { - winrate: "ASC", - }, - }); - const ret = leaderboard.filter((user) => user.matchs !== 0); - let r = 0; + winrate: 'ASC' + } + }) + const ret = leaderboard.filter((user) => user.matchs !== 0) + let r = 0 ret.forEach((usr) => { - usr.rank = r++; - this.usersRepository.save(usr); - usr.socketKey = ""; - }); - return ret; + usr.rank = r++ + this.usersRepository.save(usr) + usr.socketKey = '' + }) + return ret } - async invit(ftId: number, targetFtId: number): Promise { + async invit (ftId: number, targetFtId: number): Promise { const user: User | null = await this.usersRepository.findOne({ where: { ftId }, relations: { followers: true, - friends: true, - }, - }); - if (user === null) throw new BadRequestException("User not found."); + friends: true + } + }) + if (user === null) throw new BadRequestException('User not found.') if (user.friends.findIndex((friend) => friend.ftId === targetFtId) !== -1) { - return "You are already friends."; + return 'You are already friends.' } const target: User | null = await this.usersRepository.findOne({ where: { ftId: targetFtId }, relations: { followers: true, - friends: true, - }, - }); - if (target == null) return "Target not found."; + friends: true + } + }) + if (target == null) return 'Target not found.' const id = user.followers.findIndex( (follower) => follower.ftId === targetFtId - ); + ) if ( target.followers.findIndex((follower) => follower.ftId === user.ftId) !== -1 ) { - return "Invitation already sent."; + return 'Invitation already sent.' } else if ( user.followers.findIndex((follower) => follower.ftId === targetFtId) !== -1 ) { - user.friends.push(target); - target.friends.push(user); - user.followers.splice(id, 1); - await this.usersRepository.save(user); - } else target.followers.push(user); - await this.usersRepository.save(target); - return "OK"; + user.friends.push(target) + target.friends.push(user) + user.followers.splice(id, 1) + await this.usersRepository.save(user) + } else target.followers.push(user) + await this.usersRepository.save(target) + return 'OK' } - async findByCode(code: string): Promise { - const user = await this.usersRepository.findOneBy({ authToken: code }); - if (user == null) throw new BadRequestException("User not found"); - return user; + async findByCode (code: string): Promise { + const user = await this.usersRepository.findOneBy({ authToken: code }) + if (user == null) throw new BadRequestException('User not found') + return user } - async turnOnTwoFactorAuthentication(ftId: number): Promise { - await this.usersRepository.update({ ftId }, { twoFA: true }); + async turnOnTwoFactorAuthentication (ftId: number): Promise { + await this.usersRepository.update({ ftId }, { twoFA: true }) } } diff --git a/front/volume/src/components/Chat.svelte b/front/volume/src/components/Chat.svelte index 3bf3aa5..81023cf 100644 --- a/front/volume/src/components/Chat.svelte +++ b/front/volume/src/components/Chat.svelte @@ -1,392 +1,388 @@ - - < script lang = "ts" > - //--------------------------------------------------------------------------------/ - - let blockedUsers: Array = []; -let chatMembers: Array = []; -let chatMessages: Array = []; -export let channel: ChannelsType; -let newText = ""; -onMount(async () => { - let res = await fetch(API_URL + "/users/" + $store.ftId + "/blocked", { - credentials: "include", - mode: "cors", - }); - if (res.ok) blockedUsers = await res.json(); - - res = await fetch(API_URL + "/channels/" + channel.id + "/members", { - credentials: "include", - mode: "cors", - }); - if (res.ok) chatMembers = await res.json(); - - io.on("messages", (msgs: Array) => { - chatMessages = msgs; - }); - - io.on("newMessage", (msg: chatMessagesType) => { - chatMessages = [...chatMessages.slice(-5 + 1), msg]; - }); - - onDestroy(() => { - io.emit("leaveChannel", channel.id, $store.ftId); - }); -}); - -//--------------------------------------------------------------------------------/ - -const sendMessage = () => { - if (newText !== "") { - const newMessage = { - id: chatMessages.length + 1, - author: $store.username, - text: newText, - }; - chatMessages = [...chatMessages.slice(-5 + 1)]; - io.emit("addMessage", channel.id, $store.ftId, newText); - newText = ""; - const messagesDiv = document.querySelector(".messages"); - if (messagesDiv) { - messagesDiv.scrollTop = messagesDiv.scrollHeight; - } - } -}; - -//--------------------------------------------------------------------------------/ - -const dispatch = createEventDispatcher(); -let showProfileMenu = false; -let selectedUser = null; -function openProfile(username: string) { - showProfileMenu = true; - selectedUser = username; - showChatMembers = false; -} -function closeProfileMenu() { - showProfileMenu = false; - selectedUser = ""; -} -onMount(closeProfileMenu); - -//--------------------------------------------------------------------------------/ - -let showChatMembers = false; -function toggleChatMembers() { - showChatMembers = !showChatMembers; -} - -//--------------------------------------------------------------------------------/ - -const blockUser = async (username: string) => { - const res1 = await fetch(API_URL + "/users/" + username + "/byname", { - credentials: "include", - mode: "cors", - }); - const data1 = await res1.json(); - const res2 = await fetch(API_URL + "/users/block/" + data1.ftId, { - credentials: "include", - method: "POST", - mode: "cors", - }); - const data2 = await res2.json(); - if (res2.ok) { - alert("User blocked"); - } else { - alert("Failed to block user"); - } -}; - -//--------------------------------------------------------------------------------/ - -const unblockUser = async (username: string) => { - const res1 = await fetch(API_URL + "/users/" + username + "/byname", { - credentials: "include", - mode: "cors", - }); - const data1 = await res1.json(); - const res2 = await fetch(API_URL + "/users/unblock/" + data1.ftId, { - credentials: "include", - method: "DELETE", - mode: "cors", - }); - const data2 = await res2.json(); - if (res2.ok) { - alert("User unblocked"); - } else { - alert("Failed to unblock user"); - } -}; - -//--------------------------------------------------------------------------------/ - -const banUser = async (username: string) => { - const prompt = window.prompt("Enter ban duration in seconds"); - const res1 = await fetch(API_URL + "/users/" + username + "/byname", { - credentials: "include", - mode: "cors", - }); - const data1 = await res1.json(); - const res2 = await fetch(API_URL + "/channels/" + data1.ftId + "/ban", { - credentials: "include", - method: "POST", - mode: "cors", - }); - const data2 = await res2.json(); - if (res2.ok) { - io.emit("kickUser", channel.id, $store.ftId, data1.ftId); - alert("User banned"); - } else { - alert("Failed to ban user"); - } -}; - -//--------------------------------------------------------------------------------/ - -const kickUser = async (username: string) => { - const res = await fetch(API_URL + "/users/" + username + "/byname", { - credentials: "include", - mode: "cors", - }); - const kickedUser = await res.json(); - io.emit("kickUser", channel.id, $store.ftId, kickedUser.ftId); -}; - -//--------------------------------------------------------------------------------/ - -const muteUser = async (username: string) => { - const prompt = window.prompt("Enter mute duration in seconds"); - const res1 = await fetch(API_URL + "/users/" + username + "/byname", { - credentials: "include", - mode: "cors", - }); - const data1 = await res1.json(); - const res2 = await fetch(API_URL + "/channels/" + data1.ftId + "/mute", { - credentials: "include", - method: "POST", - mode: "cors", - }); - const data2 = await res2.json(); - if (res2.ok) { - alert("User muted"); - } else { - alert("Failed to mute user"); - } -}; - -//--------------------------------------------------------------------------------/ - -const adminUser = async (username: string) => { - const res1 = await fetch(API_URL + "/users/" + username + "/byname", { - credentials: "include", - mode: "cors", - }); - const data1 = await res1.json(); - const res2 = await fetch(API_URL + "/channels/" + data1.ftId + "/admin", { - credentials: "include", - method: "POST", - mode: "cors", - }); - const data2 = await res2.json(); - if (res2.ok) { - alert("User admined"); - } else { - alert("Failed to admin user"); - } -}; - -//--------------------------------------------------------------------------------/ - -const removeAdminUser = async (username: string) => { - const res1 = await fetch(API_URL + "/users/" + username + "/byname", { - credentials: "include", - mode: "cors", - }); - const data1 = await res1.json(); - const res2 = await fetch(API_URL + "/channels/" + data1.ftId + "/admin", { - credentials: "include", - method: "DELETE", - mode: "cors", - }); - const data2 = await res2.json(); - if (res2.ok) { - alert("User admin removed"); - } else { - alert("Failed to remove admin user"); - } -}; - -//--------------------------------------------------------------------------------/ + - < div class="overlay" > -
-
- { #each chatMessages as message } - < p class="message" > - { #if !blockedUsers.filter((user) => user.username == message.author).length } - < span -class="message-name" -on: click = {() => openProfile(message.author)} -on: keydown = {() => openProfile(message.author)} -style = "cursor: pointer;" - > - { message.author } - < /span>: {message.text} -{ - /if} - < /p> - { - /each} - < /div> - { #if showProfileMenu } -
+
+
+ {#each chatMessages as message} +

+ {#if !blockedUsers.filter((user) => user.username == message.author).length} + openProfile(message.author)} + on:keydown={() => openProfile(message.author)} + style="cursor: pointer;" + > + {message.author} + : {message.text} + {/if} +

+ {/each} +
+ {#if showProfileMenu} +
-
    -
  • -
  • - < li > -
- < /div> - { - /if} - < form on: submit | preventDefault={ sendMessage }> - - - < /form> - < button - on: click | stopPropagation={ toggleChatMembers } - on: keydown | stopPropagation > Chat Members < /button - > - { #if showChatMembers } - < div - class="chatMembers" - on: click | stopPropagation - on: keydown | stopPropagation - > -
-
    - { #each chatMembers as member } - < li > -

    - { member.username } - < button on: click = {() => banUser(member.username) - }> ban < /button> - < button on: click = {() => kickUser(member.username) -} - > kick < /button - > - + +

  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + {#if !blockedUsers.filter((user) => (user.username = selectedUser)).length} + + {:else} + + {/if} +
  • +
  • +
+
+ {/if} +
+ + +
+ + {#if showChatMembers} +
+
+
    + {#each chatMembers as member} +
  • +

    + {member.username} + + + + + +

    +

    + ----------------------------------------------------------------------------------- +

    +
  • + {/each} +
+
+
+ {/if} +
+
+ width: 6rem; + } +