Browse Source

configuration and routes rework

master
nicolas-arnaud 2 years ago
parent
commit
f1d4b54d0c
  1. 16
      .env_sample
  2. 14
      README.md
  3. 12
      back/entrypoint.sh
  4. 27
      back/volume/src/app.controller.ts
  5. 33
      back/volume/src/app.module.ts
  6. 5
      back/volume/src/auth/42.strategy.ts
  7. 27
      back/volume/src/auth/auth.controller.ts
  8. 13
      back/volume/src/chat/chat.gateway.ts
  9. 6
      back/volume/src/chat/chat.module.ts
  10. 7
      back/volume/src/chat/chat.service.ts
  11. 0
      back/volume/src/chat/dto/createChannel.dto.ts
  12. 8
      back/volume/src/chat/dto/updateChannel.dto.ts
  13. 5
      back/volume/src/chat/entity/channel.entity.ts
  14. 3
      back/volume/src/chat/entity/message.entity.ts
  15. 25
      back/volume/src/db/db.module.ts
  16. 3
      back/volume/src/pong/pong.gateway.ts
  17. 7
      back/volume/src/users/dto/user.dto.ts
  18. 10
      back/volume/src/users/entity/user.entity.ts
  19. 48
      back/volume/src/users/users.controller.ts
  20. 2
      back/volume/src/users/users.module.ts
  21. 84
      back/volume/src/users/users.service.ts
  22. 2
      docker-compose.yml
  23. 14
      front/Dockerfile
  24. 18
      front/entrypoint.sh
  25. 12
      front/volume/package-lock.json
  26. 6
      front/volume/src/components/Pong/Pong.svelte
  27. 5
      front/volume/src/global.d.ts

16
.env_sample

@ -1,12 +1,16 @@
POSTGRES_HOST: postgres POSTGRES_HOST=postgres
POSTGRES_PORT: 5432 POSTGRES_PORT=5432
POSTGRES_USER: postgres_usr POSTGRES_USER=postgres_usr
POSTGRES_PASSWORD: postgres_pw POSTGRES_PASSWORD=postgres_pw
POSTGRES_DB: transcendence POSTGRES_DB=transcendence
PGADMIN_DEFAULT_EMAIL=admin@pg.com PGADMIN_DEFAULT_EMAIL=admin@pg.com
PGADMIN_DEFAULT_PASSWORD=admin PGADMIN_DEFAULT_PASSWORD=admin
FRONT_FPS=144
HOST=localhost
FRONT_PORT=80
BACK_PORT=3001 BACK_PORT=3001
HASH_SALT=10 HASH_SALT=10
@ -15,4 +19,4 @@ JWT_EXPIRATION_TIME=900
FT_OAUTH_CLIENT_ID= FT_OAUTH_CLIENT_ID=
FT_OAUTH_CLIENT_SECRET= FT_OAUTH_CLIENT_SECRET=
FT_OAUTH_CALLBACK_URL=http://localhost/ FT_OAUTH_CALLBACK_URL="http://$HOST:$BACK_PORT/log/inReturn"

14
README.md

