Browse Source

configuration and routes rework

master
nicolas-arnaud 2 years ago
parent
commit
f1d4b54d0c
  1. 16
      .env_sample
  2. 14
      README.md
  3. 2
      back/entrypoint.sh
  4. 27
      back/volume/src/app.controller.ts
  5. 31
      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. 6
      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. 34
      back/volume/src/users/users.controller.ts
  20. 2
      back/volume/src/users/users.module.ts
  21. 64
      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_PORT: 5432
POSTGRES_USER: postgres_usr
POSTGRES_PASSWORD: postgres_pw
POSTGRES_DB: transcendence
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_USER=postgres_usr
POSTGRES_PASSWORD=postgres_pw
POSTGRES_DB=transcendence
PGADMIN_DEFAULT_EMAIL=admin@pg.com
PGADMIN_DEFAULT_PASSWORD=admin
FRONT_FPS=144
HOST=localhost
FRONT_PORT=80
BACK_PORT=3001
HASH_SALT=10
@ -15,4 +19,4 @@ JWT_EXPIRATION_TIME=900
FT_OAUTH_CLIENT_ID=
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:
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:

2
back/entrypoint.sh

@ -6,6 +6,8 @@ POSTGRES_USER= $POSTGRES_USER
POSTGRES_PASSWORD=$POSTGRES_PASSWORD
POSTGRES_DB=$POSTGRES_DB
HOST=$HOST
FRONT_PORT=$FRONT_PORT
BACK_PORT=$BACK_PORT
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]
}
}

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

