From e8fe46194417d9fc22877e330a634a4e20ad7375 Mon Sep 17 00:00:00 2001 From: nicolas-arnaud Date: Tue, 14 Mar 2023 11:54:34 +0100 Subject: [PATCH 1/9] added chat service --- back/volume/src/chat/chat.controller.ts | 99 +++++++++++++++++++ back/volume/src/chat/chat.gateway.ts | 2 + back/volume/src/chat/chat.module.ts | 8 +- back/volume/src/chat/chat.service.ts | 78 +++++++-------- back/volume/src/chat/dto/connection.dto.ts | 10 ++ ...teChannel.dto.ts => create-channel.dto.ts} | 8 +- .../volume/src/chat/dto/create-message.dto.ts | 12 +++ .../volume/src/chat/dto/update-channel.dto.ts | 20 ++++ back/volume/src/chat/dto/updateChannel.dto.ts | 24 ----- back/volume/src/chat/entity/channel.entity.ts | 6 +- back/volume/src/users/users.controller.ts | 9 +- back/volume/src/users/users.service.ts | 2 +- front/volume/src/components/Friends.svelte | 1 - 13 files changed, 201 insertions(+), 78 deletions(-) create mode 100644 back/volume/src/chat/chat.controller.ts create mode 100644 back/volume/src/chat/dto/connection.dto.ts rename back/volume/src/chat/dto/{createChannel.dto.ts => create-channel.dto.ts} (70%) create mode 100644 back/volume/src/chat/dto/create-message.dto.ts create mode 100644 back/volume/src/chat/dto/update-channel.dto.ts delete mode 100644 back/volume/src/chat/dto/updateChannel.dto.ts diff --git a/back/volume/src/chat/chat.controller.ts b/back/volume/src/chat/chat.controller.ts new file mode 100644 index 0000000..cd925a0 --- /dev/null +++ b/back/volume/src/chat/chat.controller.ts @@ -0,0 +1,99 @@ +import { + Body, + Controller, + Delete, + Get, + NotFoundException, + Param, + Post, +} from "@nestjs/common"; +//import { channel, Channel } from "diagnostics_channel"; +import { Channel } from './entity/channel.entity'; +import { ChannelService } from "./chat.service"; +import { CreateChannelDto } from "./dto/create-channel.dto"; +import { UsersService } from "src/users/users.service"; +import { UpdateChannelDto } from "./dto/update-channel.dto"; +import { User } from "src/users/entity/user.entity"; + +@Controller("chat") +export class ChatController { + private readonly channelService: ChannelService; + private readonly usersService: UsersService; + + @Get("channels/:id") + getChannelsForUser(@Param("id") id: number): Promise> { + return this.channelService.getChannelsForUser(id); + } + + @Post("channels") + async createChannel(@Body() channel: CreateChannelDto) { + return await this.channelService.createChannel(channel); + } + + @Delete("channels/:id") + async deleteChannel(@Param("id") id: number) { + return await this.channelService.removeChannel(id); + } + + @Post("channels/:id/owner") + async moveOwner(@Param("id") id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id); + const user: User | null = await this.usersService.findUser(userId); + if (user == null) throw new NotFoundException(`User #${userId} not found`); + channel.owner = user; + this.channelService.update(channel); + } + + @Post("channels/:id/admin") + async addAdmin(@Param("id") id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id); + const user: User | null = await this.usersService.findUser(userId); + if (user == null) throw new NotFoundException(`User #${userId} not found`); + channel.admins.push(user); + this.channelService.update(channel); + } + + @Delete("channels/:id/admin") + async removeAdmin(@Param("id") id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id); + channel.admins = channel.admins.filter((a) => { + return a.ftId !== userId; + }); + this.channelService.update(channel); + } + + @Post("channels/:id/ban") + async addBan(@Param("id") id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id); + const user: User | null = await this.usersService.findUser(userId); + if (user == null) throw new NotFoundException(`User #${userId} not found`); + channel.banned.push(user); + this.channelService.update(channel); + } + + @Delete("channels/:id/ban") + async removeBan(@Param("id") id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id); + channel.banned = channel.banned.filter((a) => { + return a.ftId !== userId; + }); + this.channelService.update(channel); + } + + @Post("channels/:id/mute") + async addMute(@Param("id") id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id); + const user: User | null = await this.usersService.findUser(userId); + if (user == null) throw new NotFoundException(`User #${userId} not found`); + channel.mute.push(user); + this.channelService.update(channel); + } + @Delete("channels/:id/mute") + async removeMute(@Param("id") id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id); + channel.mute = channel.mute.filter((a) => { + return a.ftId !== userId; + }); + this.channelService.update(channel); + } +} diff --git a/back/volume/src/chat/chat.gateway.ts b/back/volume/src/chat/chat.gateway.ts index 0d47de3..3e54192 100644 --- a/back/volume/src/chat/chat.gateway.ts +++ b/back/volume/src/chat/chat.gateway.ts @@ -1,3 +1,4 @@ +/* import { UnauthorizedException, UseGuards } from '@nestjs/common' import { type OnGatewayConnection, @@ -99,3 +100,4 @@ export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect { /// TODO: Send message to users } } +*/ diff --git a/back/volume/src/chat/chat.module.ts b/back/volume/src/chat/chat.module.ts index 930ebb4..4f69607 100644 --- a/back/volume/src/chat/chat.module.ts +++ b/back/volume/src/chat/chat.module.ts @@ -3,8 +3,9 @@ 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 { ChatService } from './chat.service' +//import { ChatGateway } from './chat.gateway' +import { ChatController } from './chat.controller' +import { ChannelService } from './chat.service' import { Channel } from './entity/channel.entity' import { Message } from './entity/message.entity' @@ -15,6 +16,7 @@ import { Message } from './entity/message.entity' TypeOrmModule.forFeature([Channel]), TypeOrmModule.forFeature([Message]) ], - providers: [ChatGateway, ChatService] + controllers: [ChatController], + providers: [/*ChatGateway, */ChannelService] }) export class ChatModule {} diff --git a/back/volume/src/chat/chat.service.ts b/back/volume/src/chat/chat.service.ts index 525949d..ab5c270 100644 --- a/back/volume/src/chat/chat.service.ts +++ b/back/volume/src/chat/chat.service.ts @@ -1,56 +1,56 @@ -import { Injectable } from '@nestjs/common' -import { InjectRepository } from '@nestjs/typeorm' -import { Repository } from 'typeorm' -import { type User } from 'src/users/entity/user.entity' -import { Channel } from './entity/channel.entity' -import { Message } from './entity/message.entity' +import { Injectable, NotFoundException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Channel } from './entity/channel.entity'; +import { User } from 'src/users/entity/user.entity'; +import { Repository } from 'typeorm'; +import { CreateChannelDto } from './dto/create-channel.dto'; +import { UsersService } from 'src/users/users.service'; @Injectable() -export class ChatService { - constructor ( +export class ChannelService { + constructor( @InjectRepository(Channel) private readonly ChannelRepository: Repository, - @InjectRepository(Message) - private readonly MessageRepository: Repository + private readonly usersService: UsersService, ) {} - async createChannel (Channel: Channel, creator: User): Promise { - const newChannel = await this.addCreatorToChannel(Channel, creator) - return await this.ChannelRepository.save(newChannel) + async createChannel(channel: CreateChannelDto): Promise { + const newChannel = this.ChannelRepository.create({ + name: channel.name, + password: channel.password, + }); + let user: User| null = await this.usersService.findUser(channel.owner); + if (user == null) throw new NotFoundException(`User #${channel.owner} not found`) + newChannel.owner = user; + return await this.ChannelRepository.save(newChannel); } - async getChannelsForUser (userId: number): Promise { - return await this.ChannelRepository.find({}) // where userId is in User[] of channel? + async getChannelsForUser(ftId: number): Promise> { + const query = await this.ChannelRepository.createQueryBuilder('room') + .innerJoin('room.users', 'users') + .where('users.ftId = :ftId', { ftId }) + .leftJoinAndSelect('room.users', 'all_users') + .orderBy('room.id', 'DESC') // TODO: order by last message + .getRawMany(); + return query; //where userId is in User[] of channel? } - async addCreatorToChannel (Channel: Channel, creator: User): Promise { - Channel.users.push(creator) - return Channel + async addUserToChannel(channel: Channel, user: User): Promise { + channel.owner = user; + return await this.ChannelRepository.save(channel); } - async createMessage (message: Message): Promise { - return await this.MessageRepository.save( - this.MessageRepository.create(message) - ) + async getChannel(id: number): Promise { + const channel = await this.ChannelRepository.findOneBy({ id }); + if (!channel) throw new NotFoundException(`Channel #${id} not found`); + return channel; } - async deleteBySocketId (socketId: string) { - return await this.ChannelRepository.delete({}) // for disconnect + async update(channel: Channel) { + this.ChannelRepository.update(channel.id, channel); } - - async getChannel (id: number): Promise { - return await this.ChannelRepository.findOneBy({ id }) - } - - 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 - }) - .getMany() + async removeChannel(id: number) { + await this.ChannelRepository.delete(id); } } + diff --git a/back/volume/src/chat/dto/connection.dto.ts b/back/volume/src/chat/dto/connection.dto.ts new file mode 100644 index 0000000..7f9e2b6 --- /dev/null +++ b/back/volume/src/chat/dto/connection.dto.ts @@ -0,0 +1,10 @@ +import { IsNumber } from 'class-validator'; + +export class ConnectionDto { + @IsNumber() + UserId: number; + @IsNumber() + ChannelId: number; + @IsNumber() + SocketId: number; +} diff --git a/back/volume/src/chat/dto/createChannel.dto.ts b/back/volume/src/chat/dto/create-channel.dto.ts similarity index 70% rename from back/volume/src/chat/dto/createChannel.dto.ts rename to back/volume/src/chat/dto/create-channel.dto.ts index cc3fbff..ab7d4ec 100644 --- a/back/volume/src/chat/dto/createChannel.dto.ts +++ b/back/volume/src/chat/dto/create-channel.dto.ts @@ -1,13 +1,13 @@ -import { IsPositive, IsAlpha, IsString, IsOptional } from 'class-validator' +import { IsPositive, IsAlpha, IsString, IsOptional } from 'class-validator'; export class CreateChannelDto { @IsString() @IsAlpha() - name: string + name: string; @IsPositive() - owner: number + owner: number; @IsOptional() - password: string + password: string; } diff --git a/back/volume/src/chat/dto/create-message.dto.ts b/back/volume/src/chat/dto/create-message.dto.ts new file mode 100644 index 0000000..6abbfb9 --- /dev/null +++ b/back/volume/src/chat/dto/create-message.dto.ts @@ -0,0 +1,12 @@ +import { IsNumber, IsString } from 'class-validator'; + +export class CreateMessageDto { + @IsString() + text: string; + + @IsNumber() + UserId: number; + + @IsNumber() + ChannelId: number; +} diff --git a/back/volume/src/chat/dto/update-channel.dto.ts b/back/volume/src/chat/dto/update-channel.dto.ts new file mode 100644 index 0000000..bdf4c87 --- /dev/null +++ b/back/volume/src/chat/dto/update-channel.dto.ts @@ -0,0 +1,20 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateChannelDto } from './create-channel.dto'; +import { IsOptional, IsString } from 'class-validator'; + +export class UpdateChannelDto extends PartialType(CreateChannelDto) { + id: number; + @IsOptional() + users: [number]; + @IsOptional() + messages: [number]; + @IsOptional() + owners: [number]; //user id + @IsOptional() + banned: [number]; //user id + @IsOptional() + muted: [number]; //user id + @IsString() + @IsOptional() + password: string; +} diff --git a/back/volume/src/chat/dto/updateChannel.dto.ts b/back/volume/src/chat/dto/updateChannel.dto.ts deleted file mode 100644 index dc2b5ff..0000000 --- a/back/volume/src/chat/dto/updateChannel.dto.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { PartialType } from '@nestjs/mapped-types' -import { CreateChannelDto } from './createChannel.dto' -import { type Message } from '../entity/message.entity' -import { type User } from 'src/users/entity/user.entity' -import { IsString } from 'class-validator' - -export class UpdateChannelDto extends PartialType(CreateChannelDto) { - id: number - - users: [User] - - messages: [Message] - - owners: [number] // ftId - - admins: [number] - - banned: [number] // ftId - - muted: [number] // ftId - - @IsString() - password: string -} diff --git a/back/volume/src/chat/entity/channel.entity.ts b/back/volume/src/chat/entity/channel.entity.ts index bc06699..624473e 100644 --- a/back/volume/src/chat/entity/channel.entity.ts +++ b/back/volume/src/chat/entity/channel.entity.ts @@ -24,6 +24,10 @@ export class Channel { @JoinTable() owner: User + @ManyToMany(() => User) + @JoinTable() + admins: User[] + @ManyToMany(() => User) @JoinTable() users: User[] @@ -35,7 +39,7 @@ export class Channel { banned: User[] @OneToMany(() => User, (user: User) => user.id) // refuse post - muted: User[] + mute: User[] @Column({ select: false }) password: string diff --git a/back/volume/src/users/users.controller.ts b/back/volume/src/users/users.controller.ts index 5899424..73d9d64 100644 --- a/back/volume/src/users/users.controller.ts +++ b/back/volume/src/users/users.controller.ts @@ -137,10 +137,9 @@ export class UsersController { return user } - @Get('invit/:username') - @UseGuards(AuthenticatedGuard) + @Get('invit/:id/:username') async invitUser ( - @Profile42() profile: Profile, + @Param('id', ParseIntPipe) id: number, @Param('username') username: string ): Promise { const target: User | null = await this.usersService.findUserByName( @@ -149,10 +148,10 @@ export class UsersController { if (target === null) { throw new BadRequestException(`User ${username} not found.`) } - if (+profile.id === target.ftId) { + if (id === target.ftId) { throw new BadRequestException("You can't invite yourself.") } - const ret: string = await this.usersService.invit(profile.id, target.ftId) + const ret: string = await this.usersService.invit(id, target.ftId) if (ret !== 'OK') throw new BadRequestException(ret) } diff --git a/back/volume/src/users/users.service.ts b/back/volume/src/users/users.service.ts index 64f971d..137d90a 100644 --- a/back/volume/src/users/users.service.ts +++ b/back/volume/src/users/users.service.ts @@ -167,7 +167,7 @@ export class UsersService { ) { user.friends.push(target) target.friends.push(user) - user.followers.slice(id, 1) + user.followers = user.followers.slice(id, 1) await this.usersRepository.save(user) } else target.followers.push(user) await this.usersRepository.save(target) diff --git a/front/volume/src/components/Friends.svelte b/front/volume/src/components/Friends.svelte index f88b256..566205c 100644 --- a/front/volume/src/components/Friends.svelte +++ b/front/volume/src/components/Friends.svelte @@ -73,7 +73,6 @@ {friend.username} is {friend.status} {/each} - /> {:else}

No friends to display

From b84ea3481d90a94d9e25ea0e9d8702634cbc796e Mon Sep 17 00:00:00 2001 From: nicolas-arnaud Date: Wed, 15 Mar 2023 00:17:39 +0100 Subject: [PATCH 2/9] routes refactoring and chat fetchs start to work delete channel and chatServices to check is a user is... fixed friends invitations LINT lint --- back/volume/src/chat/chat.controller.ts | 142 +++++++++--------- back/volume/src/chat/chat.module.ts | 9 +- back/volume/src/chat/chat.service.ts | 138 ++++++++++++----- back/volume/src/chat/dto/connection.dto.ts | 13 +- .../volume/src/chat/dto/create-channel.dto.ts | 27 +++- .../volume/src/chat/dto/create-message.dto.ts | 8 +- .../volume/src/chat/dto/update-channel.dto.ts | 30 ++-- back/volume/src/chat/entity/channel.entity.ts | 55 ++++--- .../src/chat/entity/connection.entity.ts | 16 ++ back/volume/src/chat/entity/dm.entity.ts | 15 ++ back/volume/src/chat/entity/message.entity.ts | 15 +- back/volume/src/pong/pong.controller.ts | 33 ++++ back/volume/src/pong/pong.module.ts | 2 + back/volume/src/users/entity/user.entity.ts | 6 - back/volume/src/users/users.controller.ts | 41 ++--- back/volume/src/users/users.service.ts | 9 +- front/volume/src/App.svelte | 2 +- front/volume/src/Auth.ts | 4 +- front/volume/src/FakeLogin.svelte | 2 +- front/volume/src/components/Channels.svelte | 88 +++++------ front/volume/src/components/Chat.svelte | 22 +-- front/volume/src/components/Friends.svelte | 6 +- .../volume/src/components/Leaderboard.svelte | 2 +- .../volume/src/components/MatchHistory.svelte | 19 ++- front/volume/src/components/NavBar.svelte | 2 +- front/volume/src/components/Profile.svelte | 16 +- 26 files changed, 423 insertions(+), 299 deletions(-) create mode 100644 back/volume/src/chat/entity/connection.entity.ts create mode 100644 back/volume/src/chat/entity/dm.entity.ts create mode 100644 back/volume/src/pong/pong.controller.ts diff --git a/back/volume/src/chat/chat.controller.ts b/back/volume/src/chat/chat.controller.ts index cd925a0..e13aca0 100644 --- a/back/volume/src/chat/chat.controller.ts +++ b/back/volume/src/chat/chat.controller.ts @@ -1,99 +1,97 @@ import { + BadRequestException, Body, Controller, Delete, Get, NotFoundException, Param, + ParseIntPipe, Post, -} from "@nestjs/common"; -//import { channel, Channel } from "diagnostics_channel"; -import { Channel } from './entity/channel.entity'; -import { ChannelService } from "./chat.service"; -import { CreateChannelDto } from "./dto/create-channel.dto"; -import { UsersService } from "src/users/users.service"; -import { UpdateChannelDto } from "./dto/update-channel.dto"; -import { User } from "src/users/entity/user.entity"; + UseGuards +} from '@nestjs/common' +import { AuthenticatedGuard } from 'src/auth/42-auth.guard' +import { UsersService } from 'src/users/users.service' +import { ChannelService } from './chat.service' -@Controller("chat") -export class ChatController { - private readonly channelService: ChannelService; - private readonly usersService: UsersService; +import { CreateChannelDto } from './dto/create-channel.dto' +import { UpdateChannelDto } from './dto/update-channel.dto' - @Get("channels/:id") - getChannelsForUser(@Param("id") id: number): Promise> { - return this.channelService.getChannelsForUser(id); - } +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' - @Post("channels") - async createChannel(@Body() channel: CreateChannelDto) { - return await this.channelService.createChannel(channel); - } +@Controller('channels') +export class ChatController { + constructor ( + private readonly channelService: ChannelService, + private readonly usersService: UsersService + ) {} - @Delete("channels/:id") - async deleteChannel(@Param("id") id: number) { - return await this.channelService.removeChannel(id); + @Post(':id/admin') + async addAdmin (@Param('id') id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id) + const user: User | null = await this.usersService.findUser(userId) + if (user == null) throw new NotFoundException(`User #${userId} not found`) + channel.admins.push(user) + this.channelService.update(channel) } - @Post("channels/:id/owner") - async moveOwner(@Param("id") id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id); - const user: User | null = await this.usersService.findUser(userId); - if (user == null) throw new NotFoundException(`User #${userId} not found`); - channel.owner = user; - this.channelService.update(channel); + @Delete(':id/admin') + async removeAdmin (@Param('id') id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id) + channel.admins = channel.admins.filter((usr: User) => { + return usr.ftId !== userId + }) + this.channelService.update(channel) } - @Post("channels/:id/admin") - async addAdmin(@Param("id") id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id); - const user: User | null = await this.usersService.findUser(userId); - if (user == null) throw new NotFoundException(`User #${userId} not found`); - channel.admins.push(user); - this.channelService.update(channel); + @Post(':id/ban') + async addBan (@Param('id') id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id) + const user: User | null = await this.usersService.findUser(userId) + if (user == null) throw new NotFoundException(`User #${userId} not found`) + channel.banned.push(user) + this.channelService.update(channel) } - @Delete("channels/:id/admin") - async removeAdmin(@Param("id") id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id); - channel.admins = channel.admins.filter((a) => { - return a.ftId !== userId; - }); - this.channelService.update(channel); + @Post(':id/mute') + async addMute (@Param('id') id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id) + const user: User | null = await this.usersService.findUser(userId) + if (user == null) throw new NotFoundException(`User #${userId} not found`) + channel.muted.push(user) + this.channelService.update(channel) } - @Post("channels/:id/ban") - async addBan(@Param("id") id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id); - const user: User | null = await this.usersService.findUser(userId); - if (user == null) throw new NotFoundException(`User #${userId} not found`); - channel.banned.push(user); - this.channelService.update(channel); + @Delete(':id/mute') + async removeMute (@Param('id') id: number, @Body() userId: number) { + const channel = await this.channelService.getChannel(id) + channel.muted = channel.muted.filter((usr: User) => { + return usr.ftId !== userId + }) + this.channelService.update(channel) } - @Delete("channels/:id/ban") - async removeBan(@Param("id") id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id); - channel.banned = channel.banned.filter((a) => { - return a.ftId !== userId; - }); - this.channelService.update(channel); + @Delete(':id') + @UseGuards(AuthenticatedGuard) + async deleteChannel (@Profile42() profile: Profile, @Param('id') id: number) { + if (await this.channelService.isOwner(id, +profile.id)) { + await this.channelService.removeChannel(id) + return + } + throw new BadRequestException('You are not the owner of this channel') } - @Post("channels/:id/mute") - async addMute(@Param("id") id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id); - const user: User | null = await this.usersService.findUser(userId); - if (user == null) throw new NotFoundException(`User #${userId} not found`); - channel.mute.push(user); - this.channelService.update(channel); + @Get() + @UseGuards(AuthenticatedGuard) + async getChannelsForUser (@Profile42() profile: Profile): Promise { + return await this.channelService.getChannelsForUser(profile.id) } - @Delete("channels/:id/mute") - async removeMute(@Param("id") id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id); - channel.mute = channel.mute.filter((a) => { - return a.ftId !== userId; - }); - this.channelService.update(channel); + + @Post() + async createChannel (@Body() channel: CreateChannelDto) { + return await this.channelService.createChannel(channel) } } diff --git a/back/volume/src/chat/chat.module.ts b/back/volume/src/chat/chat.module.ts index 4f69607..8fcaa1f 100644 --- a/back/volume/src/chat/chat.module.ts +++ b/back/volume/src/chat/chat.module.ts @@ -3,11 +3,12 @@ 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 { ChatGateway } from './chat.gateway' import { ChatController } from './chat.controller' import { ChannelService } from './chat.service' -import { Channel } from './entity/channel.entity' -import { Message } from './entity/message.entity' + +import Channel from './entity/channel.entity' +import Message from './entity/message.entity' @Module({ imports: [ @@ -17,6 +18,6 @@ import { Message } from './entity/message.entity' TypeOrmModule.forFeature([Message]) ], controllers: [ChatController], - providers: [/*ChatGateway, */ChannelService] + providers: [ChannelService] }) export class ChatModule {} diff --git a/back/volume/src/chat/chat.service.ts b/back/volume/src/chat/chat.service.ts index ab5c270..0b50500 100644 --- a/back/volume/src/chat/chat.service.ts +++ b/back/volume/src/chat/chat.service.ts @@ -1,56 +1,118 @@ -import { Injectable, NotFoundException } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Channel } from './entity/channel.entity'; -import { User } from 'src/users/entity/user.entity'; -import { Repository } from 'typeorm'; -import { CreateChannelDto } from './dto/create-channel.dto'; -import { UsersService } from 'src/users/users.service'; +import { 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 User from 'src/users/entity/user.entity' +import Channel from './entity/channel.entity' +import { classToPlain, plainToClass } from 'class-transformer' @Injectable() export class ChannelService { - constructor( + constructor ( @InjectRepository(Channel) private readonly ChannelRepository: Repository, - private readonly usersService: UsersService, + private readonly usersService: UsersService ) {} - async createChannel(channel: CreateChannelDto): Promise { - const newChannel = this.ChannelRepository.create({ - name: channel.name, - password: channel.password, - }); - let user: User| null = await this.usersService.findUser(channel.owner); - if (user == null) throw new NotFoundException(`User #${channel.owner} not found`) - newChannel.owner = user; - return await this.ChannelRepository.save(newChannel); + 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`) + } + 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 getChannelsForUser (ftId: number): Promise { + let rooms: Channel[] = [] + rooms = [ + ...(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 } - async getChannelsForUser(ftId: number): Promise> { - const query = await this.ChannelRepository.createQueryBuilder('room') - .innerJoin('room.users', 'users') - .where('users.ftId = :ftId', { ftId }) - .leftJoinAndSelect('room.users', 'all_users') - .orderBy('room.id', 'DESC') // TODO: order by last message - .getRawMany(); - return query; //where userId is in User[] of 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 }) + if (channel == null) { throw new NotFoundException(`Channel #${id} not found`) } + return channel } - async getChannel(id: number): Promise { - const channel = await this.ChannelRepository.findOneBy({ id }); - if (!channel) throw new NotFoundException(`Channel #${id} not found`); - return channel; + async update (channel: Channel) { + this.ChannelRepository.update(channel.id, channel) } - async update(channel: Channel) { - this.ChannelRepository.update(channel.id, channel); + async removeChannel (channelId: number) { + await this.ChannelRepository.delete(channelId) } - async removeChannel(id: number) { - await this.ChannelRepository.delete(id); + + async isOwner (id: number, userId: number): Promise { + const channel = await this.ChannelRepository.findOne({ + where: { id }, + relations: { owner: true } + }) + if (channel == null) { throw new NotFoundException(`Channel #${id} not found`) } + console.log(channel.owner.ftId, userId) + return channel.owner.ftId == userId } -} + async isAdmin (id: number, userId: number): Promise { + const channel = await this.ChannelRepository.findOne({ + where: { id }, + relations: { admins: true } + }) + if (channel == null) { throw new NotFoundException(`Channel #${id} not found`) } + return channel.admins.findIndex((user) => user.ftId == userId) != -1 + } + + async isUser (id: number, userId: number): Promise { + const channel = await this.ChannelRepository.findOne({ + where: { id }, + relations: { users: true } + }) + if (channel == null) { throw new NotFoundException(`Channel #${id} not found`) } + return channel.users.findIndex((user) => user.ftId == userId) != -1 + } + + async isBanned (id: number, userId: number): Promise { + const channel = await this.ChannelRepository.findOne({ + where: { id }, + relations: { banned: true } + }) + if (channel == null) { throw new NotFoundException(`Channel #${id} not found`) } + return channel.banned.findIndex((user) => user.ftId == userId) != -1 + } + + async isMuted (id: number, userId: number): Promise { + const channel = await this.ChannelRepository.findOne({ + where: { id }, + relations: { muted: true } + }) + if (channel == null) { throw new NotFoundException(`Channel #${id} not found`) } + return channel.muted.findIndex((user) => user.ftId == userId) != -1 + } +} diff --git a/back/volume/src/chat/dto/connection.dto.ts b/back/volume/src/chat/dto/connection.dto.ts index 7f9e2b6..c70f38c 100644 --- a/back/volume/src/chat/dto/connection.dto.ts +++ b/back/volume/src/chat/dto/connection.dto.ts @@ -1,10 +1,13 @@ -import { IsNumber } from 'class-validator'; +import { IsNumber, IsOptional, IsString } from 'class-validator' export class ConnectionDto { @IsNumber() - UserId: number; - @IsNumber() - ChannelId: number; + UserId: number + @IsNumber() - SocketId: number; + ChannelId: number + + @IsString() + @IsOptional() + 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 ab7d4ec..af1f03a 100644 --- a/back/volume/src/chat/dto/create-channel.dto.ts +++ b/back/volume/src/chat/dto/create-channel.dto.ts @@ -1,13 +1,28 @@ -import { IsPositive, IsAlpha, IsString, IsOptional } from 'class-validator'; +import { Transform } from 'class-transformer' +import { + IsPositive, + IsAlpha, + IsString, + IsOptional, + IsNumber, + IsBoolean +} from 'class-validator' export class CreateChannelDto { + @IsOptional() + @IsPositive() + id: number + @IsString() - @IsAlpha() - name: string; + name: string - @IsPositive() - owner: number; + @IsNumber() + owner: number @IsOptional() - password: string; + password: string + + @IsBoolean() + @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 6abbfb9..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 bdf4c87..c9cb3a3 100644 --- a/back/volume/src/chat/dto/update-channel.dto.ts +++ b/back/volume/src/chat/dto/update-channel.dto.ts @@ -1,20 +1,30 @@ -import { PartialType } from '@nestjs/mapped-types'; -import { CreateChannelDto } from './create-channel.dto'; -import { 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() - users: [number]; + @IsNumber() + users: [number] + @IsOptional() - messages: [number]; + @IsNumber() + messages: [number] + @IsOptional() - owners: [number]; //user id + @IsNumber() + owners: [number] // user id + @IsOptional() - banned: [number]; //user id + @IsNumber() + banned: [number] // user id + @IsOptional() - muted: [number]; //user id + @IsNumber() + muted: [number] // user id + @IsString() @IsOptional() - password: string; + password: string } diff --git a/back/volume/src/chat/entity/channel.entity.ts b/back/volume/src/chat/entity/channel.entity.ts index 624473e..f2b51c9 100644 --- a/back/volume/src/chat/entity/channel.entity.ts +++ b/back/volume/src/chat/entity/channel.entity.ts @@ -2,31 +2,39 @@ import { BeforeInsert, Column, Entity, + JoinColumn, JoinTable, ManyToMany, + ManyToOne, OneToMany, + OneToOne, PrimaryGeneratedColumn } from 'typeorm' +import User from 'src/users/entity/user.entity' +import Message from './message.entity' import * as bcrypt from 'bcrypt' -import { User } from 'src/users/entity/user.entity' -import { Message } from './message.entity' - @Entity() -export class Channel { +export default class Channel { @PrimaryGeneratedColumn() id: number @Column() name: string - @ManyToMany(() => User) - @JoinTable() - owner: User + @Column({ default: false }) + isPrivate: boolean - @ManyToMany(() => User) - @JoinTable() - admins: User[] + @Column({ select: false, default: '' }) + password: string + + @BeforeInsert() + async hashPassword () { + this.password = await bcrypt.hash( + this.password, + Number(process.env.HASH_SALT) + ) + } @ManyToMany(() => User) @JoinTable() @@ -35,22 +43,19 @@ export class Channel { @OneToMany(() => Message, (message: Message) => message.channel) messages: Message[] - @OneToMany(() => User, (user: User) => user.id) // refuse connection - banned: User[] + @ManyToOne(() => User) + @JoinColumn() + owner: User - @OneToMany(() => User, (user: User) => user.id) // refuse post - mute: User[] + @ManyToMany(() => User) + @JoinTable() + admins: User[] - @Column({ select: false }) - password: string + @ManyToMany(() => User) // refuse connection + @JoinTable() + banned: User[] - @BeforeInsert() - async hashPassword () { - this.password = await bcrypt.hash( - this.password, - Number(process.env.HASH_SALT) - ) - } + @ManyToMany(() => User) // refuse post + @JoinTable() + muted: User[] } - -export default Channel diff --git a/back/volume/src/chat/entity/connection.entity.ts b/back/volume/src/chat/entity/connection.entity.ts new file mode 100644 index 0000000..fc949f9 --- /dev/null +++ b/back/volume/src/chat/entity/connection.entity.ts @@ -0,0 +1,16 @@ +import { Column, Entity, OneToOne } from 'typeorm' + +import Channel from './channel.entity' +import User from 'src/users/entity/user.entity' + +@Entity() +export class connectedUser { + @OneToOne(() => User) + user: User + + @OneToOne(() => Channel, (channel) => channel.id) + channel: Channel + + @Column() + socket: string +} diff --git a/back/volume/src/chat/entity/dm.entity.ts b/back/volume/src/chat/entity/dm.entity.ts new file mode 100644 index 0000000..d1a344c --- /dev/null +++ b/back/volume/src/chat/entity/dm.entity.ts @@ -0,0 +1,15 @@ +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 + + @Column() + users: User[] + + @OneToMany(() => Message, (message) => message.channel) + messages: Message[] +} diff --git a/back/volume/src/chat/entity/message.entity.ts b/back/volume/src/chat/entity/message.entity.ts index 488dacd..e44b4a3 100644 --- a/back/volume/src/chat/entity/message.entity.ts +++ b/back/volume/src/chat/entity/message.entity.ts @@ -7,28 +7,25 @@ import { ManyToOne, PrimaryGeneratedColumn } from 'typeorm' - -import { User } from 'src/users/entity/user.entity' -import { Channel } from './channel.entity' +import User from 'src/users/entity/user.entity' +import Channel from './channel.entity' @Entity() -export class Message { +export default class Message { @PrimaryGeneratedColumn() id: number @Column() text: string - @ManyToOne(() => User, (author: User) => author.messages) + @ManyToOne(() => User) @JoinColumn() author: User - @ManyToOne(() => Channel, (channel: Channel) => channel.messages) + @ManyToOne(() => Channel, (channel) => channel.messages, { cascade: true }) @JoinTable() channel: Channel @CreateDateColumn() - createdAt: Date + created_at: Date } - -export default Message diff --git a/back/volume/src/pong/pong.controller.ts b/back/volume/src/pong/pong.controller.ts new file mode 100644 index 0000000..809880d --- /dev/null +++ b/back/volume/src/pong/pong.controller.ts @@ -0,0 +1,33 @@ +import { + Controller, + 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' + +@Controller('results') +export class PongController { + constructor (private readonly pongService: PongService) {} + + @Get('global') + @UseGuards(AuthenticatedGuard) + async getGlobalHistory ( + @Paginate() query: PaginateQuery + ): Promise> { + return await this.pongService.getHistory(query, 0) + } + + @Get(':id') + @UseGuards(AuthenticatedGuard) + async getHistoryById ( + @Param('id', ParseIntPipe) id: number, + @Paginate() query: PaginateQuery + ): Promise> { + return await this.pongService.getHistory(query, id) + } +} diff --git a/back/volume/src/pong/pong.module.ts b/back/volume/src/pong/pong.module.ts index 821acbb..df862a7 100644 --- a/back/volume/src/pong/pong.module.ts +++ b/back/volume/src/pong/pong.module.ts @@ -4,10 +4,12 @@ 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] }) export class PongModule {} diff --git a/back/volume/src/users/entity/user.entity.ts b/back/volume/src/users/entity/user.entity.ts index 6a8e5ec..a52ce7f 100644 --- a/back/volume/src/users/entity/user.entity.ts +++ b/back/volume/src/users/entity/user.entity.ts @@ -65,12 +65,6 @@ export class User { @JoinTable() results: Result[] - @OneToMany(() => Message, (message: Message) => message.author) - messages: Message[] - - @ManyToMany(() => Channel, (channel: Channel) => channel.users) - rooms: Channel[] - @ManyToMany(() => User) @JoinTable() blocked: User[] diff --git a/back/volume/src/users/users.controller.ts b/back/volume/src/users/users.controller.ts index 73d9d64..6673313 100644 --- a/back/volume/src/users/users.controller.ts +++ b/back/volume/src/users/users.controller.ts @@ -13,7 +13,6 @@ import { BadRequestException, Redirect } from '@nestjs/common' -import { PaginateQuery, type Paginated, Paginate } from 'nestjs-paginate' import { FileInterceptor } from '@nestjs/platform-express' import { diskStorage } from 'multer' @@ -31,14 +30,10 @@ import { ApiBody, ApiConsumes } from '@nestjs/swagger' import { type Request, Response } from 'express' import { createReadStream } from 'fs' import { join } from 'path' -import type Result from 'src/pong/entity/result.entity' -@Controller() +@Controller('users') export class UsersController { - constructor ( - private readonly usersService: UsersService, - private readonly pongService: PongService - ) {} + constructor (private readonly usersService: UsersService) {} @Get('all') async getAllUsers (): Promise { @@ -68,29 +63,12 @@ export class UsersController { return await this.usersService.getLeaderboard() } - @Get('rank/:id') + @Get(':id/rank') @UseGuards(AuthenticatedGuard) async getRank (@Param('id', ParseIntPipe) id: number): Promise { return await this.usersService.getRank(id) } - @Get('globalHistory') - @UseGuards(AuthenticatedGuard) - async getGlobalHistory ( - @Paginate() query: PaginateQuery - ): Promise> { - return await this.pongService.getHistory(query, 0) - } - - @Get('history/:id') - @UseGuards(AuthenticatedGuard) - async getHistoryById ( - @Param('id', ParseIntPipe) id: number, - @Paginate() query: PaginateQuery - ): Promise> { - return await this.pongService.getHistory(query, id) - } - @Post('avatar') @UseGuards(AuthenticatedGuard) @Redirect('http://localhost') @@ -130,16 +108,17 @@ export class UsersController { return await this.getAvatarById(profile.id, response) } - @Get('user/:name') + @Get(':name/byname') async getUserByName (@Param('name') username: string): Promise { const user = await this.usersService.findUserByName(username) user.socketKey = '' return user } - @Get('invit/:id/:username') + @Get('invit/:username') + @UseGuards(AuthenticatedGuard) async invitUser ( - @Param('id', ParseIntPipe) id: number, + @Profile42() profile: Profile, @Param('username') username: string ): Promise { const target: User | null = await this.usersService.findUserByName( @@ -148,14 +127,14 @@ export class UsersController { if (target === null) { throw new BadRequestException(`User ${username} not found.`) } - if (id === target.ftId) { + if (profile.id === target.ftId) { throw new BadRequestException("You can't invite yourself.") } - const ret: string = await this.usersService.invit(id, target.ftId) + const ret: string = await this.usersService.invit(profile.id, target.ftId) if (ret !== 'OK') throw new BadRequestException(ret) } - @Get('avatar/:id') + @Get(':id/avatar') async getAvatarById ( @Param('id', ParseIntPipe) ftId: number, @Res({ passthrough: true }) response: Response diff --git a/back/volume/src/users/users.service.ts b/back/volume/src/users/users.service.ts index 137d90a..ae2d26e 100644 --- a/back/volume/src/users/users.service.ts +++ b/back/volume/src/users/users.service.ts @@ -1,12 +1,13 @@ import { BadRequestException, Catch, Injectable } from '@nestjs/common' import { InjectRepository } from '@nestjs/typeorm' import { EntityNotFoundError, QueryFailedError, Repository } from 'typeorm' -import { User } from './entity/user.entity' -import { type UserDto } from './dto/user.dto' -import { type Channel } from 'src/chat/entity/channel.entity' 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' + @Injectable() @Catch(QueryFailedError, EntityNotFoundError) export class UsersService { @@ -167,7 +168,7 @@ export class UsersService { ) { user.friends.push(target) target.friends.push(user) - user.followers = user.followers.slice(id, 1) + user.followers.splice(id, 1) await this.usersRepository.save(user) } else target.followers.push(user) await this.usersRepository.save(target) diff --git a/front/volume/src/App.svelte b/front/volume/src/App.svelte index 47d5df2..083e860 100644 --- a/front/volume/src/App.svelte +++ b/front/volume/src/App.svelte @@ -148,7 +148,7 @@ {:else}
- +
{/if} {/if} diff --git a/front/volume/src/Auth.ts b/front/volume/src/Auth.ts index 0cd6919..137f52d 100644 --- a/front/volume/src/Auth.ts +++ b/front/volume/src/Auth.ts @@ -11,8 +11,8 @@ export const API_URL = `http://${import.meta.env.VITE_HOST}:${ import.meta.env.VITE_BACK_PORT }`; -export async function getUser() { - const res = await fetch(API_URL, { +export async function getUser(bypass: boolean = false) { + const res = await fetch(API_URL + "/users", { method: "get", mode: "cors", cache: "no-cache", diff --git a/front/volume/src/FakeLogin.svelte b/front/volume/src/FakeLogin.svelte index a05f2b7..2f76ef5 100644 --- a/front/volume/src/FakeLogin.svelte +++ b/front/volume/src/FakeLogin.svelte @@ -5,7 +5,7 @@ export let ftId; async function doPost() { - await fetch(API_URL + "/" + ftId, { + await fetch(API_URL + "/users/" + ftId, { method: "POST", credentials: "include", mode: "cors", diff --git a/front/volume/src/components/Channels.svelte b/front/volume/src/components/Channels.svelte index 058ff5f..51d7baa 100644 --- a/front/volume/src/components/Channels.svelte +++ b/front/volume/src/components/Channels.svelte @@ -1,34 +1,31 @@
@@ -104,6 +131,7 @@ on:click={() => removeChannel(_channels.id)} on:keydown={() => removeChannel(_channels.id)}>delete + {/each} {:else}

No channels available

From 1948f04ca0f1d8e858edfe8d05c69dc4d5c09d5e Mon Sep 17 00:00:00 2001 From: WalidMoovin Date: Wed, 15 Mar 2023 04:53:16 +0100 Subject: [PATCH 5/9] moved channel settings from chat to channels, fetch done, need route in controller --- front/volume/src/components/Channels.svelte | 23 +++++++++++ front/volume/src/components/Chat.svelte | 42 --------------------- 2 files changed, 23 insertions(+), 42 deletions(-) diff --git a/front/volume/src/components/Channels.svelte b/front/volume/src/components/Channels.svelte index 564b9c3..95ff953 100644 --- a/front/volume/src/components/Channels.svelte +++ b/front/volume/src/components/Channels.svelte @@ -116,6 +116,28 @@ }; //--------------------------------------------------------------------------------/ + + const changePassword = async (id: number) => { + let string = prompt("Enter the new password for this channel (leave empty to remove password) :"); + const response = await fetch(API_URL + "/channels/" + id + "/password", { + credentials: "include", + method: "POST", + mode: "cors", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + password: string, + }), + }); + if (response.ok) { + channels.push(await response.json()); + } else { + alert("Error changing password"); + } + }; + + //--------------------------------------------------------------------------------/
@@ -132,6 +154,7 @@ on:keydown={() => removeChannel(_channels.id)}>delete + {/each} {:else}

No channels available

diff --git a/front/volume/src/components/Chat.svelte b/front/volume/src/components/Chat.svelte index 1993b7b..680f609 100644 --- a/front/volume/src/components/Chat.svelte +++ b/front/volume/src/components/Chat.svelte @@ -34,7 +34,6 @@ messagesDiv.scrollTop = messagesDiv.scrollHeight; } } - // TODO: save to database }; //--------------------------------------------------------------------------------/ @@ -46,7 +45,6 @@ showProfileMenu = true; selectedUser = username; showChatMembers = false; - showChannelSettings = false; } function closeProfileMenu() { showProfileMenu = false; @@ -59,7 +57,6 @@ let showChatMembers = false; function toggleChatMembers() { showChatMembers = !showChatMembers; - showChannelSettings = false; } let chatMembers: Array = [ { username: "user1" }, @@ -83,14 +80,6 @@ //--------------------------------------------------------------------------------/ - let showChannelSettings = false; - function toggleChannelSettings() { - showChannelSettings = !showChannelSettings; - showChatMembers = false; - } - - //--------------------------------------------------------------------------------/ - const blockUser = async (username: string) => {}; //--------------------------------------------------------------------------------/ @@ -291,23 +280,6 @@
{/if} - - {#if showChannelSettings} -
-
- - - -
-
- {/if} @@ -356,18 +328,4 @@ .chatMembers button { width: 6rem; } - - .channelSettings { - position: absolute; - background-color: #fff; - border: 1px solid #ccc; - border-radius: 5px; - padding: 1rem; - max-height: 100px; - overflow-y: scroll; - } - - .channelSettings button { - width: 5rem; - } From 89ced4319b5ef2aaffce9e0d223ea9f94f7cd58d Mon Sep 17 00:00:00 2001 From: nicolas-arnaud Date: Wed, 15 Mar 2023 08:50:52 +0100 Subject: [PATCH 6/9] ready to try channels management --- back/volume/src/chat/chat.controller.ts | 146 ++++++++++++------ back/volume/src/chat/chat.service.ts | 24 ++- back/volume/src/chat/dto/updateUser.dto.ts | 16 ++ back/volume/src/chat/entity/channel.entity.ts | 2 +- front/volume/src/components/Channels.svelte | 2 +- 5 files changed, 133 insertions(+), 57 deletions(-) create mode 100644 back/volume/src/chat/dto/updateUser.dto.ts diff --git a/back/volume/src/chat/chat.controller.ts b/back/volume/src/chat/chat.controller.ts index accdd58..f43d86e 100644 --- a/back/volume/src/chat/chat.controller.ts +++ b/back/volume/src/chat/chat.controller.ts @@ -15,7 +15,7 @@ import { UsersService } from 'src/users/users.service' import { ChannelService } from './chat.service' import { CreateChannelDto } from './dto/create-channel.dto' -import { UpdateChannelDto } from './dto/update-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' @@ -30,66 +30,113 @@ export class ChatController { ) {} @Post(':id/invite') - async addUser (@Param('id') id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id) - const user: User | null = await this.usersService.findUser(userId) - if (user == null) throw new NotFoundException(`User #${userId} not found`) + @UseGuards(AuthenticatedGuard) + 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) + if (user == null) 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') + if (await this.channelService.isUser(channel.id, target.id)) + 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') channel.users.push(user) - this.channelService.update(channel) + this.channelService.save(channel) } @Delete(':id/kick') - async removeUser (@Param('id') id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id) - channel.users = channel.admins.filter((usr: User) => { - return usr.ftId !== userId + @UseGuards(AuthenticatedGuard) + async removeUser ( + @Param('id') id: number, @Body() target: IdDto, + @Profile42() profile: Profile) { + 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') + if (!await this.channelService.isUser(channel.id, target.id)) + 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') + channel.users = channel.users.filter((usr: User) => { + return usr.ftId !== target.id }) - this.channelService.update(channel) + this.channelService.save(channel) } @Post(':id/admin') - async addAdmin (@Param('id') id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id) - const user: User | null = await this.usersService.findUser(userId) - if (user == null) throw new NotFoundException(`User #${userId} not found`) + @UseGuards(AuthenticatedGuard) + 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) + if (user == null) 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') + if (!await this.channelService.isUser(channel.id, target.id)) + 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') channel.admins.push(user) - this.channelService.update(channel) + this.channelService.save(channel) } @Delete(':id/admin') - async removeAdmin (@Param('id') id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id) + @UseGuards(AuthenticatedGuard) + async removeAdmin ( + @Param('id') id: number, + @Body() target: IdDto, + @Profile42() profile: Profile) { + 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') + if (!await this.channelService.isAdmin(channel.id, target.id)) + throw new BadRequestException('User is not an admin of this channel') channel.admins = channel.admins.filter((usr: User) => { - return usr.ftId !== userId + return usr.ftId !== target.id }) - this.channelService.update(channel) + this.channelService.save(channel) } @Post(':id/ban') - async addBan (@Param('id') id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id) - const user: User | null = await this.usersService.findUser(userId) - if (user == null) throw new NotFoundException(`User #${userId} not found`) + @UseGuards(AuthenticatedGuard) + 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) + if (user == null) 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') + if (await this.channelService.isOwner(channel.id, target.id)) + 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') channel.banned.push(user) - this.channelService.update(channel) + this.channelService.save(channel) } @Post(':id/mute') - async addMute (@Param('id') id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id) - const user: User | null = await this.usersService.findUser(userId) - if (user == null) throw new NotFoundException(`User #${userId} not found`) - channel.muted.push(user) - this.channelService.update(channel) - } - - @Delete(':id/mute') - async removeMute (@Param('id') id: number, @Body() userId: number) { - const channel = await this.channelService.getChannel(id) - channel.muted = channel.muted.filter((usr: User) => { - return usr.ftId !== userId - }) - this.channelService.update(channel) + @UseGuards(AuthenticatedGuard) + 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]) + if (user == null) 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') + if (await this.channelService.isOwner(channel.id, mute.data[0])) + 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') + channel.muted.push(mute.data) + this.channelService.save(channel) } @Delete(':id') @@ -98,11 +145,10 @@ export class ChatController { @Profile42() profile: Profile, @Param('id') id: number ) { - if (await this.channelService.isOwner(id, +profile.id)) { - await this.channelService.removeChannel(id) - return - } - throw new BadRequestException('You are not the owner of this channel') + if (!await this.channelService.isOwner(id, +profile.id)) + throw new BadRequestException('You are not the owner of this channel') + await this.channelService.removeChannel(id) + return } @Post(':id/password') @@ -110,13 +156,11 @@ export class ChatController { async updatePassword ( @Profile42() profile: Profile, @Param('id') id: number, - @Body() password: string + @Body() data: PasswordDto ) { - if (await this.channelService.isOwner(id, +profile.id)) { - await this.channelService.updatePassword(id, password) - return - } - throw new BadRequestException('You are not the owner of this channel') + if (await this.channelService.isOwner(id, +profile.id)) + throw new BadRequestException('You are not the owner of this channel') + await this.channelService.updatePassword(id, data.password) } diff --git a/back/volume/src/chat/chat.service.ts b/back/volume/src/chat/chat.service.ts index 29eea35..1ee459d 100644 --- a/back/volume/src/chat/chat.service.ts +++ b/back/volume/src/chat/chat.service.ts @@ -7,7 +7,6 @@ import { UsersService } from 'src/users/users.service' import type User from 'src/users/entity/user.entity' import Channel from './entity/channel.entity' -import { classToPlain, plainToClass } from 'class-transformer' @Injectable() export class ChannelService { @@ -68,8 +67,21 @@ export class ChannelService { return channel } + async getFullChannel (id: number): Promise { + const channel = await this.ChannelRepository.findOne({ + where: { id }, + relations: ['users', 'admins', 'banned', 'muted', 'owner'] + }) + if (channel == null) { throw new NotFoundException(`Channel #${id} not found`) } + return channel + } + async update (channel: Channel) { - this.ChannelRepository.update(channel.id, channel) + await this.ChannelRepository.update(channel.id, channel) + } + + async save (channel: Channel) { + await this.ChannelRepository.save(channel) } async removeChannel (channelId: number) { @@ -112,12 +124,16 @@ export class ChannelService { return channel.banned.findIndex((user) => user.ftId === userId) != -1 } - async isMuted (id: number, userId: number): Promise { + async getMuteDuration (id: number, userId: number): Promise { const channel = await this.ChannelRepository.findOne({ where: { id }, relations: { muted: true } }) if (channel == null) { throw new NotFoundException(`Channel #${id} not found`) } - return channel.muted.findIndex((user) => user.ftId === userId) != -1 + + const mutation: Array | undefined = channel.muted.find((mutation) => mutation[0] === userId) + if (mutation == null) { return 0 } + return mutation[1] + } } diff --git a/back/volume/src/chat/dto/updateUser.dto.ts b/back/volume/src/chat/dto/updateUser.dto.ts new file mode 100644 index 0000000..bbc0350 --- /dev/null +++ b/back/volume/src/chat/dto/updateUser.dto.ts @@ -0,0 +1,16 @@ + +import { IsNumber, IsString} from 'class-validator' + +export class IdDto { + @IsNumber() + id: number +} + +export class PasswordDto { + @IsString() + password: string +} + +export class MuteDto { + data: Array +} diff --git a/back/volume/src/chat/entity/channel.entity.ts b/back/volume/src/chat/entity/channel.entity.ts index f2b51c9..475e0a9 100644 --- a/back/volume/src/chat/entity/channel.entity.ts +++ b/back/volume/src/chat/entity/channel.entity.ts @@ -57,5 +57,5 @@ export default class Channel { @ManyToMany(() => User) // refuse post @JoinTable() - muted: User[] + muted: Array> } diff --git a/front/volume/src/components/Channels.svelte b/front/volume/src/components/Channels.svelte index 95ff953..eb2e543 100644 --- a/front/volume/src/components/Channels.svelte +++ b/front/volume/src/components/Channels.svelte @@ -94,7 +94,7 @@ }); if (response.ok) { const user = await response.json(); - const response2 = await fetch(API_URL + "/channels/" + id, { + const response2 = await fetch(API_URL + "/channels/" + id + "/invite", { credentials: "include", method: "POST", mode: "cors", From a5e89a906575594d413a160f328cccdb007e68e8 Mon Sep 17 00:00:00 2001 From: vvandenb Date: Wed, 15 Mar 2023 10:20:30 +0100 Subject: [PATCH 7/9] * Fixed many pong bugs --- back/volume/src/pong/game/Ball.ts | 16 +++++----- back/volume/src/pong/game/Game.ts | 32 ++++++++------------ back/volume/src/pong/pong.gateway.ts | 2 +- back/volume/src/pong/pong.service.ts | 14 ++++----- front/volume/src/components/Pong/Paddle.ts | 2 +- front/volume/src/components/Pong/Pong.svelte | 1 + 6 files changed, 31 insertions(+), 36 deletions(-) diff --git a/back/volume/src/pong/game/Ball.ts b/back/volume/src/pong/game/Ball.ts index fe5f76f..544f075 100644 --- a/back/volume/src/pong/game/Ball.ts +++ b/back/volume/src/pong/game/Ball.ts @@ -20,7 +20,7 @@ export class Ball { constructor ( spawn: Point, size: Point = DEFAULT_BALL_SIZE, - speed: Point = DEFAULT_BALL_INITIAL_SPEED + speed: Point = DEFAULT_BALL_INITIAL_SPEED.clone() ) { this.rect = new Rect(spawn, size) this.speed = speed @@ -93,21 +93,23 @@ export class Ball { playerScored (): number { let indexPlayerScored: number + if (this.rect.center.x <= this.spawn.x) { indexPlayerScored = 1 + this.speed.x = this.initial_speed.x } else { indexPlayerScored = 0 + this.speed.x = -this.initial_speed.x } - this.rect.center = this.spawn.clone() - if (this.speed.x < 0) { - this.speed.x = this.initial_speed.x - this.speed.y = -this.initial_speed.y - } else { - this.speed.x = -this.initial_speed.x + if (this.speed.y < 0) { this.speed.y = this.initial_speed.y + } else { + this.speed.y = -this.initial_speed.y } + this.rect.center = this.spawn.clone() + return indexPlayerScored } } diff --git a/back/volume/src/pong/game/Game.ts b/back/volume/src/pong/game/Game.ts index 4336be4..7c3d3ee 100644 --- a/back/volume/src/pong/game/Game.ts +++ b/back/volume/src/pong/game/Game.ts @@ -21,7 +21,6 @@ export class Game { map: MapDtoValidated ball: Ball players: Player[] = [] - playing: boolean ranked: boolean waitingForTimeout: boolean gameStoppedCallback: (name: string) => void @@ -37,7 +36,6 @@ export class Game { ) { this.id = randomUUID() this.timer = null - this.playing = false this.ranked = ranked this.waitingForTimeout = false this.map = map @@ -99,7 +97,6 @@ export class Game { void this.pongService.setInGame(p.name) p.newGame() }) - this.playing = true 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`) @@ -111,21 +108,20 @@ export class Game { } stop (): void { - if (this.timer !== null && this.playing) { - this.playing = false + if (this.timer !== null) { clearInterval(this.timer) - this.timer = null - this.pongService - .saveResult(this.players, this.ranked) - .then(() => { - this.gameStoppedCallback(this.players[0].name) - this.players = [] - }) - .catch(() => { - this.gameStoppedCallback(this.players[0].name) - this.players = [] - }) } + this.timer = null + this.pongService + .saveResult(this.players, this.ranked, DEFAULT_WIN_SCORE) + .then(() => { + this.gameStoppedCallback(this.players[0].name) + this.players = [] + }) + .catch(() => { + this.gameStoppedCallback(this.players[0].name) + this.players = [] + }) } movePaddle (name: string | undefined, position: Point): void { @@ -142,10 +138,6 @@ export class Game { }) } - isPlaying (): boolean { - return this.playing - } - private gameLoop (): void { if (this.waitingForTimeout) { return diff --git a/back/volume/src/pong/pong.gateway.ts b/back/volume/src/pong/pong.gateway.ts index 99c3e1d..f2df12b 100644 --- a/back/volume/src/pong/pong.gateway.ts +++ b/back/volume/src/pong/pong.gateway.ts @@ -46,7 +46,7 @@ export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect { ): void { const name: string | undefined = this.socketToPlayerName.get(client) const game: Game | undefined = this.games.playerGame(name) - if (game?.isPlaying() !== undefined) { + if (game !== undefined) { game.stop() } if (name !== undefined) { diff --git a/back/volume/src/pong/pong.service.ts b/back/volume/src/pong/pong.service.ts index d024c07..b0f8a06 100644 --- a/back/volume/src/pong/pong.service.ts +++ b/back/volume/src/pong/pong.service.ts @@ -15,18 +15,18 @@ export class PongService { private readonly usersService: UsersService ) {} - async updateStats (player: User, i: number, result: Result): Promise { + async updateStats (player: User, i: number, result: Result, maxScore: number): Promise { player.matchs++ - if (result.score[i] > result.score[Math.abs(i - 1)]) player.wins++ + if (result.score[i] === maxScore) player.wins++ else player.looses++ player.winrate = (100 * player.wins) / player.matchs player.rank = (await this.usersService.getRank(player.ftId)) + 1 } - async updatePlayer (i: number, result: Result): Promise { + 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) + if (result.ranked) await this.updateStats(player, i, result, maxScore) player.results.push(result) player.status = 'online' await this.usersService.save(player) @@ -38,7 +38,7 @@ export class PongService { await this.usersService.save(player) } - async saveResult (players: Player[], ranked: boolean): Promise { + 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)) @@ -47,8 +47,8 @@ export class PongService { result.players = ply result.score = [players[0].score, players[1].score] await this.resultsRepository.save(result) - await this.updatePlayer(0, result) - await this.updatePlayer(1, result) + await this.updatePlayer(0, result, maxScore) + await this.updatePlayer(1, result, maxScore) } async getHistory ( diff --git a/front/volume/src/components/Pong/Paddle.ts b/front/volume/src/components/Pong/Paddle.ts index 727fc69..4f3359c 100644 --- a/front/volume/src/components/Pong/Paddle.ts +++ b/front/volume/src/components/Pong/Paddle.ts @@ -19,7 +19,7 @@ export class Paddle { new Point(this.rect.center.x + offset, this.rect.center.y), new Point(this.rect.size.x / 3, this.rect.size.y) ); - render_rect.draw(context, "yellow"); + render_rect.draw(context, color); } move(e: MouseEvent) { diff --git a/front/volume/src/components/Pong/Pong.svelte b/front/volume/src/components/Pong/Pong.svelte index ef47463..0afd251 100644 --- a/front/volume/src/components/Pong/Pong.svelte +++ b/front/volume/src/components/Pong/Pong.svelte @@ -70,6 +70,7 @@ } if (data.yourPaddleIndex !== -2) { gamePlaying = true; + game.ranked = data.ranked; game.setInfo(data); } } From 0da5988b7d53d7c7b2378ad62feaab3565421f3d Mon Sep 17 00:00:00 2001 From: nicolas-arnaud Date: Wed, 15 Mar 2023 10:50:34 +0100 Subject: [PATCH 8/9] fixed personals histories --- back/volume/src/chat/entity/channel.entity.ts | 1 + front/volume/src/App.svelte | 11 +++-------- front/volume/src/components/Profile.svelte | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/back/volume/src/chat/entity/channel.entity.ts b/back/volume/src/chat/entity/channel.entity.ts index 475e0a9..6ab26bf 100644 --- a/back/volume/src/chat/entity/channel.entity.ts +++ b/back/volume/src/chat/entity/channel.entity.ts @@ -30,6 +30,7 @@ export default class Channel { @BeforeInsert() async hashPassword () { + if (this.password === '') return this.password = await bcrypt.hash( this.password, Number(process.env.HASH_SALT) diff --git a/front/volume/src/App.svelte b/front/volume/src/App.svelte index 083e860..cd979b8 100644 --- a/front/volume/src/App.svelte +++ b/front/volume/src/App.svelte @@ -61,7 +61,7 @@ setAppState(APPSTATE.PROFILE); } - let profileUsername: string; + let profileUsername: string = ""; async function openIdProfile(event: CustomEvent) { profileUsername = event.detail; setAppState(APPSTATE.PROFILE_ID); @@ -71,10 +71,6 @@ setAppState(APPSTATE.HISTORY); } - async function openIdHistory() { - setAppState(APPSTATE.HISTORY_ID); - } - async function clickFriends() { setAppState(APPSTATE.FRIENDS); } @@ -86,7 +82,6 @@ function clickChannels() { setAppState(APPSTATE.CHANNELS); } - let channels: Array = []; let selectedChannel: ChannelsType; const handleSelectChannel = (channel: ChannelsType) => { selectedChannel = channel; @@ -177,7 +172,7 @@ {/if} {#if appState === APPSTATE.PROFILE}
- + setAppState(APPSTATE.HISTORY_ID)} />
{/if} {#if appState === APPSTATE.PROFILE_ID} @@ -187,7 +182,7 @@ on:keydown={() => setAppState(APPSTATE.CHANNELS + "#" + selectedChannel.name)} > - + setAppState(APPSTATE.HISTORY_ID)} /> {/if} diff --git a/front/volume/src/components/Profile.svelte b/front/volume/src/components/Profile.svelte index 8a9a71b..a8cdddd 100644 --- a/front/volume/src/components/Profile.svelte +++ b/front/volume/src/components/Profile.svelte @@ -96,7 +96,7 @@

-

From b7fb9617d575bf1c3bf87195953d42921398995c Mon Sep 17 00:00:00 2001 From: nicolas-arnaud Date: Wed, 15 Mar 2023 12:26:59 +0100 Subject: [PATCH 9/9] *fix private chan visibles *socketKey safety *fix rank --- back/volume/src/pong/pong.service.ts | 1 - back/volume/src/users/users.service.ts | 20 ++++++++++---------- front/volume/src/components/Channels.svelte | 4 ++-- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/back/volume/src/pong/pong.service.ts b/back/volume/src/pong/pong.service.ts index b0f8a06..2c59d63 100644 --- a/back/volume/src/pong/pong.service.ts +++ b/back/volume/src/pong/pong.service.ts @@ -20,7 +20,6 @@ export class PongService { if (result.score[i] === maxScore) player.wins++ else player.looses++ player.winrate = (100 * player.wins) / player.matchs - player.rank = (await this.usersService.getRank(player.ftId)) + 1 } async updatePlayer (i: number, result: Result, maxScore: number): Promise { diff --git a/back/volume/src/users/users.service.ts b/back/volume/src/users/users.service.ts index ae2d26e..858d86f 100644 --- a/back/volume/src/users/users.service.ts +++ b/back/volume/src/users/users.service.ts @@ -21,9 +21,7 @@ export class UsersService { async findUsers (): Promise { const users = await this.usersRepository.find({}) - users.forEach((usr) => { - usr.socketKey = '' - }) + users.forEach((usr) => usr.socketKey = '') return users } @@ -33,6 +31,7 @@ export class UsersService { relations: { results: true } }) if (user == null) throw new BadRequestException('User not found.') + user.rank = (await this.getRank(user.ftId)) + 1; return user } @@ -43,9 +42,7 @@ export class UsersService { if (Date.now() - usr.lastAccess > 60000) { usr.isVerified = false usr.status = 'offline' - this.usersRepository.save(usr).catch((err) => { - console.log(err) - }) + this.usersRepository.save(usr).catch((err) => console.log(err)) } }) } @@ -53,6 +50,7 @@ export class UsersService { async findUser (ftId: number): Promise { const user = await this.usersRepository.findOneBy({ ftId }) if (user == null) return null + user.rank = (await this.getRank(user.ftId)) + 1; user.lastAccess = Date.now() if (user.status === 'offline') user.status = 'online' await this.usersRepository.save(user) @@ -63,9 +61,7 @@ export class UsersService { const users = await this.usersRepository.find({ where: { status: 'online' } }) - users.forEach((usr) => { - usr.socketKey = '' - }) + users.forEach((usr) => usr.socketKey = '') return users } @@ -102,6 +98,7 @@ export class UsersService { relations: { friends: true } }) if (user == null) throw new BadRequestException('User not found.') + user.friends.forEach((friend) => friend.socketKey = '') return user.friends } @@ -113,6 +110,7 @@ export class UsersService { } }) if (user == null) throw new BadRequestException('User not found.') + user.followers.forEach((follower) => follower.socketKey = '') return user.followers } @@ -122,7 +120,9 @@ export class UsersService { winrate: 'DESC' } }) - return leaderboard.filter((user) => user.rank !== 0) + let ret = leaderboard.filter((user) => user.rank !== 0) + ret.forEach((follower) => follower.socketKey = '') + return ret } async getRank (ftId: number): Promise { diff --git a/front/volume/src/components/Channels.svelte b/front/volume/src/components/Channels.svelte index eb2e543..cdee9b0 100644 --- a/front/volume/src/components/Channels.svelte +++ b/front/volume/src/components/Channels.svelte @@ -56,8 +56,8 @@ body: JSON.stringify({ name: name, owner: $store.ftId, - password: password || "", - isPrivate: privacy, + password: password, + isPrivate: privacy === "private", }), }); if (response.ok) {