@ -14,6 +14,20 @@ If you not use rootless docker, either rename Makesudo as Makefile or call `make
### Setting: ### Setting:
rename .env_sample to .env and customize it to your needs and credentials. rename .env_sample to .env and customize it to your needs and credentials.
## Back endpoints:
|Method|endpoint|description|
|:---:|:---:|:---:|
|GET |/log/in |the login using 42 api.|
|GET |/log/inReturn |the 42 api callback.|
|GET |/log/profile |get user 42's datas.|
|GET |/log/out |log out user.|
|GET |/ |return user datas.|
|POST|/ |update user datas.|
|GET |/friends |return users which are friends.|
|GET |/invits |return users which invited user to be friend.|
|POST|/invit/:id |invit user whith ftId: id as friend.|
|GET |/avatar |return the user avatar|
|POST|/avatar |set a user avatar with multipart post upload.|
## Dependencies: ## Dependencies:

12
back/entrypoint.sh

@ -1,11 +1,13 @@
npm install; npm install;
cat >.env <<EOF cat >.env <<EOF
POSTGRES_HOST= $POSTGRES_HOST POSTGRES_HOST=$POSTGRES_HOST
POSTGRES_PORT= $POSTGRES_PORT POSTGRES_PORT=$POSTGRES_PORT
POSTGRES_USER= $POSTGRES_USER POSTGRES_USER=$POSTGRES_USER
POSTGRES_PASSWORD= $POSTGRES_PASSWORD POSTGRES_PASSWORD=$POSTGRES_PASSWORD
POSTGRES_DB= $POSTGRES_DB POSTGRES_DB=$POSTGRES_DB
HOST=$HOST
FRONT_PORT=$FRONT_PORT
BACK_PORT=$BACK_PORT BACK_PORT=$BACK_PORT
HASH_SALT=$HASH_SALT HASH_SALT=$HASH_SALT

27
back/volume/src/app.controller.ts

@ -1,27 +0,0 @@
import { Controller, Get, Redirect, Req, UseGuards } from '@nestjs/common'
import { Request } from 'express'
import { Profile } from 'passport-42'
import { FtUser } from './auth/42.decorator'
import { AuthenticatedGuard } from './auth/42-auth.guard'
@Controller()
export class AppController {
@Get('profile')
@UseGuards(AuthenticatedGuard)
profile (@FtUser() user: Profile) {
return { user }
}
@Get('logout')
@Redirect('/')
logOut (@Req() req: Request) {
req.logOut(function (err) {
if (err) return err
})
}
@Get('ranks')
getRanks (): number[] {
return [1, 2, 3]
}
}

33
back/volume/src/app.module.ts

@ -1,11 +1,10 @@
import { Module } from '@nestjs/common' import { Module } from '@nestjs/common'
import { ConfigModule } from '@nestjs/config' import { ConfigModule, ConfigService } from '@nestjs/config'
import { TypeOrmModule } from '@nestjs/typeorm'
import * as Joi from 'joi' import * as Joi from 'joi'
import { AppController } from './app.controller'
import { AuthModule } from './auth/auth.module' import { AuthModule } from './auth/auth.module'
import { ChatModule } from './chat/chat.module' import { ChatModule } from './chat/chat.module'
import { DbModule } from './db/db.module'
import { PongModule } from './pong/pong.module' import { PongModule } from './pong/pong.module'
import { UsersModule } from './users/users.module' import { UsersModule } from './users/users.module'
@ -18,17 +17,33 @@ import { UsersModule } from './users/users.module'
POSTGRES_USER: Joi.string().required(), POSTGRES_USER: Joi.string().required(),
POSTGRES_PASSWORD: Joi.string().required(), POSTGRES_PASSWORD: Joi.string().required(),
POSTGRES_DB: Joi.string().required(), POSTGRES_DB: Joi.string().required(),
BACK_PORT: Joi.number(),
JWT_SECRET: Joi.string().required(), JWT_SECRET: Joi.string().required(),
JWT_EXPIRATION_TIME: Joi.string().required() JWT_EXPIRATION_TIME: Joi.string().required(),
HOST: Joi.string().required(),
FRONT_PORT: Joi.number().required(),
BACK_PORT: Joi.number().required(),
HASH_SALT: Joi.number().required()
})
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
type: 'postgres',
host: configService.get<string>('POSTGRES_HOST'),
port: configService.get<number>('POSTGRES_PORT'),
username: configService.get<string>('POSTGRES_USER'),
password: configService.get<string>('POSTGRES_PASSWORD'),
database: configService.get<string>('POSTGRES_DB'),
jwt_secret: configService.get<string>('JWT_SECRET'),
autoLoadEntities: true,
synchronize: true
}) })
}), }),
AuthModule, AuthModule,
ChatModule, ChatModule,
DbModule,
PongModule, PongModule,
UsersModule UsersModule
], ]
controllers: [AppController]
}) })
export class AppModule { } export class AppModule {}

5
back/volume/src/auth/42.strategy.ts

@ -2,11 +2,12 @@ import { Injectable } from '@nestjs/common'
import { ConfigService } from '@nestjs/config' import { ConfigService } from '@nestjs/config'
import { PassportStrategy } from '@nestjs/passport' import { PassportStrategy } from '@nestjs/passport'
import { Strategy, type Profile, type VerifyCallback } from 'passport-42' import { Strategy, type Profile, type VerifyCallback } from 'passport-42'
import { UsersService } from 'src/users/users.service'
import { User } from 'src/users/user.entity'
import { get } from 'https' import { get } from 'https'
import { createWriteStream } from 'fs' import { createWriteStream } from 'fs'
import { UsersService } from 'src/users/users.service'
import { User } from 'src/users/entity/user.entity'
@Injectable() @Injectable()
export class FtStrategy extends PassportStrategy(Strategy, '42') { export class FtStrategy extends PassportStrategy(Strategy, '42') {
constructor ( constructor (

27
back/volume/src/auth/auth.controller.ts

@ -1,16 +1,19 @@
import { Controller, Get, Redirect, UseGuards, Res, Req } from '@nestjs/common' import { Controller, Get, Redirect, UseGuards, Res, Req } from '@nestjs/common'
import { FtOauthGuard } from './42-auth.guard'
import { Response, Request } from 'express' import { Response, Request } from 'express'
import { Profile } from 'passport-42'
@Controller('auth') import { FtOauthGuard, AuthenticatedGuard } from './42-auth.guard'
import { FtUser } from './42.decorator'
@Controller('log')
export class AuthController { export class AuthController {
@Get('42') @Get('in')
@UseGuards(FtOauthGuard) @UseGuards(FtOauthGuard)
ftAuth () {} ftAuth () {}
@Get('42/return') @Get('inReturn')
@UseGuards(FtOauthGuard) @UseGuards(FtOauthGuard)
@Redirect('http://localhost:80/') @Redirect('http://' + process.env.HOST + ':' + process.env.FRONT_PORT + '/')
ftAuthCallback ( ftAuthCallback (
@Res({ passthrough: true }) response: Response, @Res({ passthrough: true }) response: Response,
@Req() request: Request @Req() request: Request
@ -18,4 +21,18 @@ export class AuthController {
console.log('cookie:', request.cookies['connect.sid']) console.log('cookie:', request.cookies['connect.sid'])
response.cookie('connect.sid', request.cookies['connect.sid']) response.cookie('connect.sid', request.cookies['connect.sid'])
} }
@Get('profile')
@UseGuards(AuthenticatedGuard)
profile (@FtUser() user: Profile) {
return { user }
}
@Get('out')
@Redirect('/')
logOut (@Req() req: Request) {
req.logOut(function (err) {
if (err) return err
})
}
} }

13
back/volume/src/chat/chat.gateway.ts

@ -1,3 +1,4 @@
import { UnauthorizedException } from '@nestjs/common'
import { import {
type OnGatewayConnection, type OnGatewayConnection,
type OnGatewayDisconnect, type OnGatewayDisconnect,
@ -7,14 +8,14 @@ import {
WebSocketServer WebSocketServer
} from '@nestjs/websockets' } from '@nestjs/websockets'
import { Socket, Server } from 'socket.io' import { Socket, Server } from 'socket.io'
import { type User } from 'src/users/user.entity'
import { UsersService } from 'src/users/users.service'
import { UnauthorizedException } from '@nestjs/common'
import { ChatService } from './chat.service' import { ChatService } from './chat.service'
import { Channel } from './model/channel.entity' import { type User } from 'src/users/entity/user.entity'
import { Message } from './model/message.entity' import { UsersService } from 'src/users/users.service'
import { Channel } from './entity/channel.entity'
import { Message } from './entity/message.entity'
import { CreateChannelDto } from './model/create-channel.dto' import { CreateChannelDto } from './dto/createChannel.dto'
@WebSocketGateway({ @WebSocketGateway({
cors: { cors: {

6
back/volume/src/chat/chat.module.ts

@ -1,12 +1,12 @@
import { Module } from '@nestjs/common' import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm' import { TypeOrmModule } from '@nestjs/typeorm'
import { AuthModule } from 'src/auth/auth.module' import { AuthModule } from 'src/auth/auth.module'
import { UsersModule } from 'src/users/users.module' import { UsersModule } from 'src/users/users.module'
import { ChatGateway } from './chat.gateway' import { ChatGateway } from './chat.gateway'
import { ChatService } from './chat.service' import { ChatService } from './chat.service'
import { UsersService } from 'src/users/users.service' import { Channel } from './entity/channel.entity'
import { Channel } from './model/channel.entity' import { Message } from './entity/message.entity'
import { Message } from './model/message.entity'
@Module({ @Module({
imports: [ imports: [

7
back/volume/src/chat/chat.service.ts

@ -1,10 +1,9 @@
import { Injectable } from '@nestjs/common' import { Injectable } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm' import { InjectRepository } from '@nestjs/typeorm'
import { Channel } from 'src/chat/model/channel.entity'
import { type User } from 'src/users/user.entity'
import { Repository } from 'typeorm' import { Repository } from 'typeorm'
import { Message } from './model/message.entity' import { type User } from 'src/users/entity/user.entity'
import { CreateChannelDto } from './model/create-channel.dto' import { Channel } from './entity/channel.entity'
import { Message } from './entity/message.entity'
@Injectable() @Injectable()
export class ChatService { export class ChatService {

0
back/volume/src/chat/model/create-channel.dto.ts → back/volume/src/chat/dto/createChannel.dto.ts

8
back/volume/src/chat/model/update-channel.dto.ts → back/volume/src/chat/dto/updateChannel.dto.ts

@ -1,7 +1,7 @@
import { PartialType } from '@nestjs/mapped-types' import { PartialType } from '@nestjs/mapped-types'
import { CreateChannelDto } from './create-channel.dto' import { CreateChannelDto } from './createChannel.dto'
import { type Message } from './message.entity' import { type Message } from '../entity/message.entity'
import { type User } from 'src/users/user.entity' import { type User } from 'src/users/entity/user.entity'
import { IsString } from 'class-validator' import { IsString } from 'class-validator'
export class UpdateChannelDto extends PartialType(CreateChannelDto) { export class UpdateChannelDto extends PartialType(CreateChannelDto) {
@ -12,7 +12,7 @@ export class UpdateChannelDto extends PartialType(CreateChannelDto) {
messages: [Message] messages: [Message]
owners: [number] // ftId owners: [number] // ftId
admins: [number] admins: [number]
banned: [number] // ftId banned: [number] // ftId

5
back/volume/src/chat/model/channel.entity.ts → back/volume/src/chat/entity/channel.entity.ts

@ -1,4 +1,3 @@
import { User } from 'src/users/user.entity'
import { import {
BeforeInsert, BeforeInsert,
Column, Column,
@ -8,9 +7,11 @@ import {
OneToMany, OneToMany,
PrimaryGeneratedColumn PrimaryGeneratedColumn
} from 'typeorm' } from 'typeorm'
import { Message } from './message.entity'
import * as bcrypt from 'bcrypt' import * as bcrypt from 'bcrypt'
import { User } from 'src/users/entity/user.entity'
import { Message } from './message.entity'
@Entity() @Entity()
export class Channel { export class Channel {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()

3
back/volume/src/chat/model/message.entity.ts → back/volume/src/chat/entity/message.entity.ts

@ -1,4 +1,3 @@
import { User } from 'src/users/user.entity'
import { import {
Column, Column,
CreateDateColumn, CreateDateColumn,
@ -8,6 +7,8 @@ import {
ManyToOne, ManyToOne,
PrimaryGeneratedColumn PrimaryGeneratedColumn
} from 'typeorm' } from 'typeorm'
import { User } from 'src/users/entity/user.entity'
import { Channel } from './channel.entity' import { Channel } from './channel.entity'
@Entity() @Entity()

25
back/volume/src/db/db.module.ts

@ -1,25 +0,0 @@
import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm'
import { ConfigModule, ConfigService } from '@nestjs/config'
import * as Joi from 'joi'
@Module({
imports: [
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
type: 'postgres',
host: configService.get<string>('POSTGRES_HOST'),
port: configService.get<number>('POSTGRES_PORT'),
username: configService.get<string>('POSTGRES_USER'),
password: configService.get<string>('POSTGRES_PASSWORD'),
database: configService.get<string>('POSTGRES_DB'),
jwt_secret: configService.get<string>('JWT_SECRET'),
autoLoadEntities: true,
synchronize: true
})
})
]
})
export class DbModule {}

3
back/volume/src/pong/pong.gateway.ts

@ -1,3 +1,4 @@
import { UsePipes, ValidationPipe } from '@nestjs/common'
import { type WebSocket } from 'ws' import { type WebSocket } from 'ws'
import { import {
ConnectedSocket, ConnectedSocket,
@ -8,11 +9,11 @@ import {
WebSocketGateway WebSocketGateway
} from '@nestjs/websockets' } from '@nestjs/websockets'
import { randomUUID } from 'crypto' import { randomUUID } from 'crypto'
import { Games } from './game/Games' import { Games } from './game/Games'
import { formatWebsocketData } from './game/utils' import { formatWebsocketData } from './game/utils'
import { GAME_EVENTS } from './game/constants' import { GAME_EVENTS } from './game/constants'
import { GameCreationDtoValidated } from './dtos/GameCreationDtoValidated' import { GameCreationDtoValidated } from './dtos/GameCreationDtoValidated'
import { UsePipes, ValidationPipe } from '@nestjs/common'
import { type Game } from './game/Game' import { type Game } from './game/Game'
import { plainToClass } from 'class-transformer' import { plainToClass } from 'class-transformer'
import { PointDtoValidated } from './dtos/PointDtoValidated' import { PointDtoValidated } from './dtos/PointDtoValidated'

7
back/volume/src/users/user.dto.ts → back/volume/src/users/dto/user.dto.ts

@ -1,9 +1,4 @@
import { import { IsString, IsNotEmpty, IsPositive, IsOptional } from 'class-validator'
IsString,
IsNotEmpty,
IsPositive,
IsOptional
} from 'class-validator'
import { ApiProperty } from '@nestjs/swagger' import { ApiProperty } from '@nestjs/swagger'
import { Express } from 'express' import { Express } from 'express'

10
back/volume/src/users/user.entity.ts → back/volume/src/users/entity/user.entity.ts

@ -7,13 +7,13 @@ import {
JoinTable JoinTable
} from 'typeorm' } from 'typeorm'
import Message from 'src/chat/model/message.entity' import Message from 'src/chat/entity/message.entity'
import Channel from 'src/chat/model/channel.entity' import Channel from 'src/chat/entity/channel.entity'
@Entity() @Entity()
export class User { export class User {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id: number; id: number
@Column({ unique: true }) @Column({ unique: true })
ftId: number ftId: number
@ -39,11 +39,11 @@ export class User {
@ManyToMany(() => User) @ManyToMany(() => User)
@JoinTable() @JoinTable()
followers: User[]; followers: User[]
@ManyToMany(() => User) @ManyToMany(() => User)
@JoinTable() @JoinTable()
friends: User[]; friends: User[]
// @Column({ default: { wr: -1, place: -1 } }) // @Column({ default: { wr: -1, place: -1 } })
// rank: { wr: number; place: number }; // rank: { wr: number; place: number };

48
back/volume/src/users/users.controller.ts

@ -16,34 +16,32 @@ import {
import { FileInterceptor } from '@nestjs/platform-express' import { FileInterceptor } from '@nestjs/platform-express'
import { diskStorage } from 'multer' import { diskStorage } from 'multer'
import { type User } from './user.entity' import { type User } from './entity/user.entity'
import { UsersService } from './users.service' import { UsersService } from './users.service'
import { UserDto, AvatarUploadDto } from './user.dto' import { UserDto, AvatarUploadDto } from './dto/user.dto'
import { AuthenticatedGuard } from 'src/auth/42-auth.guard' import { AuthenticatedGuard } from 'src/auth/42-auth.guard'
import { FtUser } from 'src/auth/42.decorator' import { FtUser } from 'src/auth/42.decorator'
import { Profile } from 'passport-42' import { Profile } from 'passport-42'
import { ApiBody, ApiConsumes } from '@nestjs/swagger' import { ApiBody, ApiConsumes } from '@nestjs/swagger'
import { Request, Response } from 'express' import { type Request, Response } from 'express'
import { createReadStream } from 'fs' import { createReadStream } from 'fs'
import { join } from 'path' import { join } from 'path'
@Controller('users') @Controller()
export class UsersController { export class UsersController {
constructor(private readonly usersService: UsersService) { } constructor (private readonly usersService: UsersService) {}
@Get() @Get()
async getAllUsers(): Promise<User[]> { async getAllUsers (): Promise<User[]> {
return await this.usersService.findUsers() return await this.usersService.findUsers()
} }
@Post() @Post()
@UseGuards(AuthenticatedGuard) @UseGuards(AuthenticatedGuard)
async create( async create (@Body() payload: UserDto, @FtUser() profile: Profile) {
@Body() payload: UserDto, const user = await this.usersService.findUser(profile.id)
@FtUser() profile: Profile) {
const user = await this.usersService.findUser(profile.id);
if (user) { if (user) {
return await this.usersService.update(user.id, payload) return await this.usersService.update(user.id, payload)
} else { } else {
@ -51,13 +49,25 @@ export class UsersController {
} }
} }
@Post("invit/:id") @Get('friends')
@UseGuards(AuthenticatedGuard)
async getFriends (@FtUser() profile: Profile) {
return await this.usersService.getFriends(profile.id)
}
@Get('invits')
@UseGuards(AuthenticatedGuard)
async getInvits (@FtUser() profile: Profile) {
return await this.usersService.getInvits(profile.id)
}
@Post('invit/:id')
@UseGuards(AuthenticatedGuard) @UseGuards(AuthenticatedGuard)
followUser( async invitUser (
@FtUser() profile: Profile, @FtUser() profile: Profile,
@Param('id', ParseIntPipe) id: number, @Param('id', ParseIntPipe) id: number
) { ) {
return this.usersService.invit(profile.id, id); return await this.usersService.invit(profile.id, id)
} }
@Post('avatar') @Post('avatar')
@ -81,16 +91,16 @@ export class UsersController {
description: 'A new avatar for the user', description: 'A new avatar for the user',
type: AvatarUploadDto type: AvatarUploadDto
}) })
async addAvatar( async addAvatar (
@FtUser() profile: Profile, @FtUser() profile: Profile,
@UploadedFile() file: Express.Multer.File @UploadedFile() file: Express.Multer.File
) { ) {
return await this.usersService.addAvatar(profile.id, file.filename) return await this.usersService.addAvatar(profile.id, file.filename)
} }
@Get('avatar') @Get('avatar')
async getAvatar( async getAvatar (
@FtUser() profile: Profile, @FtUser() profile: Profile,
@Res({ passthrough: true }) response: Response @Res({ passthrough: true }) response: Response
) { ) {
const user = await this.usersService.findUser(profile.id) const user = await this.usersService.findUser(profile.id)

2
back/volume/src/users/users.module.ts

@ -1,6 +1,6 @@
import { Module } from '@nestjs/common' import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm' import { TypeOrmModule } from '@nestjs/typeorm'
import { User } from './user.entity' import { User } from './entity/user.entity'
import { UsersController } from './users.controller' import { UsersController } from './users.controller'
import { UsersService } from './users.service' import { UsersService } from './users.service'

84
back/volume/src/users/users.service.ts

@ -1,35 +1,29 @@
import { Injectable, NotFoundException } from '@nestjs/common' import { Injectable, NotFoundException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm' import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm' import { Repository } from 'typeorm'
import { User } from './user.entity' import { User } from './entity/user.entity'
import { UserDto } from './user.dto' import { type UserDto } from './dto/user.dto'
import { type Channel } from 'src/chat/model/channel.entity' import { type Channel } from 'src/chat/entity/channel.entity'
@Injectable() @Injectable()
export class UsersService { export class UsersService {
constructor( constructor (
@InjectRepository(User) private readonly usersRepository: Repository<User> @InjectRepository(User) private readonly usersRepository: Repository<User>
) { } ) {}
async findUsers(): Promise<User[]> { async findUsers (): Promise<User[]> {
return await this.usersRepository.find({}) return await this.usersRepository.find({})
} }
async findUserByName(username: string): Promise<User | null> { async findUserByName (username: string): Promise<User | null> {
return await this.usersRepository.findOneBy({ username }) return await this.usersRepository.findOneBy({ username })
} }
async findUser(ftId: number): Promise<User | null> { async findUser (ftId: number): Promise<User | null> {
return await this.usersRepository.findOne({ return await this.usersRepository.findOneBy({ftId})
where: { ftId },
relations: {
friends: true,
followers: true,
}
});
} }
async create(userData: UserDto) { async create (userData: UserDto) {
try { try {
const newUser = this.usersRepository.create(userData) const newUser = this.usersRepository.create(userData)
return await this.usersRepository.save(newUser) return await this.usersRepository.save(newUser)
@ -38,7 +32,7 @@ export class UsersService {
} }
} }
async findOnlineInChannel(channel: Channel): Promise<User[]> { async findOnlineInChannel (channel: Channel): Promise<User[]> {
return await this.usersRepository return await this.usersRepository
.createQueryBuilder('user') .createQueryBuilder('user')
.where('user.channel = :chan', { chan: channel }) .where('user.channel = :chan', { chan: channel })
@ -46,35 +40,61 @@ export class UsersService {
.getMany() .getMany()
} }
async update(ftId: number, changes: UserDto) { async update (ftId: number, changes: UserDto) {
const updatedUser = await this.findUser(ftId) const updatedUser = await this.findUser(ftId)
this.usersRepository.merge(updatedUser, changes) this.usersRepository.merge(updatedUser, changes)
return await this.usersRepository.save(updatedUser) return await this.usersRepository.save(updatedUser)
} }
async addAvatar(ftId: number, filename: string) { async addAvatar (ftId: number, filename: string) {
return await this.usersRepository.update(ftId, { return await this.usersRepository.update(ftId, {
avatar: filename avatar: filename
}) })
} }
async invit(ftId: number, targetFtId: number) { async getFriends (ftId: number) {
const user = await this.findUser(ftId); const user = await this.usersRepository.findOne({
const target = await this.findUser(targetFtId); where: { ftId },
relations: {
friends: true,
}
})
return user.friends
}
async getInvits (ftId: number) {
const user = await this.usersRepository.findOne({
where: { ftId },
relations: {
followers: true,
}
})
return user.followers
}
async invit (ftId: number, targetFtId: number) {
const user = await this.findUser(ftId)
const target = await this.findUser(targetFtId)
if (!target) { if (!target) {
return new NotFoundException(`Error: user id ${targetFtId} isn't in our db.`) return new NotFoundException(
`Error: user id ${targetFtId} isn't in our db.`
)
} }
const id = user.followers.findIndex((follower) => follower.ftId === targetFtId) const id = user.followers.findIndex(
(follower) => follower.ftId === targetFtId
)
if (id != -1) { if (id != -1) {
console.log(`Friend relation complete between ${user.username} and ${target.username}`); console.log(
user.friends.push(target); `Friend relation complete between ${user.username} and ${target.username}`
target.friends.push(user); )
user.followers.slice(id, 1); user.friends.push(target)
this.usersRepository.save(user); target.friends.push(user)
user.followers.slice(id, 1)
this.usersRepository.save(user)
} else { } else {
console.log(`You asked ${target.username} to be your friend.`); console.log(`You asked ${target.username} to be your friend.`)
target.followers.push(user); target.followers.push(user)
} }
this.usersRepository.save(target); this.usersRepository.save(target)
} }
} }

