diff --git a/events b/events index 49829c8..e9d5d8d 160000 --- a/events +++ b/events @@ -1 +1 @@ -Subproject commit 49829c8017b37b2fad75eb6ed658d6eba2c13304 +Subproject commit e9d5d8d909e4ba952f6bed53ead08642466431d1 diff --git a/package-lock.json b/package-lock.json index 12c8bd3..b2be149 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,6 @@ "@nestjs/swagger": "^7.3.1", "@nestjs/typeorm": "^10.0.2", "@types/ranjs": "^1.22.7", - "class-transformer": "^0.5.1", "connect-redis": "^8.0.1", "express-session": "^1.18.0", "pg": "^8.13.1", @@ -4749,7 +4748,9 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/clean-stack": { "version": "2.2.0", diff --git a/package.json b/package.json index b0f4d66..7f41146 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "@nestjs/swagger": "^7.3.1", "@nestjs/typeorm": "^10.0.2", "@types/ranjs": "^1.22.7", - "class-transformer": "^0.5.1", "connect-redis": "^8.0.1", "express-session": "^1.18.0", "pg": "^8.13.1", diff --git a/src/games/services/lobby.service.ts b/src/games/services/lobby.service.ts index 8c8c433..20cceb5 100644 --- a/src/games/services/lobby.service.ts +++ b/src/games/services/lobby.service.ts @@ -8,10 +8,12 @@ import { User } from 'src/users/entities/user.entity'; import { Player } from '../entities/player.entity'; import { randomUUID } from 'node:crypto'; import { - GameCreateEvent, - GameDeleteEvent, - GameJoinEvent, + LobbyCreateEvent, + LobbyDeleteEvent, + LobbyJoinEvent, } from 'events/lobby.events'; +import { GameResponseDTO } from 'events/dto/gameresponse.dto'; +import { GameDeleteEvent, GameJoinEvent } from 'events/game.events'; @Injectable() export class LobbyService { @@ -28,7 +30,8 @@ export class LobbyService { createdGame.seed = randomUUID(); await this.gameRepository.save(createdGame); await this.joinGame(createdGame, owner); - this.eventEmitter.emit('sse.lobby', new GameCreateEvent(createdGame)); + const g = new GameResponseDTO(createdGame); + this.eventEmitter.emit('sse.lobby', new LobbyCreateEvent(g)); return createdGame; } @@ -37,7 +40,7 @@ export class LobbyService { player.user = user; player.game = game; - this.eventEmitter.emit('sse.lobby', new GameJoinEvent(player, game)); + this.eventEmitter.emit('sse.lobby', new LobbyJoinEvent(player, game)); this.eventEmitter.emit('sse.game.' + game.id, new GameJoinEvent(player)); await this.playerRepository.save(player); } @@ -59,7 +62,7 @@ export class LobbyService { } async remove(game: Game) { - this.eventEmitter.emit('sse.lobby', new GameDeleteEvent(game.id)); + this.eventEmitter.emit('sse.lobby', new LobbyDeleteEvent(game.id)); this.eventEmitter.emit('sse.game.' + game.id, new GameDeleteEvent()); await this.gameRepository.remove(game); } diff --git a/src/main.ts b/src/main.ts index 449bfd7..b0e6f2e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,7 +2,6 @@ import { NestFactory, Reflector } from '@nestjs/core'; import * as session from 'express-session'; import { AppModule } from './app.module'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; -import { ClassSerializerInterceptor, INestApplication } from '@nestjs/common'; import { RedisStore } from 'connect-redis'; import { createClient } from 'redis'; @@ -31,13 +30,7 @@ async function bootstrap() { }), ); - app.useGlobalInterceptors( - new ClassSerializerInterceptor(app.get(Reflector), { - // strategy: 'excludeAll', 👈 we'll talk about this later - excludeExtraneousValues: true, - }), - ); - await app.listen(8765); } -bootstrap(); + +void bootstrap(); diff --git a/src/users/guards/auth.guard.ts b/src/users/guards/auth.guard.ts index 3a32adf..3bbc0d4 100644 --- a/src/users/guards/auth.guard.ts +++ b/src/users/guards/auth.guard.ts @@ -25,6 +25,8 @@ export class AuthGuard implements CanActivate { HttpStatus.UNAUTHORIZED, ); } + + request.user = user; return true; } } diff --git a/src/users/user.pipe.ts b/src/users/user.pipe.ts index 0401e0a..2ed3f63 100644 --- a/src/users/user.pipe.ts +++ b/src/users/user.pipe.ts @@ -1,17 +1,20 @@ import { createParamDecorator, + ExecutionContext, HttpException, HttpStatus, } from '@nestjs/common'; +import { Request } from 'express'; export const GetUser = createParamDecorator( - (data: unknown, req: Record) => { - if (!req.user) { + (data: unknown, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + if (!request.user) { throw new HttpException( 'You are not authentified', HttpStatus.UNAUTHORIZED, ); } - return req.user; + return request.user; }, ); diff --git a/src/word/controllers/word.controller.ts b/src/word/controllers/word.controller.ts index 32fabfc..bff0d8c 100644 --- a/src/word/controllers/word.controller.ts +++ b/src/word/controllers/word.controller.ts @@ -44,7 +44,7 @@ export class WordController { ); } - @Delete() + @Delete(':id') @ApiOperation({ summary: 'Delete a word' }) @UseGuards(AuthGuard) async delete(@Param('id') id: number) { @@ -78,19 +78,25 @@ export class WordController { return (await this.wordService.list()).map((w) => new WordResponseDTO(w)); } - @Put('/enable/:id') + @Put(':id/enable') @ApiOperation({ summary: 'Enable a word' }) @UseGuards(AuthGuard) - async enable(@Param('id', ParseIntPipe, WordPipe) word: Word) { + async enable( + @Param('id', ParseIntPipe) _id: string, + @Param('id', WordPipe) word: Word, + ) { await this.wordService.enable(word); return new WordResponseDTO(word); } - @Put('/disable/:id') + @Put(':id/disable') @ApiOperation({ summary: 'Disable a word' }) @UseGuards(AuthGuard) - async disable(@Param('id', ParseIntPipe, WordPipe) word: Word) { - await this.wordService.enable(word); + async disable( + @Param('id', ParseIntPipe) _id: string, + @Param('id', WordPipe) word: Word, + ) { + await this.wordService.disable(word); return new WordResponseDTO(word); } } diff --git a/src/word/services/word.service.ts b/src/word/services/word.service.ts index 4ab4a53..d5c57e6 100644 --- a/src/word/services/word.service.ts +++ b/src/word/services/word.service.ts @@ -1,4 +1,9 @@ -import { Injectable } from '@nestjs/common'; +import { + HttpCode, + HttpException, + HttpStatus, + Injectable, +} from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Word } from '../entities/word.entity'; @@ -10,6 +15,7 @@ import { WordDisableEvent, WordEnableEvent, } from '../../../events/word.events'; +import { HttpErrorByCode } from '@nestjs/common/utils/http-error-by-code.util'; @Injectable() export class WordService { @@ -24,17 +30,22 @@ export class WordService { } async delete(word: Word) { + const wordId = word.id; await this.wordRepository.remove(word); - this.eventEmitter.emit(this.sse_prefix, new WordDeleteEvent(word.id)); + this.eventEmitter.emit(this.sse_prefix, new WordDeleteEvent(wordId)); } async create(value: string, owner: User) { const word = this.wordRepository.create(); word.owner = owner; word.value = value; - await this.wordRepository.save(word); - this.eventEmitter.emit(this.sse_prefix, new WordCreateEvent(word)); - return word; + try { + await this.wordRepository.save(word); + this.eventEmitter.emit(this.sse_prefix, new WordCreateEvent(word)); + return word; + } catch { + throw new HttpException('Word already exists', HttpStatus.CONFLICT); + } } async listActive() { diff --git a/types.d.ts/express-session.d.ts b/types.d.ts/express-session.d.ts index e7c28ea..0947bee 100644 --- a/types.d.ts/express-session.d.ts +++ b/types.d.ts/express-session.d.ts @@ -10,3 +10,9 @@ declare module 'express-session' { }; } } + +declare module 'express' { + interface Request extends Request { + user: User; + } +}