Browse Source

routes refactoring and chat fetchs start to work

delete channel and chatServices to check is a user is...

fixed friends invitations

LINT

lint
master
nicolas-arnaud 2 years ago
parent
commit
b84ea3481d
  1. 140
      back/volume/src/chat/chat.controller.ts
  2. 9
      back/volume/src/chat/chat.module.ts
  3. 136
      back/volume/src/chat/chat.service.ts
  4. 13
      back/volume/src/chat/dto/connection.dto.ts
  5. 27
      back/volume/src/chat/dto/create-channel.dto.ts
  6. 8
      back/volume/src/chat/dto/create-message.dto.ts
  7. 30
      back/volume/src/chat/dto/update-channel.dto.ts
  8. 55
      back/volume/src/chat/entity/channel.entity.ts
  9. 16
      back/volume/src/chat/entity/connection.entity.ts
  10. 15
      back/volume/src/chat/entity/dm.entity.ts
  11. 15
      back/volume/src/chat/entity/message.entity.ts
  12. 33
      back/volume/src/pong/pong.controller.ts
  13. 2
      back/volume/src/pong/pong.module.ts
  14. 6
      back/volume/src/users/entity/user.entity.ts
  15. 41
      back/volume/src/users/users.controller.ts
  16. 9
      back/volume/src/users/users.service.ts
  17. 2
      front/volume/src/App.svelte
  18. 4
      front/volume/src/Auth.ts
  19. 2
      front/volume/src/FakeLogin.svelte
  20. 88
      front/volume/src/components/Channels.svelte
  21. 22
      front/volume/src/components/Chat.svelte
  22. 6
      front/volume/src/components/Friends.svelte
  23. 2
      front/volume/src/components/Leaderboard.svelte
  24. 11
      front/volume/src/components/MatchHistory.svelte
  25. 2
      front/volume/src/components/NavBar.svelte
  26. 16
      front/volume/src/components/Profile.svelte

140
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")
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 {
private readonly channelService: ChannelService;
private readonly usersService: UsersService;
constructor (
private readonly channelService: ChannelService,
private readonly usersService: UsersService
) {}
@Get("channels/:id")
getChannelsForUser(@Param("id") id: number): Promise<Array<Channel>> {
return this.channelService.getChannelsForUser(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")
async createChannel(@Body() channel: CreateChannelDto) {
return await this.channelService.createChannel(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)
}
@Delete("channels/:id")
async deleteChannel(@Param("id") id: number) {
return await this.channelService.removeChannel(id);
@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)
}
@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(':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/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(':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/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);
@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
}
@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);
throw new BadRequestException('You are not the owner of this 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);
@Get()
@UseGuards(AuthenticatedGuard)
async getChannelsForUser (@Profile42() profile: Profile): Promise<Channel[]> {
return await this.channelService.getChannelsForUser(profile.id)
}
@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);
@Post()
async createChannel (@Body() channel: CreateChannelDto) {
return await this.channelService.createChannel(channel)
}
}

9
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 {}

136
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<Channel>,
private readonly usersService: UsersService,
private readonly usersService: UsersService
) {}
async createChannel(channel: CreateChannelDto): Promise<Channel> {
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<Channel> {
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<Channel[]> {
let rooms: Channel[] = []
rooms = [
...(await this.ChannelRepository.createQueryBuilder('room')
.where('room.isPrivate = false')
.getMany())
]
async getChannelsForUser(ftId: number): Promise<Array<Channel>> {
const query = await this.ChannelRepository.createQueryBuilder('room')
rooms = [
...rooms,
...(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?
.where('room.isPrivate = true')
.andWhere('users.ftId = :ftId', { ftId })
.getMany())
]
return rooms
}
async addUserToChannel(channel: Channel, user: User): Promise<Channel> {
channel.owner = user;
return await this.ChannelRepository.save(channel);
async addUserToChannel (channel: Channel, user: User): Promise<Channel> {
channel.owner = user
return await this.ChannelRepository.save(channel)
}
async getChannel(id: number): Promise<Channel> {
const channel = await this.ChannelRepository.findOneBy({ id });
if (!channel) throw new NotFoundException(`Channel #${id} not found`);
return channel;
async getChannel (id: number): Promise<Channel> {
const channel = await this.ChannelRepository.findOneBy({ id })
if (channel == null) { 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(id: number) {
await this.ChannelRepository.delete(id);
async removeChannel (channelId: number) {
await this.ChannelRepository.delete(channelId)
}
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
}
}

13
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
}

27
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
}

8
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
}

30
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
}

55
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

16
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
}

15
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[]
}