@ -1,11 +1,10 @@
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 { AppController } from './app.controller'
import { AuthModule } from './auth/auth.module'
import { ChatModule } from './chat/chat.module'
import { DbModule } from './db/db.module'
import { PongModule } from './pong/pong.module'
import { UsersModule } from './users/users.module'
@ -18,17 +17,33 @@ import { UsersModule } from './users/users.module'
POSTGRES_USER: Joi.string().required(),
POSTGRES_PASSWORD: Joi.string().required(),
POSTGRES_DB: Joi.string().required(),
BACK_PORT: Joi.number(),
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,
ChatModule,
DbModule,
PongModule,
UsersModule
],
controllers: [AppController]
]
})
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 { PassportStrategy } from '@nestjs/passport'
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 { createWriteStream } from 'fs'
import { UsersService } from 'src/users/users.service'
import { User } from 'src/users/entity/user.entity'
@Injectable()
export class FtStrategy extends PassportStrategy(Strategy, '42') {
constructor (

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

@ -1,16 +1,19 @@
import { Controller, Get, Redirect, UseGuards, Res, Req } from '@nestjs/common'
import { FtOauthGuard } from './42-auth.guard'
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 {
@Get('42')
@Get('in')
@UseGuards(FtOauthGuard)
ftAuth () {}
@Get('42/return')
@Get('inReturn')
@UseGuards(FtOauthGuard)
@Redirect('http://localhost:80/')
@Redirect('http://' + process.env.HOST + ':' + process.env.FRONT_PORT + '/')
ftAuthCallback (
@Res({ passthrough: true }) response: Response,
@Req() request: Request
@ -18,4 +21,18 @@ export class AuthController {
console.log('cookie:', 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 {
type OnGatewayConnection,
type OnGatewayDisconnect,
@ -7,14 +8,14 @@ import {
WebSocketServer
} from '@nestjs/websockets'
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 { Channel } from './model/channel.entity'
import { Message } from './model/message.entity'
import { type User } from 'src/users/entity/user.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({
cors: {

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

@ -1,12 +1,12 @@
import { Module } from '@nestjs/common'
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 { UsersService } from 'src/users/users.service'
import { Channel } from './model/channel.entity'
import { Message } from './model/message.entity'
import { Channel } from './entity/channel.entity'
import { Message } from './entity/message.entity'
@Module({
imports: [

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

@ -1,10 +1,9 @@
import { Injectable } from '@nestjs/common'
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 { Message } from './model/message.entity'
import { CreateChannelDto } from './model/create-channel.dto'
import { type User } from 'src/users/entity/user.entity'
import { Channel } from './entity/channel.entity'
import { Message } from './entity/message.entity'
@Injectable()
export class ChatService {

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

6
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 { CreateChannelDto } from './create-channel.dto'
import { type Message } from './message.entity'
import { type User } from 'src/users/user.entity'
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) {

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 {
BeforeInsert,
Column,
@ -8,9 +7,11 @@ import {
OneToMany,
PrimaryGeneratedColumn
} from 'typeorm'
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 {
@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 {
Column,
CreateDateColumn,
@ -8,6 +7,8 @@ import {
ManyToOne,
PrimaryGeneratedColumn
} from 'typeorm'
import { User } from 'src/users/entity/user.entity'
import { Channel } from './channel.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 {
ConnectedSocket,
@ -8,11 +9,11 @@ import {
WebSocketGateway
} from '@nestjs/websockets'
import { randomUUID } from 'crypto'
import { Games } from './game/Games'
import { formatWebsocketData } from './game/utils'
import { GAME_EVENTS } from './game/constants'
import { GameCreationDtoValidated } from './dtos/GameCreationDtoValidated'
import { UsePipes, ValidationPipe } from '@nestjs/common'
import { type Game } from './game/Game'
import { plainToClass } from 'class-transformer'
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 {
IsString,
IsNotEmpty,
IsPositive,
IsOptional
} from 'class-validator'
import { IsString, IsNotEmpty, IsPositive, IsOptional } from 'class-validator'
import { ApiProperty } from '@nestjs/swagger'
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
} from 'typeorm'
import Message from 'src/chat/model/message.entity'
import Channel from 'src/chat/model/channel.entity'
import Message from 'src/chat/entity/message.entity'
import Channel from 'src/chat/entity/channel.entity'
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
id: number
@Column({ unique: true })
ftId: number
@ -39,11 +39,11 @@ export class User {
@ManyToMany(() => User)
@JoinTable()
followers: User[];
followers: User[]
@ManyToMany(() => User)
@JoinTable()
friends: User[];
friends: User[]
// @Column({ default: { wr: -1, place: -1 } })
// rank: { wr: number; place: number };

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

@ -16,20 +16,20 @@ import {
import { FileInterceptor } from '@nestjs/platform-express'
import { diskStorage } from 'multer'
import { type User } from './user.entity'
import { type User } from './entity/user.entity'
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 { FtUser } from 'src/auth/42.decorator'
import { Profile } from 'passport-42'
import { ApiBody, ApiConsumes } from '@nestjs/swagger'
import { Request, Response } from 'express'
import { type Request, Response } from 'express'
import { createReadStream } from 'fs'
import { join } from 'path'
@Controller('users')
@Controller()
export class UsersController {
constructor (private readonly usersService: UsersService) {}
@ -40,10 +40,8 @@ export class UsersController {
@Post()
@UseGuards(AuthenticatedGuard)
async create(
@Body() payload: UserDto,
@FtUser() profile: Profile) {
const user = await this.usersService.findUser(profile.id);
async create (@Body() payload: UserDto, @FtUser() profile: Profile) {
const user = await this.usersService.findUser(profile.id)
if (user) {
return await this.usersService.update(user.id, payload)
} 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)
followUser(
async invitUser (
@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')

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

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

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

@ -1,9 +1,9 @@
import { Injectable, NotFoundException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { User } from './user.entity'
import { UserDto } from './user.dto'
import { type Channel } from 'src/chat/model/channel.entity'
import { User } from './entity/user.entity'
import { type UserDto } from './dto/user.dto'
import { type Channel } from 'src/chat/entity/channel.entity'
@Injectable()
export class UsersService {
@ -20,13 +20,7 @@ export class UsersService {
}
async findUser (ftId: number): Promise<User | null> {
return await this.usersRepository.findOne({
where: { ftId },
relations: {
friends: true,
followers: true,
}
});
return await this.usersRepository.findOneBy({ftId})
}
async create (userData: UserDto) {
@ -58,23 +52,49 @@ export class UsersService {
})
}
async getFriends (ftId: number) {
const user = await this.usersRepository.findOne({
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);
const user = await this.findUser(ftId)
const target = await this.findUser(targetFtId)
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) {
console.log(`Friend relation complete between ${user.username} and ${target.username}`);
user.friends.push(target);
target.friends.push(user);
user.followers.slice(id, 1);
this.usersRepository.save(user);
console.log(
`Friend relation complete between ${user.username} and ${target.username}`
)
user.friends.push(target)
target.friends.push(user)
user.followers.slice(id, 1)
this.usersRepository.save(user)
} else {
console.log(`You asked ${target.username} to be your friend.`);
target.followers.push(user);
console.log(`You asked ${target.username} to be your friend.`)
target.followers.push(user)
}
this.usersRepository.save(target);
this.usersRepository.save(target)
}
}

2
docker-compose.yml

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

14
front/Dockerfile

@ -3,15 +3,5 @@ FROM alpine:3.15
RUN apk update && apk upgrade && apk add npm
WORKDIR /var/www/html
ENTRYPOINT 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;
COPY entrypoint.sh /tmp/entrypoint.sh
ENTRYPOINT ["sh", "/tmp/entrypoint.sh"]

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

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

@ -8,8 +8,10 @@
import { onMount } from "svelte";
import type { StringDto } from "./dtos/StringDto";
const FPS = 144;
const SERVER_URL = "ws://localhost:3001";
const FPS = import.meta.env.VITE_FRONT_FPS;
const SERVER_URL = `ws://${import.meta.env.VITE_HOST}:${
import.meta.env.VITE_BACK_PORT
}`;
let gameCanvas: HTMLCanvasElement;
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