2
docker-compose.yml

@ -41,7 +41,7 @@ services:
container_name: pgadmin container_name: pgadmin
image: dpage/pgadmin4 image: dpage/pgadmin4
ports: ports:
- "8080:80" - "8081:80"
volumes: volumes:
- /data/pgadmin:/root/.pgadmin - /data/pgadmin:/root/.pgadmin
environment: environment:

14
front/Dockerfile

@ -3,15 +3,5 @@ FROM alpine:3.15
RUN apk update && apk upgrade && apk add npm RUN apk update && apk upgrade && apk add npm
WORKDIR /var/www/html WORKDIR /var/www/html
COPY entrypoint.sh /tmp/entrypoint.sh
ENTRYPOINT npm install; \ ENTRYPOINT ["sh", "/tmp/entrypoint.sh"]
if [[ $NODE_ENV == "production" ]]; then \
npm run build && npm run preview; \
elif [[ $NODE_ENV == "development" ]]; then \
npm run dev; \
elif [[ $NODE_ENV == "debug" ]]; then \
npm run dev; \
elif [[ $NODE_ENV == "check" ]]; then \
npm run format && npm run check; echo "=== FINISH ==="\
else echo "Nothing to do for that NODE_ENV context."; \
fi;

18
front/entrypoint.sh

