From c5c6495909f1f0151fd51726990d1b57dd83b435 Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Wed, 21 Feb 2024 15:44:22 -0800 Subject: [PATCH] Fix/backend/strict null check (#279) * [backend] Enable strictNullChecks in tsconfig.json * [backend] Fix handleDisconnect to handle null user * [backend] Fix MessageEntity constructor by strict null check * [backend] Fix WsPublicUserEntity constructor by using the correct type * [backend] Fix match request handlers - Naming consistency - Use match request instead of invite * [backend] Fix UpdateUserOnRoomDto to not use PartialType - because the properties are required, it should not use PartialType * [backend] Fix RoomEntity password type to be nullable - Align with the prisma schema * [backend] Fix UserEntity password type to be nullable - To align with prisma schema - But it is not desirable to have nullable password field * [backend] Fix PublicUserEntity password type to be nullable * [backend] Fix mute and ban services to use findUniqueOrThrow * [backend] Fix strict null check in enter-room.guard.ts * [backend] Fix strict null check for events.gateway.ts * [backend] Fix strict null check in auth service * [backend] Fix strict null check in seed.ts * [backend] Fix strict null check in main.ts * [backend] Fix strict null check in events.gateway.ts * [backend] Fix WsPublicUserEntity constructor * [backend] Remove CreateUserOnRoomDto (which is not used) --- backend/prisma/seed.ts | 21 +++-- backend/src/auth/auth.service.ts | 59 +++++++++----- backend/src/chat/chat.gateway.ts | 80 +++++++++++++------ backend/src/chat/chat.service.ts | 26 +++--- backend/src/chat/entities/message.entity.ts | 22 ++--- backend/src/events/events.gateway.ts | 15 ++-- backend/src/main.ts | 6 +- backend/src/room/ban/ban.service.ts | 2 +- backend/src/room/dto/update-UserOnRoom.dto.ts | 4 - ...Room.dto.ts => update-user-on-room.dto.ts} | 2 +- backend/src/room/entities/room.entity.ts | 2 +- backend/src/room/guards/enter-room.guard.ts | 3 + backend/src/room/mute/mute.service.ts | 2 +- backend/src/room/room.controller.ts | 2 +- backend/src/room/room.service.ts | 13 ++- .../src/user/entities/public-user.entity.ts | 2 +- backend/src/user/entities/user.entity.ts | 2 +- backend/test/utils/app.ts | 2 +- backend/tsconfig.json | 2 +- 19 files changed, 162 insertions(+), 105 deletions(-) delete mode 100644 backend/src/room/dto/update-UserOnRoom.dto.ts rename backend/src/room/dto/{create-UserOnRoom.dto.ts => update-user-on-room.dto.ts} (85%) diff --git a/backend/prisma/seed.ts b/backend/prisma/seed.ts index 9727c7f9..e124983d 100644 --- a/backend/prisma/seed.ts +++ b/backend/prisma/seed.ts @@ -163,19 +163,16 @@ async function seedMatchHistory() { } async function seedFriends(users) { - let promises = []; - for (let i = 0; i < users.length - 1; i++) { - promises.push( - prisma.user.update({ - where: { id: users[users.length - 1].id }, - data: { - friends: { - connect: { id: users[i].id }, - }, + const promises = users.map((user) => { + return prisma.user.update({ + where: { id: users[users.length - 1].id }, + data: { + friends: { + connect: { id: user.id }, }, - }), - ); - } + }, + }); + }); await Promise.all(promises); } diff --git a/backend/src/auth/auth.service.ts b/backend/src/auth/auth.service.ts index fc7eb4b5..3f4af122 100644 --- a/backend/src/auth/auth.service.ts +++ b/backend/src/auth/auth.service.ts @@ -16,6 +16,13 @@ import { TwoFactorAuthenticationDto } from './dto/twoFactorAuthentication.dto'; import { TwoFactorAuthenticationEnableDto } from './dto/twoFactorAuthenticationEnable.dto'; import { AuthEntity } from './entity/auth.entity'; +const constants = { + appName: process.env.TWO_FACTOR_AUTHENTICATION_APP_NAME || 'Pong API', + clientId: process.env.OAUTH_42_CLIENT_ID || 'You need to set this', + clientSecret: process.env.OAUTH_42_CLIENT_SECRET || 'You need to set this', + publicURL: process.env.NEST_PUBLIC_API_URL || 'http://localhost:3000/api', +}; + @Injectable() export class AuthService { constructor( @@ -24,7 +31,7 @@ export class AuthService { ) {} async login(email: string, password: string): Promise { - const user = await this.prisma.user.findUnique({ where: { email } }); + const user = await this.prisma.user.findUniqueOrThrow({ where: { email } }); if (!user) { throw new NotFoundException(`No user found for email: ${email}`); @@ -36,6 +43,11 @@ export class AuthService { ); } + // This should not happen : password should be set for all users except oauth users + if (!user.password) { + throw new UnauthorizedException('Password is not set for this user'); + } + const isPasswordValid = await bcrypt.compare(password, user.password); if (!isPasswordValid) { @@ -66,14 +78,16 @@ export class AuthService { async generateTwoFactorAuthenticationSecret(userId: number) { return this.prisma.$transaction(async (prisma) => { - const user = await prisma.user.findUnique({ where: { id: userId } }); + const user = await prisma.user.findUniqueOrThrow({ + where: { id: userId }, + }); if (user.twoFactorEnabled) { throw new ConflictException('2FA secret is already enabled'); } const secret = authenticator.generateSecret(); const otpAuthUrl = authenticator.keyuri( user.email, - process.env.TWO_FACTOR_AUTHENTICATION_APP_NAME, + constants.appName, secret, ); await prisma.user.update({ @@ -93,10 +107,10 @@ export class AuthService { }) { const form = new URLSearchParams({ grant_type: 'authorization_code', - client_id: process.env.OAUTH_42_CLIENT_ID, - client_secret: process.env.OAUTH_42_CLIENT_SECRET, + client_id: constants.clientId, + client_secret: constants.clientSecret, code: code, - redirect_uri: process.env.NEST_PUBLIC_API_URL + redirect_uri, + redirect_uri: constants.publicURL + redirect_uri, }); return fetch('https://api.intra.42.fr/oauth/token', { @@ -190,23 +204,24 @@ export class AuthService { return toFileStream(stream, otpAuthUrl); } - isTwoFactorAuthenticationCodeValid(code: string, user: User) { - return authenticator.verify({ token: code, secret: user.twoFactorSecret }); - } - enableTwoFactorAuthentication( dto: TwoFactorAuthenticationEnableDto, userId: number, ) { return this.prisma.$transaction(async (prisma) => { - let user = await prisma.user.findUnique({ where: { id: userId } }); + let user = await prisma.user.findUniqueOrThrow({ where: { id: userId } }); if (user.twoFactorEnabled) { throw new ConflictException('2FA secret is already enabled'); } - const isCodeValid = this.isTwoFactorAuthenticationCodeValid( - dto.code, - user, - ); + if (!user.twoFactorSecret) { + throw new ConflictException( + '2FA secret is not generated for this user', + ); + } + const isCodeValid = authenticator.verify({ + token: dto.code, + secret: user.twoFactorSecret, + }); if (!isCodeValid) { throw new UnauthorizedException('Invalid 2FA code'); } @@ -226,7 +241,7 @@ export class AuthService { disableTwoFactorAuthentication(userId: number) { return this.prisma.$transaction(async (prisma) => { - let user = await prisma.user.findUnique({ where: { id: userId } }); + let user = await prisma.user.findUniqueOrThrow({ where: { id: userId } }); if (!user.twoFactorEnabled) { throw new ConflictException('2FA secret is not enabled'); } @@ -247,11 +262,19 @@ export class AuthService { } async twoFactorAuthenticate(dto: TwoFactorAuthenticationDto, userId: number) { - const user = await this.prisma.user.findUnique({ where: { id: userId } }); + const user = await this.prisma.user.findUniqueOrThrow({ + where: { id: userId }, + }); if (!user.twoFactorEnabled) { throw new ConflictException('2FA secret is not enabled'); } - const isCodeValid = this.isTwoFactorAuthenticationCodeValid(dto.code, user); + if (!user.twoFactorSecret) { + throw new ConflictException('2FA secret is not generated for this user'); + } + const isCodeValid = authenticator.verify({ + token: dto.code, + secret: user.twoFactorSecret, + }); if (!isCodeValid) { throw new UnauthorizedException('Invalid 2FA code'); } diff --git a/backend/src/chat/chat.gateway.ts b/backend/src/chat/chat.gateway.ts index 62b5728f..2c115283 100644 --- a/backend/src/chat/chat.gateway.ts +++ b/backend/src/chat/chat.gateway.ts @@ -55,6 +55,11 @@ export class ChatGateway { this.logger.error('invalid userId'); return; } + const user = this.chatService.getUser(client); + if (!user) { + this.logger.error('invalid user'); + return; + } const MutedUsers = await this.muteService.findAll(data.roomId); if (MutedUsers.some((user) => user.id === data.userId)) { @@ -68,10 +73,7 @@ export class ChatGateway { const room = this.server .to(data.roomId.toString()) .except('block' + data.userId); - room.emit( - 'message', - new MessageEntity(data, this.chatService.getUser(client)), - ); + room.emit('message', new MessageEntity(data, user)); } @SubscribeMessage('request-match') @@ -79,33 +81,59 @@ export class ChatGateway { @MessageBody() data: { userId: number }, @ConnectedSocket() client: Socket, ) { - const inviteUser = this.chatService.getUser(client); - const invitedUserWsId = this.chatService.getWsFromUserId(data.userId)?.id; - if (!invitedUserWsId) { + // Check if the requesting user is valid + const requestingUser = this.chatService.getUser(client); + if (!requestingUser) { + this.logger.error('invalid requesting user'); + return; + } + // Check if the requested user is connected + const requestedUserWsId = this.chatService.getWsFromUserId(data.userId)?.id; + if (!requestedUserWsId) { + this.logger.error('invalid requested user'); return; - } else { - const blockings = await this.chatService.getUsersBlockedBy(data.userId); - if (blockings.some((user) => user.id === inviteUser.id)) return; - const blocked = await this.chatService.getUsersBlockedBy(inviteUser.id); - if (blocked.some((user) => user.id === data.userId)) return; - this.server - .to(invitedUserWsId) - .emit('request-match', { userId: inviteUser.id }); - this.chatService.addInvite(inviteUser.id, data.userId); } + // Check if the requesting user is blocked by the requested user + const blockings = await this.chatService.getUsersBlockedBy(data.userId); + if (blockings.some((user) => user.id === requestingUser.id)) return; + // Check if the requested user is blocked by the requesting user + const blocked = await this.chatService.getUsersBlockedBy(requestingUser.id); + if (blocked.some((user) => user.id === data.userId)) return; + // Send the request + this.server + .to(requestedUserWsId) + .emit('request-match', { userId: requestingUser.id }); + // Save the request + this.chatService.addMatchRequest(requestingUser.id, data.userId); } @SubscribeMessage('cancel-request-match') handleCancelRequestMatch(@ConnectedSocket() client: Socket) { - const inviteUser = this.chatService.getUser(client); - const invitee = this.chatService.getInvite(inviteUser.id); - if (!invitee) { + // Check if the requesting user is valid + const requestingUser = this.chatService.getUser(client); + if (!requestingUser) { + this.logger.error('invalid requesting user'); + return; + } + // Check if the request exists + const requestedUser = this.chatService.getMatchRequest(requestingUser.id); + if (!requestedUser) { + this.logger.error('invalid requested user'); this.server.to(client.id).emit('error-pong', 'No pending invite found.'); return; } - const inviteeWsId = this.chatService.getWsFromUserId(invitee)?.id; - this.chatService.removeInvite(inviteUser.id); - this.server.to(inviteeWsId).emit('cancel-request-match', inviteUser); + // Cancel the request + this.chatService.removeMatchRequest(requestingUser.id); + // Check if the requested user is connected + const requestedUserWsId = + this.chatService.getWsFromUserId(requestedUser)?.id; + if (!requestedUserWsId) { + return; + } + // Send the cancel request + this.server + .to(requestedUserWsId) + .emit('cancel-request-match', requestingUser); } @SubscribeMessage('approve-pong') @@ -118,7 +146,7 @@ export class ChatGateway { return; } else { if ( - this.chatService.getInvite(data.userId) !== + this.chatService.getMatchRequest(data.userId) !== this.chatService.getUserId(client) ) { this.server @@ -129,7 +157,7 @@ export class ChatGateway { const emitData = { roomId: v4() }; this.server.to(client.id).emit('match-pong', emitData); this.server.to(approvedUserWsId).emit('match-pong', emitData); - this.chatService.removeInvite(data.userId); + this.chatService.removeMatchRequest(data.userId); } } @@ -143,7 +171,7 @@ export class ChatGateway { return; } else { if ( - this.chatService.getInvite(data.userId) !== + this.chatService.getMatchRequest(data.userId) !== this.chatService.getUserId(client) ) { this.server @@ -152,7 +180,7 @@ export class ChatGateway { return; } this.server.to(deniedUserWsId).emit('deny-pong'); - this.chatService.removeInvite(data.userId); + this.chatService.removeMatchRequest(data.userId); } } diff --git a/backend/src/chat/chat.service.ts b/backend/src/chat/chat.service.ts index 94084594..3b165feb 100644 --- a/backend/src/chat/chat.service.ts +++ b/backend/src/chat/chat.service.ts @@ -11,7 +11,7 @@ import { UnblockEvent } from 'src/common/events/unblock.event'; import { PrismaService } from 'src/prisma/prisma.service'; import { UserService } from 'src/user/user.service'; import { CreateMessageDto } from './dto/create-message.dto'; -import { PublicUserEntity } from './entities/message.entity'; +import { WsPublicUserEntity } from './entities/message.entity'; export enum UserStatus { Offline = 0b0, @@ -35,9 +35,9 @@ export class ChatService { // Map private clients = new Map(); - // key: inviter, value: invitee - private users = new Map(); - private invite = new Map(); + private users = new Map(); + // key: requestingUserId, value: requestedUserId + private matchRequests = new Map(); private statuses = new Map(); getUser(client: Socket) { @@ -58,7 +58,7 @@ export class ChatService { addClient(user: User, client: Socket) { this.clients.set(user.id, client); - this.users.set(client.id, new PublicUserEntity(user)); + this.users.set(client.id, new WsPublicUserEntity(user)); } removeClient(client: Socket) { @@ -67,20 +67,20 @@ export class ChatService { this.statuses.delete(user.id); this.clients.delete(user.id); this.users.delete(client.id); - this.removeInvite(user.id); + this.removeMatchRequest(user.id); } } - addInvite(inviterId: number, inviteeId: number) { - this.invite.set(inviterId, inviteeId); + addMatchRequest(requestingUserId: number, requestedUserId: number) { + this.matchRequests.set(requestingUserId, requestedUserId); } - getInvite(inviterId: number) { - return this.invite.get(inviterId); + getMatchRequest(requestingUserId: number) { + return this.matchRequests.get(requestingUserId); } - removeInvite(inviterId: number) { - this.invite.delete(inviterId); + removeMatchRequest(requestingUserId: number) { + this.matchRequests.delete(requestingUserId); } addUserToRoom(roomId: number, userId: number) { @@ -215,7 +215,7 @@ export class ChatService { const emitData = { userId: this.getUserId(client), status: UserStatus.Offline, - name: this.getUser(client).name, + name: this.getUser(client)?.name, }; if (emitData.userId) { client.broadcast.emit('online-status', [emitData]); diff --git a/backend/src/chat/entities/message.entity.ts b/backend/src/chat/entities/message.entity.ts index a16010c8..1311f3a2 100644 --- a/backend/src/chat/entities/message.entity.ts +++ b/backend/src/chat/entities/message.entity.ts @@ -1,21 +1,23 @@ -export class PublicUserEntity { - constructor(partial: Partial) { - this.id = partial.id; - this.name = partial.name; - this.avatarURL = partial.avatarURL; +import { User } from '@prisma/client'; + +export class WsPublicUserEntity { + constructor(user: User) { + this.id = user.id; + this.name = user.name; + this.avatarURL = user.avatarURL; } id: number; name: string; - avatarURL?: string; + avatarURL: string | null; } export class MessageEntity { - constructor(partial: Partial, user: PublicUserEntity) { - this.content = partial.content; - this.roomId = partial.roomId; + constructor(message: Omit, user: WsPublicUserEntity) { + this.content = message.content; + this.roomId = message.roomId; this.user = user; } content: string; roomId: number; - user: PublicUserEntity; + user: WsPublicUserEntity; } diff --git a/backend/src/events/events.gateway.ts b/backend/src/events/events.gateway.ts index a643ee7c..2985cea2 100644 --- a/backend/src/events/events.gateway.ts +++ b/backend/src/events/events.gateway.ts @@ -159,7 +159,7 @@ export class EventsGateway implements OnGatewayDisconnect { async start( @MessageBody() data: { vx: number; vy: number }, @ConnectedSocket() client: Socket, - ): Promise { + ): Promise { const roomId = client.handshake.query['game_id'] as string; if (!isPlayer(this.players, roomId, client.id)) return; @@ -173,7 +173,7 @@ export class EventsGateway implements OnGatewayDisconnect { async left( @MessageBody() data: string, @ConnectedSocket() client: Socket, - ): Promise { + ): Promise { const roomId = client.handshake.query['game_id'] as string; if (!isPlayer(this.players, roomId, client.id)) return; @@ -190,7 +190,7 @@ export class EventsGateway implements OnGatewayDisconnect { async right( @MessageBody() data: string, @ConnectedSocket() client: Socket, - ): Promise { + ): Promise { const roomId = client.handshake.query['game_id'] as string; if (!isPlayer(this.players, roomId, client.id)) return; @@ -205,7 +205,7 @@ export class EventsGateway implements OnGatewayDisconnect { async bounce( @MessageBody() data: string, @ConnectedSocket() client: Socket, - ): Promise { + ): Promise { const roomId = client.handshake.query['game_id'] as string; if (!isPlayer(this.players, roomId, client.id)) return; @@ -220,7 +220,7 @@ export class EventsGateway implements OnGatewayDisconnect { async collide( @MessageBody() data: string, @ConnectedSocket() client: Socket, - ): Promise { + ): Promise { const roomId = client.handshake.query['game_id'] as string; if (!isPlayer(this.players, roomId, client.id)) return; @@ -233,6 +233,11 @@ export class EventsGateway implements OnGatewayDisconnect { client.emit('finish'); const opponent = getOpponent(this.players, roomId, client.id); + // TODO: handle invalid game. The opponent must have been disconnected. + if (!opponent) { + this.logger.error('opponent not found'); + return; + } this.emitUpdateStatus(client, 'lost'); this.emitUpdateStatusToRoomId(client, opponent, 'won'); this.emitUpdateStatusToRoomId(client, roomId, 'finish'); diff --git a/backend/src/main.ts b/backend/src/main.ts index 849ac01b..a4bcab78 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -4,6 +4,10 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { PrismaClientExceptionFilter } from 'nestjs-prisma'; import { AppModule } from './app.module'; +const constants = { + port: process.env.PORT || 3000, +}; + async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors(); // enable CORS @@ -25,6 +29,6 @@ async function bootstrap() { const { httpAdapter } = app.get(HttpAdapterHost); app.useGlobalFilters(new PrismaClientExceptionFilter(httpAdapter)); - await app.listen(process.env.PORT); + await app.listen(constants.port); } bootstrap(); diff --git a/backend/src/room/ban/ban.service.ts b/backend/src/room/ban/ban.service.ts index 751d009b..23cbd47b 100644 --- a/backend/src/room/ban/ban.service.ts +++ b/backend/src/room/ban/ban.service.ts @@ -18,7 +18,7 @@ export class BanService { async create(roomId: number, userId: number) { await this.prisma.$transaction(async (prisma) => { - const room = await prisma.room.findUnique({ + const room = await prisma.room.findUniqueOrThrow({ where: { id: roomId, }, diff --git a/backend/src/room/dto/update-UserOnRoom.dto.ts b/backend/src/room/dto/update-UserOnRoom.dto.ts deleted file mode 100644 index f81050c5..00000000 --- a/backend/src/room/dto/update-UserOnRoom.dto.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PartialType } from '@nestjs/swagger'; -import { CreateUserOnRoomDto } from './create-UserOnRoom.dto'; - -export class UpdateUserOnRoomDto extends PartialType(CreateUserOnRoomDto) {} diff --git a/backend/src/room/dto/create-UserOnRoom.dto.ts b/backend/src/room/dto/update-user-on-room.dto.ts similarity index 85% rename from backend/src/room/dto/create-UserOnRoom.dto.ts rename to backend/src/room/dto/update-user-on-room.dto.ts index 178d2f83..2bdb91b9 100644 --- a/backend/src/room/dto/create-UserOnRoom.dto.ts +++ b/backend/src/room/dto/update-user-on-room.dto.ts @@ -2,7 +2,7 @@ import { ApiProperty } from '@nestjs/swagger'; import { Role } from '@prisma/client'; import { IsNotEmpty, IsString } from 'class-validator'; -export class CreateUserOnRoomDto { +export class UpdateUserOnRoomDto { @IsString() @IsNotEmpty() @ApiProperty() diff --git a/backend/src/room/entities/room.entity.ts b/backend/src/room/entities/room.entity.ts index a873ffa4..aeb49979 100644 --- a/backend/src/room/entities/room.entity.ts +++ b/backend/src/room/entities/room.entity.ts @@ -16,5 +16,5 @@ export class RoomEntity implements Room { accessLevel: 'PUBLIC' | 'PRIVATE' | 'PROTECTED' | 'DIRECT'; @Exclude() - password: string; + password: string | null; } diff --git a/backend/src/room/guards/enter-room.guard.ts b/backend/src/room/guards/enter-room.guard.ts index f1815cca..c8b3a837 100644 --- a/backend/src/room/guards/enter-room.guard.ts +++ b/backend/src/room/guards/enter-room.guard.ts @@ -33,6 +33,9 @@ export class EnterRoomGuard implements CanActivate { if (!req.body.password) { throw new BadRequestException('password is required'); } + if (!room.password) { + throw new Error('room.password should be defined'); + } const isPasswordValid = await compare(req.body.password, room.password); if (!isPasswordValid) { throw new ForbiddenException('invalid password'); diff --git a/backend/src/room/mute/mute.service.ts b/backend/src/room/mute/mute.service.ts index 247ba3bd..51320868 100644 --- a/backend/src/room/mute/mute.service.ts +++ b/backend/src/room/mute/mute.service.ts @@ -34,7 +34,7 @@ export class MuteService { async create(roomId: number, userId: number, createMuteDto: CreateMuteDto) { await this.prisma.$transaction(async (prisma) => { - const room = await prisma.room.findUnique({ + const room = await prisma.room.findUniqueOrThrow({ where: { id: roomId, }, diff --git a/backend/src/room/room.controller.ts b/backend/src/room/room.controller.ts index c01740cd..0f648fb8 100644 --- a/backend/src/room/room.controller.ts +++ b/backend/src/room/room.controller.ts @@ -24,8 +24,8 @@ import { CurrentUser } from 'src/common/decorators/current-user.decorator'; import { Member } from './decorators/member.decorator'; import { CreateRoomDto } from './dto/create-room.dto'; import { GetRoomsQueryDto } from './dto/get-rooms-query.dto'; -import { UpdateUserOnRoomDto } from './dto/update-UserOnRoom.dto'; import { UpdateRoomDto } from './dto/update-room.dto'; +import { UpdateUserOnRoomDto } from './dto/update-user-on-room.dto'; import { UserOnRoomEntity } from './entities/UserOnRoom.entity'; import { RoomEntity } from './entities/room.entity'; import { AdminGuard } from './guards/admin.guard'; diff --git a/backend/src/room/room.service.ts b/backend/src/room/room.service.ts index db7b610f..dfe4e11f 100644 --- a/backend/src/room/room.service.ts +++ b/backend/src/room/room.service.ts @@ -4,7 +4,7 @@ import { Injectable, } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { Role, User } from '@prisma/client'; +import { Role, Room, User } from '@prisma/client'; import { hash } from 'bcrypt'; import { RoomCreatedEvent } from 'src/common/events/room-created.event'; import { RoomDeletedEvent } from 'src/common/events/room-deleted.event'; @@ -13,10 +13,9 @@ import { RoomLeftEvent } from 'src/common/events/room-left.event'; import { RoomUpdateRoleEvent } from 'src/common/events/room-update-role.event'; import { PrismaService } from 'src/prisma/prisma.service'; import { CreateRoomDto } from './dto/create-room.dto'; -import { UpdateUserOnRoomDto } from './dto/update-UserOnRoom.dto'; import { UpdateRoomDto } from './dto/update-room.dto'; +import { UpdateUserOnRoomDto } from './dto/update-user-on-room.dto'; import { UserOnRoomEntity } from './entities/UserOnRoom.entity'; -import { RoomEntity } from './entities/room.entity'; @Injectable() export class RoomService { @@ -32,7 +31,7 @@ export class RoomService { // room CRUD - async create(createRoomDto: CreateRoomDto, user: User): Promise { + async create(createRoomDto: CreateRoomDto, user: User): Promise { const { userIds, ...rest } = createRoomDto; if (rest.password) { rest.password = await this.hashPassword(rest.password); @@ -72,7 +71,7 @@ export class RoomService { return room; } - findAllRoom(userId: number, joined?: boolean): Promise { + findAllRoom(userId: number, joined?: boolean): Promise { let users; if (joined) { users = { some: { userId: userId } }; @@ -159,7 +158,7 @@ export class RoomService { async updateRoom( roomId: number, updateRoomDto: UpdateRoomDto, - ): Promise { + ): Promise { if (updateRoomDto.password) { updateRoomDto.password = await this.hashPassword(updateRoomDto.password); } @@ -199,7 +198,7 @@ export class RoomService { }); } - async removeRoom(roomId: number): Promise { + async removeRoom(roomId: number): Promise { const users = await this.findAllUserOnRoom(roomId); const deletedRoom = await this.prisma.room.delete({ where: { id: roomId }, diff --git a/backend/src/user/entities/public-user.entity.ts b/backend/src/user/entities/public-user.entity.ts index 0bac6015..ecc74837 100644 --- a/backend/src/user/entities/public-user.entity.ts +++ b/backend/src/user/entities/public-user.entity.ts @@ -17,7 +17,7 @@ export class PublicUserEntity implements User { name: string; @Exclude() - password: string; + password: string | null; @ApiProperty({ required: false, nullable: true }) avatarURL: string | null; diff --git a/backend/src/user/entities/user.entity.ts b/backend/src/user/entities/user.entity.ts index c27155ee..900f6abd 100644 --- a/backend/src/user/entities/user.entity.ts +++ b/backend/src/user/entities/user.entity.ts @@ -17,7 +17,7 @@ export class UserEntity implements User { name: string; @Exclude() - password: string; + password: string | null; @ApiProperty({ required: false, nullable: true }) avatarURL: string | null; diff --git a/backend/test/utils/app.ts b/backend/test/utils/app.ts index 62f23f75..80d6dcf2 100644 --- a/backend/test/utils/app.ts +++ b/backend/test/utils/app.ts @@ -2,8 +2,8 @@ import { INestApplication } from '@nestjs/common'; import { LoginDto } from 'src/auth/dto/login.dto'; import { CreateRoomDto } from 'src/room/dto/create-room.dto'; import { EnterRoomDto } from 'src/room/dto/enter-room.dto'; -import { UpdateUserOnRoomDto } from 'src/room/dto/update-UserOnRoom.dto'; import { UpdateRoomDto } from 'src/room/dto/update-room.dto'; +import { UpdateUserOnRoomDto } from 'src/room/dto/update-user-on-room.dto'; import { CreateUserDto } from 'src/user/dto/create-user.dto'; import { UpdateUserDto } from 'src/user/dto/update-user.dto'; import { UserEntity } from 'src/user/entities/user.entity'; diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 3ad2f748..b550206a 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -12,7 +12,7 @@ "baseUrl": "./", "incremental": true, "skipLibCheck": true, - "strictNullChecks": false, + "strictNullChecks": true, "noImplicitAny": false, "strictBindCallApply": false, "forceConsistentCasingInFileNames": false,