Browse Source

added chat service

master
nicolas-arnaud 2 years ago
parent
commit
e8fe461944
  1. 99
      back/volume/src/chat/chat.controller.ts
  2. 2
      back/volume/src/chat/chat.gateway.ts
  3. 8
      back/volume/src/chat/chat.module.ts
  4. 78
      back/volume/src/chat/chat.service.ts
  5. 10
      back/volume/src/chat/dto/connection.dto.ts
  6. 8
      back/volume/src/chat/dto/create-channel.dto.ts
  7. 12
      back/volume/src/chat/dto/create-message.dto.ts
  8. 20
      back/volume/src/chat/dto/update-channel.dto.ts
  9. 24
      back/volume/src/chat/dto/updateChannel.dto.ts
  10. 6
      back/volume/src/chat/entity/channel.entity.ts
  11. 9
      back/volume/src/users/users.controller.ts
  12. 2
      back/volume/src/users/users.service.ts
  13. 1
      front/volume/src/components/Friends.svelte

99
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<Array<Channel>> {
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);
}
}

2
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
}
}
*/

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

78
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<Channel>,
@InjectRepository(Message)
private readonly MessageRepository: Repository<Message>
private readonly usersService: UsersService,
) {}
async createChannel (Channel: Channel, creator: User): Promise<Channel> {
const newChannel = await this.addCreatorToChannel(Channel, creator)
return await this.ChannelRepository.save(newChannel)
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 getChannelsForUser (userId: number): Promise<Channel[]> {
return await this.ChannelRepository.find({}) // where userId is in User[] of channel?
async getChannelsForUser(ftId: number): Promise<Array<Channel>> {
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> {
Channel.users.push(creator)
return Channel
async addUserToChannel(channel: Channel, user: User): Promise<Channel> {
channel.owner = user;
return await this.ChannelRepository.save(channel);
}
async createMessage (message: Message): Promise<Message> {
return await this.MessageRepository.save(
this.MessageRepository.create(message)
)
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 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<Channel | null> {
return await this.ChannelRepository.findOneBy({ id })
}
async findMessagesInChannelForUser (
channel: Channel,
user: User
): Promise<Message[]> {
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);
}
}

10
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;
}

8
back/volume/src/chat/dto/createChannel.dto.ts → 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;
}

12
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;
}

20
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;
}

24
back/volume/src/chat/dto/updateChannel.dto.ts

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

6
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

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

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

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

@ -73,7 +73,6 @@
<span>{friend.username} is {friend.status}</span>
</li>
{/each}
/>
</div>
{:else}
<p>No friends to display</p>

Loading…
Cancel
Save