@ -0,0 +1,18 @@
npm install;
cat >.env <<EOF
VITE_FRONT_FPS=$FRONT_FPS
VITE_HOST=$HOST
VITE_BACK_PORT=$BACK_PORT
EOF
npm install;
if [[ $NODE_ENV == "production" ]]; then
npm run build && npm run preview;
elif [[ $NODE_ENV == "development" ]]; then
npm run dev;
elif [[ $NODE_ENV == "debug" ]]; then
npm run dev;
elif [[ $NODE_ENV == "check" ]]; then
npm run format && npm run check; echo "=== FINISH ==="
else echo "Nothing to do for that NODE_ENV context.";
fi;

12
front/volume/package-lock.json

@ -436,9 +436,9 @@
"integrity": "sha512-pYrtLtOwku/7r1i9AMONsJMVYAtk3hzOfiGNekhtq5tYBGA7unMve8RvUclKLMT3PrihvJqUmzsRGh0RP84hKg==" "integrity": "sha512-pYrtLtOwku/7r1i9AMONsJMVYAtk3hzOfiGNekhtq5tYBGA7unMve8RvUclKLMT3PrihvJqUmzsRGh0RP84hKg=="
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "18.14.0", "version": "18.14.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.5.tgz",
"integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==", "integrity": "sha512-CRT4tMK/DHYhw1fcCEBwME9CSaZNclxfzVMe7GsO6ULSwsttbj70wSiX6rZdIjGblu93sTJxLdhNIT85KKI7Qw==",
"devOptional": true "devOptional": true
}, },
"node_modules/@types/pug": { "node_modules/@types/pug": {
@ -1652,9 +1652,9 @@
"integrity": "sha512-pYrtLtOwku/7r1i9AMONsJMVYAtk3hzOfiGNekhtq5tYBGA7unMve8RvUclKLMT3PrihvJqUmzsRGh0RP84hKg==" "integrity": "sha512-pYrtLtOwku/7r1i9AMONsJMVYAtk3hzOfiGNekhtq5tYBGA7unMve8RvUclKLMT3PrihvJqUmzsRGh0RP84hKg=="
}, },
"@types/node": { "@types/node": {
"version": "18.14.0", "version": "18.14.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.5.tgz",
"integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==", "integrity": "sha512-CRT4tMK/DHYhw1fcCEBwME9CSaZNclxfzVMe7GsO6ULSwsttbj70wSiX6rZdIjGblu93sTJxLdhNIT85KKI7Qw==",
"devOptional": true "devOptional": true
}, },
"@types/pug": { "@types/pug": {

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

@ -8,8 +8,10 @@
import { onMount } from "svelte"; import { onMount } from "svelte";
import type { StringDto } from "./dtos/StringDto"; import type { StringDto } from "./dtos/StringDto";
const FPS = 144; const FPS = import.meta.env.VITE_FRONT_FPS;
const SERVER_URL = "ws://localhost:3001"; const SERVER_URL = `ws://${import.meta.env.VITE_HOST}:${
import.meta.env.VITE_BACK_PORT
}`;
let gameCanvas: HTMLCanvasElement; let gameCanvas: HTMLCanvasElement;
let connected: boolean = false; let connected: boolean = false;

5
front/volume/src/global.d.ts

@ -0,0 +1,5 @@
interface ImportMetaEnv {
VITE_HOST: string;
VITE_BACK_PORT: string;
VITE_FRONT_FPS: number;
}
Loading…
Cancel
Save