15
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

33
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<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)
}
}

2
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 {}

6
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[]

41
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<User[]> {
@ -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<number> {
return await this.usersService.getRank(id)
}
@Get('globalHistory')
@UseGuards(AuthenticatedGuard)
async getGlobalHistory (
@Paginate() query: PaginateQuery
): Promise<Paginated<Result>> {
return await this.pongService.getHistory(query, 0)
}
@Get('history/:id')
@UseGuards(AuthenticatedGuard)
async getHistoryById (
@Param('id', ParseIntPipe) id: number,
@Paginate() query: PaginateQuery
): Promise<Paginated<Result>> {
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<User> {
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<void> {
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

9
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)

2
front/volume/src/App.svelte

@ -148,7 +148,7 @@
</div>
{:else}
<div on:click={resetAppState} on:keydown={resetAppState}>
<Channels {channels} onSelectChannel={handleSelectChannel} />
<Channels onSelectChannel={handleSelectChannel} />
</div>
{/if}
{/if}

4
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",

2
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",

88
front/volume/src/components/Channels.svelte

@ -1,34 +1,31 @@
<script lang="ts" context="module">
import type { chatMessagesType } from "./Chat.svelte";
export interface ChannelsType {
id: string;
id: number;
name: string;
privacy: string;
isPrivate: boolean;
password: string;
owner: string;
owner: number;
}
import { onMount } from "svelte";
import { API_URL, store } from "../Auth";
import { dataset_dev } from "svelte/internal";
</script>
<script lang="ts">
//--------------------------------------------------------------------------------/
export let channels: Array<ChannelsType> = [];
// onMount(async () => {
// const res = await fetch(API_URL + "/channels" + $store.ftId, {
// method: "GET",
// mode: "cors",
// });
// const data = await res.json();
// channels = data;
// });
let channels: Array<ChannelsType> = [];
onMount(async () => {
const res = await fetch(API_URL + "/channels", {
credentials: "include",
mode: "cors",
});
if (res.ok) channels = await res.json();
});
//--------------------------------------------------------------------------------/
export let onSelectChannel: (channel: ChannelsType) => void;
const selectChat = (id: string) => {
const selectChat = (id: number) => {
const channel = channels.find((c) => c.id === id);
if (channel) {
onSelectChannel(channel);
@ -36,7 +33,6 @@
};
//--------------------------------------------------------------------------------/
const createChannel = async () => {
const name = prompt("Enter a name for the new channel:");
if (name) {
@ -54,47 +50,42 @@
}
}
if (privacy === "public" || password) {
const newChannel: ChannelsType = {
id: Math.random().toString(),
name,
owner: $store.username,
password,
privacy,
};
// const response = await fetch(API_URL + "/channels" + $store.ftId , {
// method: "POST",
// mode: "cors",
// body: JSON.stringify(newChannel),
// });
// const data = await response.json();
// if (data.ok) {
// channels = [newChannel, ...channels];
// } else {
// alert("Error creating channel");
// }
channels = [newChannel, ...channels];
const response = await fetch(API_URL + "/channels", {
credentials: "include",
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: name,
owner: $store.ftId,
password: password || "",
isPrivate: privacy === "private",
}),
});
if (response.ok) {
channels.push(await response.json());
} else {
alert("Error creating channel");
}
}
}
};
//--------------------------------------------------------------------------------/
const removeChannel = async (id: string) => {
const removeChannel = async (id: number) => {
let string = prompt("type 'delete' to delete this channel");
if (string === "delete") {
// const response = await fetch(API_URL + "/channels" + $store.ftId + "/" + id, {
// method: "DELETE",
// mode: "cors",
// });
// const data = await response.json();
// if (data.ok) {
// channels = channels.filter((c) => c.id !== id);
// } else {
// alert("Error deleting channel");
// }
channels = channels.filter((c) => c.id !== id);
const response = await fetch(API_URL + "/channels/" + id, {
credentials: "include",
method: "DELETE",
mode: "cors",
});
if (response.ok) channels = channels.filter((c) => c.id !== id);
else alert("Error deleting channel");
}
// TODO: save to database
};
//--------------------------------------------------------------------------------/
@ -134,7 +125,6 @@
justify-content: center;
align-items: center;
}
.channels {
background-color: #fff;
border: 1px solid #ccc;

22
front/volume/src/components/Chat.svelte

@ -75,7 +75,7 @@
// let chatMembers: Array<Player> = [];
// async function getChatMembers() {
// console.log("Getting chat members");
// const res = await fetch(API_URL + "/chat/members", {
// const res = await fetch(API_URL + "/channels/members", {
// mode: "cors",
// });
// chatMembers = await res.json();
@ -97,11 +97,11 @@
const banUser = async (username: string) => {
// const prompt = window.prompt("Enter ban duration in seconds");
// const res1 = await fetch(API_URL + "/user/" + username, {
// const res1 = await fetch(API_URL + "/users/" + username + "/byname", {
// mode: "cors",
// });
// const data1 = await res1.json();
// const res2 = await fetch(API_URL + "/chat/channels/" + data1.ftId + "/ban", {
// const res2 = await fetch(API_URL + "/channels/" + data1.ftId + "/ban", {
// method: "POST",
// mode: "cors",
// });
@ -117,11 +117,11 @@
const kickUser = async (username: string) => {
// set-up channel joining and kicking
// const res1 = await fetch(API_URL + "/user/" + username, {
// const res1 = await fetch(API_URL + "/users/" + username + "/byname", {
// mode: "cors",
// });
// const data1 = await res1.json();
// const res2 = await fetch(API_URL + "/chat/channels/" + data1.ftId + "/kick", {
// const res2 = await fetch(API_URL + "/channels/" + data1.ftId + "/kick", {
// method: "POST",
// mode: "cors",
// });
@ -138,11 +138,11 @@
const muteUser = async (username: string) => {
// use minutes prompt to determine mute duration
// const prompt = window.prompt("Enter mute duration in seconds");
// const res1 = await fetch(API_URL + "/user/" + username, {
// const res1 = await fetch(API_URL + "/users/" + username + "/byname", {
// mode: "cors",
// });
// const data1 = await res1.json();
// const res2 = await fetch(API_URL + "/chat/channels/" + data1.ftId + "/mute", {
// const res2 = await fetch(API_URL + "/channels/" + data1.ftId + "/mute", {
// method: "POST",
// mode: "cors",
// });
@ -157,11 +157,11 @@
//--------------------------------------------------------------------------------/
const adminUser = async (username: string) => {
// const res1 = await fetch(API_URL + "/user/" + username, {
// const res1 = await fetch(API_URL + "/users/" + username + "/byname", {
// mode: "cors",
// });
// const data1 = await res1.json();
// const res2 = await fetch(API_URL + "/chat/channels/" + data1.ftId + "/admin", {
// const res2 = await fetch(API_URL + "/channels/" + data1.ftId + "/admin", {
// method: "POST",
// mode: "cors",
// });
@ -176,11 +176,11 @@
//--------------------------------------------------------------------------------/
const removeAdminUser = async (username: string) => {
// const res1 = await fetch(API_URL + "/user/" + username, {
// const res1 = await fetch(API_URL + "/users/" + username + "/byname", {
// mode: "cors",
// });
// const data1 = await res1.json();
// const res2 = await fetch(API_URL + "/chat/channels/" + data1.ftId + "/admin", {
// const res2 = await fetch(API_URL + "/channels/" + data1.ftId + "/admin", {
// method: "DELETE",
// mode: "cors",
// });

6
front/volume/src/components/Friends.svelte

@ -12,7 +12,7 @@
? event.target.querySelector('input[type="text"]').value
: event.detail;
const response = await fetch(API_URL + "/invit/" + username, {
const response = await fetch(API_URL + "/users/invit/" + username, {
credentials: "include",
mode: "cors",
});
@ -34,14 +34,14 @@
let friendsInterval: ReturnType<typeof setInterval>;
async function getFriends(): Promise<void> {
let response = await fetch(API_URL + "/friends", {
let response = await fetch(API_URL + "/users/friends", {
credentials: "include",
mode: "cors",
});
friends = await response.json();
}
async function getInvits(): Promise<void> {
let response = await fetch(API_URL + "/invits", {
let response = await fetch(API_URL + "/users/invits", {
credentials: "include",
mode: "cors",
});

2
front/volume/src/components/Leaderboard.svelte

@ -6,7 +6,7 @@
let leaderboard: Array<Player> = [];
async function getLeader(): Promise<void> {
let response = await fetch(API_URL + "/leaderboard", {
let response = await fetch(API_URL + "/users/leaderboard", {
credentials: "include",
mode: "cors",
});

11
front/volume/src/components/MatchHistory.svelte

@ -25,17 +25,17 @@
let newBatch: Array<Match> = [];
async function fetchData() {
let response;
let response: Response;
if (username === "Global") {
response = await fetch(`${API_URL}/globalHistory?page=${page}`, {
response = await fetch(`${API_URL}/results/global?page=${page}`, {
credentials: "include",
mode: "cors",
});
} else {
response = await fetch(`${API_URL}/user/${username}`);
response = await fetch(`${API_URL}/users/${username}/byname`);
if (response.ok) {
let user = await response.json();
response = await fetch(`${API_URL}/history/${user.ftId}?page=${page}`, {
response = await fetch(`${API_URL}/results/${user.ftId}?page=${page}`, {
credentials: "include",
mode: "cors",
});
@ -46,8 +46,7 @@
return {
players: match.players,
score: match.score,
date:
new Date(match.date).toLocaleString("fr-FR", {
date: new Date(match.date).toLocaleString("fr-FR", {
timeZone: "Europe/Paris",
dateStyle: "short",
timeStyle: "short",

2
front/volume/src/components/NavBar.svelte

@ -50,7 +50,7 @@
{#if link.text === "Profile"}
<li>
<button on:click={clickProfile}>
<img src={api + "/avatar"} alt="avatar" />
<img src={api + "/users/avatar"} alt="avatar" />
</button>
</li>
{/if}

16
front/volume/src/components/Profile.svelte

@ -24,7 +24,7 @@
async function getUser() {
if (username !== $store.username) {
edit = false;
const res = await fetch(API_URL + "/user/" + username, {
const res = await fetch(API_URL + "/users/" + username + "/byname", {
mode: "cors",
});
user = res.json();
@ -37,7 +37,7 @@
const dispatch = createEventDispatcher();
async function handleSubmit() {
let response = await fetch(API_URL, {
let response = await fetch(API_URL + "/users", {
headers: { "content-type": "application/json" },
method: "POST",
body: JSON.stringify({ username: user.username }),
@ -52,7 +52,7 @@
async function handle2fa(event: Event) {
event.preventDefault();
user.twoFA = !user.twoFA;
let response = await fetch(API_URL, {
let response = await fetch(API_URL + "/users", {
headers: { "content-type": "application/json" },
method: "POST",
body: JSON.stringify(user),
@ -69,10 +69,10 @@
<h3>===| <mark>{user.username}'s Profile</mark> |===</h3>
<div class="profile-header">
{#if edit}
<img src={API_URL + "/avatar"} alt="avatar" class="profile-img" />
<img src={API_URL + "/users/avatar"} alt="avatar" class="profile-img" />
{:else}
<form
action={`${API_URL}/avatar`}
action={`${API_URL}/users/avatar`}
method="post"
enctype="multipart/form-data"
bind:this={avatarForm}
@ -86,7 +86,11 @@
/>
</form>
<label class="img-class" for="avatar-input">
<img src={API_URL + "/avatar"} alt="avatar" class="profile-img" />
<img
src={API_URL + "/users/avatar"}
alt="avatar"
class="profile-img"
/>
</label>
{/if}
</div>

Loading…
Cancel
Save