Browse Source
delete channel and chatServices to check is a user is... fixed friends invitations LINT lintmaster
nicolas-arnaud
2 years ago
26 changed files with 423 additions and 299 deletions
@ -1,99 +1,97 @@ |
|||||
import { |
import { |
||||
|
BadRequestException, |
||||
Body, |
Body, |
||||
Controller, |
Controller, |
||||
Delete, |
Delete, |
||||
Get, |
Get, |
||||
NotFoundException, |
NotFoundException, |
||||
Param, |
Param, |
||||
|
ParseIntPipe, |
||||
Post, |
Post, |
||||
} from "@nestjs/common"; |
UseGuards |
||||
//import { channel, Channel } from "diagnostics_channel";
|
} from '@nestjs/common' |
||||
import { Channel } from './entity/channel.entity'; |
import { AuthenticatedGuard } from 'src/auth/42-auth.guard' |
||||
import { ChannelService } from "./chat.service"; |
import { UsersService } from 'src/users/users.service' |
||||
import { CreateChannelDto } from "./dto/create-channel.dto"; |
import { ChannelService } from './chat.service' |
||||
import { UsersService } from "src/users/users.service"; |
|
||||
import { UpdateChannelDto } from "./dto/update-channel.dto"; |
|
||||
import { User } from "src/users/entity/user.entity"; |
|
||||
|
|
||||
@Controller("chat") |
import { CreateChannelDto } from './dto/create-channel.dto' |
||||
|
import { UpdateChannelDto } from './dto/update-channel.dto' |
||||
|
|
||||
|
import type User from 'src/users/entity/user.entity' |
||||
|
import type Channel from './entity/channel.entity' |
||||
|
import { Profile42 } from 'src/auth/42.decorator' |
||||
|
import { Profile } from 'passport-42' |
||||
|
|
||||
|
@Controller('channels') |
||||
export class ChatController { |
export class ChatController { |
||||
private readonly channelService: ChannelService; |
constructor ( |
||||
private readonly usersService: UsersService; |
private readonly channelService: ChannelService, |
||||
|
private readonly usersService: UsersService |
||||
|
) {} |
||||
|
|
||||
@Get("channels/:id") |
@Post(':id/admin') |
||||
getChannelsForUser(@Param("id") id: number): Promise<Array<Channel>> { |
async addAdmin (@Param('id') id: number, @Body() userId: number) { |
||||
return this.channelService.getChannelsForUser(id); |
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") |
@Delete(':id/admin') |
||||
async createChannel(@Body() channel: CreateChannelDto) { |
async removeAdmin (@Param('id') id: number, @Body() userId: number) { |
||||
return await this.channelService.createChannel(channel); |
const channel = await this.channelService.getChannel(id) |
||||
|
channel.admins = channel.admins.filter((usr: User) => { |
||||
|
return usr.ftId !== userId |
||||
|
}) |
||||
|
this.channelService.update(channel) |
||||
} |
} |
||||
|
|
||||
@Delete("channels/:id") |
@Post(':id/ban') |
||||
async deleteChannel(@Param("id") id: number) { |
async addBan (@Param('id') id: number, @Body() userId: number) { |
||||
return await this.channelService.removeChannel(id); |
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) |
||||
} |
} |
||||
|
|
||||
@Post("channels/:id/owner") |
@Post(':id/mute') |
||||
async moveOwner(@Param("id") id: number, @Body() userId: number) { |
async addMute (@Param('id') id: number, @Body() userId: number) { |
||||
const channel = await this.channelService.getChannel(id); |
const channel = await this.channelService.getChannel(id) |
||||
const user: User | null = await this.usersService.findUser(userId); |
const user: User | null = await this.usersService.findUser(userId) |
||||
if (user == null) throw new NotFoundException(`User #${userId} not found`); |
if (user == null) throw new NotFoundException(`User #${userId} not found`) |
||||
channel.owner = user; |
channel.muted.push(user) |
||||
this.channelService.update(channel); |
this.channelService.update(channel) |
||||
} |
} |
||||
|
|
||||
@Post("channels/:id/admin") |
@Delete(':id/mute') |
||||
async addAdmin(@Param("id") id: number, @Body() userId: number) { |
async removeMute (@Param('id') id: number, @Body() userId: number) { |
||||
const channel = await this.channelService.getChannel(id); |
const channel = await this.channelService.getChannel(id) |
||||
const user: User | null = await this.usersService.findUser(userId); |
channel.muted = channel.muted.filter((usr: User) => { |
||||
if (user == null) throw new NotFoundException(`User #${userId} not found`); |
return usr.ftId !== userId |
||||
channel.admins.push(user); |
}) |
||||
this.channelService.update(channel); |
this.channelService.update(channel) |
||||
} |
} |
||||
|
|
||||
@Delete("channels/:id/admin") |
@Delete(':id') |
||||
async removeAdmin(@Param("id") id: number, @Body() userId: number) { |
@UseGuards(AuthenticatedGuard) |
||||
const channel = await this.channelService.getChannel(id); |
async deleteChannel (@Profile42() profile: Profile, @Param('id') id: number) { |
||||
channel.admins = channel.admins.filter((a) => { |
if (await this.channelService.isOwner(id, +profile.id)) { |
||||
return a.ftId !== userId; |
await this.channelService.removeChannel(id) |
||||
}); |
return |
||||
this.channelService.update(channel); |
|
||||
} |
} |
||||
|
throw new BadRequestException('You are not the owner of this 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") |
@Get() |
||||
async removeBan(@Param("id") id: number, @Body() userId: number) { |
@UseGuards(AuthenticatedGuard) |
||||
const channel = await this.channelService.getChannel(id); |
async getChannelsForUser (@Profile42() profile: Profile): Promise<Channel[]> { |
||||
channel.banned = channel.banned.filter((a) => { |
return await this.channelService.getChannelsForUser(profile.id) |
||||
return a.ftId !== userId; |
|
||||
}); |
|
||||
this.channelService.update(channel); |
|
||||
} |
} |
||||
|
|
||||
@Post("channels/:id/mute") |
@Post() |
||||
async addMute(@Param("id") id: number, @Body() userId: number) { |
async createChannel (@Body() channel: CreateChannelDto) { |
||||
const channel = await this.channelService.getChannel(id); |
return await this.channelService.createChannel(channel) |
||||
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); |
|
||||
} |
} |
||||
} |
} |
||||
|
@ -1,56 +1,118 @@ |
|||||
import { Injectable, NotFoundException } from '@nestjs/common'; |
import { Injectable, NotFoundException } from '@nestjs/common' |
||||
import { InjectRepository } from '@nestjs/typeorm'; |
import { InjectRepository } from '@nestjs/typeorm' |
||||
import { Channel } from './entity/channel.entity'; |
import { Repository } from 'typeorm' |
||||
import { User } from 'src/users/entity/user.entity'; |
|
||||
import { Repository } from 'typeorm'; |
import { type CreateChannelDto } from './dto/create-channel.dto' |
||||
import { CreateChannelDto } from './dto/create-channel.dto'; |
import { UsersService } from 'src/users/users.service' |
||||
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() |
@Injectable() |
||||
export class ChannelService { |
export class ChannelService { |
||||
constructor ( |
constructor ( |
||||
@InjectRepository(Channel) |
@InjectRepository(Channel) |
||||
private readonly ChannelRepository: Repository<Channel>, |
private readonly ChannelRepository: Repository<Channel>, |
||||
private readonly usersService: UsersService, |
private readonly usersService: UsersService |
||||
) {} |
) {} |
||||
|
|
||||
async createChannel (channel: CreateChannelDto): Promise<Channel> { |
async createChannel (channel: CreateChannelDto): Promise<Channel> { |
||||
const newChannel = this.ChannelRepository.create({ |
const user: User | null = await this.usersService.findUser(channel.owner) |
||||
name: channel.name, |
if (user == null) { |
||||
password: channel.password, |
throw new NotFoundException(`User #${channel.owner} not found`) |
||||
}); |
} |
||||
let user: User| null = await this.usersService.findUser(channel.owner); |
const newChannel = new Channel() |
||||
if (user == null) throw new NotFoundException(`User #${channel.owner} not found`) |
newChannel.owner = user |
||||
newChannel.owner = user; |
newChannel.users = [user] |
||||
return await this.ChannelRepository.save(newChannel); |
newChannel.admins = [user] |
||||
} |
newChannel.name = channel.name |
||||
|
newChannel.isPrivate = channel.isPrivate |
||||
async getChannelsForUser(ftId: number): Promise<Array<Channel>> { |
newChannel.password = channel.password |
||||
const query = await this.ChannelRepository.createQueryBuilder('room') |
return await this.ChannelRepository.save(newChannel) |
||||
|
} |
||||
|
|
||||
|
async getChannelsForUser (ftId: number): Promise<Channel[]> { |
||||
|
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') |
.innerJoin('room.users', 'users') |
||||
.where('users.ftId = :ftId', { ftId }) |
.where('room.isPrivate = true') |
||||
.leftJoinAndSelect('room.users', 'all_users') |
.andWhere('users.ftId = :ftId', { ftId }) |
||||
.orderBy('room.id', 'DESC') // TODO: order by last message
|
.getMany()) |
||||
.getRawMany(); |
] |
||||
return query; //where userId is in User[] of channel?
|
return rooms |
||||
} |
} |
||||
|
|
||||
async addUserToChannel (channel: Channel, user: User): Promise<Channel> { |
async addUserToChannel (channel: Channel, user: User): Promise<Channel> { |
||||
channel.owner = user; |
channel.owner = user |
||||
return await this.ChannelRepository.save(channel); |
return await this.ChannelRepository.save(channel) |
||||
} |
} |
||||
|
|
||||
async getChannel (id: number): Promise<Channel> { |
async getChannel (id: number): Promise<Channel> { |
||||
const channel = await this.ChannelRepository.findOneBy({ id }); |
const channel = await this.ChannelRepository.findOneBy({ id }) |
||||
if (!channel) throw new NotFoundException(`Channel #${id} not found`); |
if (channel == null) { throw new NotFoundException(`Channel #${id} not found`) } |
||||
return channel; |
return channel |
||||
} |
} |
||||
|
|
||||
async update (channel: Channel) { |
async update (channel: Channel) { |
||||
this.ChannelRepository.update(channel.id, 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<boolean> { |
||||
|
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<boolean> { |
||||
|
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<boolean> { |
||||
|
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<boolean> { |
||||
|
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<boolean> { |
||||
|
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 |
||||
|
} |
||||
|
} |
||||
|
@ -1,10 +1,13 @@ |
|||||
import { IsNumber } from 'class-validator'; |
import { IsNumber, IsOptional, IsString } from 'class-validator' |
||||
|
|
||||
export class ConnectionDto { |
export class ConnectionDto { |
||||
@IsNumber() |
@IsNumber() |
||||
UserId: number; |
UserId: number |
||||
@IsNumber() |
|
||||
ChannelId: number; |
|
||||
@IsNumber() |
@IsNumber() |
||||
SocketId: number; |
ChannelId: number |
||||
|
|
||||
|
@IsString() |
||||
|
@IsOptional() |
||||
|
pwd: string |
||||
} |
} |
||||
|
@ -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 { |
export class CreateChannelDto { |
||||
|
@IsOptional() |
||||
|
@IsPositive() |
||||
|
id: number |
||||
|
|
||||
@IsString() |
@IsString() |
||||
@IsAlpha() |
name: string |
||||
name: string; |
|
||||
|
|
||||
@IsPositive() |
@IsNumber() |
||||
owner: number; |
owner: number |
||||
|
|
||||
@IsOptional() |
@IsOptional() |
||||
password: string; |
password: string |
||||
|
|
||||
|
@IsBoolean() |
||||
|
@Transform(({ value }) => value === 'true') |
||||
|
isPrivate: boolean |
||||
} |
} |
||||
|
@ -1,12 +1,12 @@ |
|||||
import { IsNumber, IsString } from 'class-validator'; |
import { IsNumber, IsString } from 'class-validator' |
||||
|
|
||||
export class CreateMessageDto { |
export class CreateMessageDto { |
||||
@IsString() |
@IsString() |
||||
text: string; |
text: string |
||||
|
|
||||
@IsNumber() |
@IsNumber() |
||||
UserId: number; |
UserId: number |
||||
|
|
||||
@IsNumber() |
@IsNumber() |
||||
ChannelId: number; |
ChannelId: number |
||||
} |
} |
||||
|
@ -1,20 +1,30 @@ |
|||||
import { PartialType } from '@nestjs/mapped-types'; |
import { PartialType } from '@nestjs/mapped-types' |
||||
import { CreateChannelDto } from './create-channel.dto'; |
import { CreateChannelDto } from './create-channel.dto' |
||||
import { IsOptional, IsString } from 'class-validator'; |
import { IsNumber, IsOptional, IsString } from 'class-validator' |
||||
|
|
||||
export class UpdateChannelDto extends PartialType(CreateChannelDto) { |
export class UpdateChannelDto extends PartialType(CreateChannelDto) { |
||||
id: number; |
id: number |
||||
@IsOptional() |
@IsOptional() |
||||
users: [number]; |
@IsNumber() |
||||
|
users: [number] |
||||
|
|
||||
@IsOptional() |
@IsOptional() |
||||
messages: [number]; |
@IsNumber() |
||||
|
messages: [number] |
||||
|
|
||||
@IsOptional() |
@IsOptional() |
||||
owners: [number]; //user id
|
@IsNumber() |
||||
|
owners: [number] // user id
|
||||
|
|
||||
@IsOptional() |
@IsOptional() |
||||
banned: [number]; //user id
|
@IsNumber() |
||||
|
banned: [number] // user id
|
||||
|
|
||||
@IsOptional() |
@IsOptional() |
||||
muted: [number]; //user id
|
@IsNumber() |
||||
|
muted: [number] // user id
|
||||
|
|
||||
@IsString() |
@IsString() |
||||
@IsOptional() |
@IsOptional() |
||||
password: string; |
password: string |
||||
} |
} |
||||
|
@ -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 |
||||
|
} |
@ -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[] |
||||
|
} |
@ -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<Paginated<Result>> { |
||||
|
return await this.pongService.getHistory(query, 0) |
||||
|
} |
||||
|
|
||||
|
@Get(':id') |
||||
|
@UseGuards(AuthenticatedGuard) |
||||
|
async getHistoryById ( |
||||
|
@Param('id', ParseIntPipe) id: number, |
||||
|
@Paginate() query: PaginateQuery |
||||
|
): Promise<Paginated<Result>> { |
||||
|
return await this.pongService.getHistory(query, id) |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue