User => Player

This commit is contained in:
Emmy D'Anello 2024-12-08 13:41:37 +01:00
parent c6da328023
commit 65576fc5b1
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
39 changed files with 193 additions and 240 deletions

View File

@ -1,14 +0,0 @@
/*
Warnings:
- Added the required column `accuracy` to the `Geolocation` table without a default value. This is not possible if the table is not empty.
- Added the required column `altitude` to the `Geolocation` table without a default value. This is not possible if the table is not empty.
- Added the required column `altitudeAccuracy` to the `Geolocation` table without a default value. This is not possible if the table is not empty.
- Added the required column `speed` to the `Geolocation` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "Geolocation" ADD COLUMN "accuracy" DOUBLE PRECISION NOT NULL,
ADD COLUMN "altitude" DOUBLE PRECISION NOT NULL,
ADD COLUMN "altitudeAccuracy" DOUBLE PRECISION NOT NULL,
ADD COLUMN "speed" DOUBLE PRECISION NOT NULL;

View File

@ -1,5 +0,0 @@
-- AlterTable
ALTER TABLE "ChallengeAction" ADD COLUMN "end" TIMESTAMP(3),
ADD COLUMN "penaltyEnd" TIMESTAMP(3),
ADD COLUMN "penaltyStart" TIMESTAMP(3),
ADD COLUMN "start" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;

View File

@ -1,12 +0,0 @@
-- AlterTable
ALTER TABLE "ChallengeAction" ALTER COLUMN "end" SET DATA TYPE TIMESTAMPTZ(3),
ALTER COLUMN "penaltyEnd" SET DATA TYPE TIMESTAMPTZ(3),
ALTER COLUMN "penaltyStart" SET DATA TYPE TIMESTAMPTZ(3),
ALTER COLUMN "start" SET DATA TYPE TIMESTAMPTZ(3);
-- AlterTable
ALTER TABLE "Geolocation" ALTER COLUMN "timestamp" SET DATA TYPE TIMESTAMPTZ(3);
-- AlterTable
ALTER TABLE "TrainTrip" ALTER COLUMN "departureTime" SET DATA TYPE TIMESTAMPTZ(3),
ALTER COLUMN "arrivalTime" SET DATA TYPE TIMESTAMPTZ(3);

View File

@ -1,8 +0,0 @@
/*
Warnings:
- You are about to drop the column `geometry` on the `TrainTrip` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "TrainTrip" DROP COLUMN "geometry";

View File

@ -1,13 +0,0 @@
/*
Warnings:
- You are about to drop the column `after` on the `MoneyUpdate` table. All the data in the column will be lost.
- You are about to drop the column `before` on the `MoneyUpdate` table. All the data in the column will be lost.
- Added the required column `amount` to the `MoneyUpdate` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "MoneyUpdate" DROP COLUMN "after",
DROP COLUMN "before",
ADD COLUMN "amount" INTEGER NOT NULL,
ADD COLUMN "timestamp" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;

View File

@ -2,23 +2,27 @@
CREATE TYPE "MoneyUpdateType" AS ENUM ('START', 'WIN_CHALLENGE', 'BUY_TRAIN'); CREATE TYPE "MoneyUpdateType" AS ENUM ('START', 'WIN_CHALLENGE', 'BUY_TRAIN');
-- CreateTable -- CreateTable
CREATE TABLE "User" ( CREATE TABLE "Player" (
"id" SERIAL NOT NULL, "id" SERIAL NOT NULL,
"name" TEXT NOT NULL, "name" TEXT NOT NULL,
"password" TEXT NOT NULL, "password" TEXT NOT NULL,
"money" INTEGER NOT NULL DEFAULT 0, "money" INTEGER NOT NULL DEFAULT 0,
"currentRunner" BOOLEAN NOT NULL DEFAULT false, "currentRunner" BOOLEAN NOT NULL DEFAULT false,
CONSTRAINT "User_pkey" PRIMARY KEY ("id") CONSTRAINT "Player_pkey" PRIMARY KEY ("id")
); );
-- CreateTable -- CreateTable
CREATE TABLE "Geolocation" ( CREATE TABLE "Geolocation" (
"id" SERIAL NOT NULL, "id" SERIAL NOT NULL,
"userId" INTEGER NOT NULL, "playerId" INTEGER NOT NULL,
"longitude" DOUBLE PRECISION NOT NULL, "longitude" DOUBLE PRECISION NOT NULL,
"latitude" DOUBLE PRECISION NOT NULL, "latitude" DOUBLE PRECISION NOT NULL,
"timestamp" TIMESTAMP(3) NOT NULL, "speed" DOUBLE PRECISION NOT NULL,
"accuracy" DOUBLE PRECISION NOT NULL,
"altitude" DOUBLE PRECISION NOT NULL,
"altitudeAccuracy" DOUBLE PRECISION NOT NULL,
"timestamp" TIMESTAMPTZ(3) NOT NULL,
CONSTRAINT "Geolocation_pkey" PRIMARY KEY ("id") CONSTRAINT "Geolocation_pkey" PRIMARY KEY ("id")
); );
@ -36,10 +40,14 @@ CREATE TABLE "Challenge" (
-- CreateTable -- CreateTable
CREATE TABLE "ChallengeAction" ( CREATE TABLE "ChallengeAction" (
"id" SERIAL NOT NULL, "id" SERIAL NOT NULL,
"userId" INTEGER NOT NULL, "playerId" INTEGER NOT NULL,
"challengeId" INTEGER NOT NULL, "challengeId" INTEGER NOT NULL,
"active" BOOLEAN NOT NULL DEFAULT false, "active" BOOLEAN NOT NULL DEFAULT false,
"success" BOOLEAN NOT NULL DEFAULT false, "success" BOOLEAN NOT NULL DEFAULT false,
"start" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"end" TIMESTAMPTZ(3),
"penaltyStart" TIMESTAMPTZ(3),
"penaltyEnd" TIMESTAMPTZ(3),
CONSTRAINT "ChallengeAction_pkey" PRIMARY KEY ("id") CONSTRAINT "ChallengeAction_pkey" PRIMARY KEY ("id")
); );
@ -47,14 +55,13 @@ CREATE TABLE "ChallengeAction" (
-- CreateTable -- CreateTable
CREATE TABLE "TrainTrip" ( CREATE TABLE "TrainTrip" (
"id" TEXT NOT NULL, "id" TEXT NOT NULL,
"userId" INTEGER NOT NULL, "playerId" INTEGER NOT NULL,
"distance" DOUBLE PRECISION NOT NULL, "distance" DOUBLE PRECISION NOT NULL,
"from" TEXT NOT NULL, "from" TEXT NOT NULL,
"to" TEXT NOT NULL, "to" TEXT NOT NULL,
"departureTime" TIMESTAMP(3) NOT NULL, "departureTime" TIMESTAMPTZ(3) NOT NULL,
"arrivalTime" TIMESTAMP(3) NOT NULL, "arrivalTime" TIMESTAMPTZ(3) NOT NULL,
"infoJson" JSONB NOT NULL, "infoJson" JSONB NOT NULL,
"geometry" TEXT NOT NULL,
CONSTRAINT "TrainTrip_pkey" PRIMARY KEY ("id") CONSTRAINT "TrainTrip_pkey" PRIMARY KEY ("id")
); );
@ -62,18 +69,18 @@ CREATE TABLE "TrainTrip" (
-- CreateTable -- CreateTable
CREATE TABLE "MoneyUpdate" ( CREATE TABLE "MoneyUpdate" (
"id" SERIAL NOT NULL, "id" SERIAL NOT NULL,
"userId" INTEGER NOT NULL, "playerId" INTEGER NOT NULL,
"before" INTEGER NOT NULL, "amount" INTEGER NOT NULL,
"after" INTEGER NOT NULL,
"reason" "MoneyUpdateType" NOT NULL, "reason" "MoneyUpdateType" NOT NULL,
"actionId" INTEGER, "actionId" INTEGER,
"tripId" TEXT, "tripId" TEXT,
"timestamp" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "MoneyUpdate_pkey" PRIMARY KEY ("id") CONSTRAINT "MoneyUpdate_pkey" PRIMARY KEY ("id")
); );
-- CreateIndex -- CreateIndex
CREATE UNIQUE INDEX "User_name_key" ON "User"("name"); CREATE UNIQUE INDEX "Player_name_key" ON "Player"("name");
-- CreateIndex -- CreateIndex
CREATE UNIQUE INDEX "Challenge_title_key" ON "Challenge"("title"); CREATE UNIQUE INDEX "Challenge_title_key" ON "Challenge"("title");
@ -88,22 +95,22 @@ CREATE UNIQUE INDEX "MoneyUpdate_actionId_key" ON "MoneyUpdate"("actionId");
CREATE UNIQUE INDEX "MoneyUpdate_tripId_key" ON "MoneyUpdate"("tripId"); CREATE UNIQUE INDEX "MoneyUpdate_tripId_key" ON "MoneyUpdate"("tripId");
-- AddForeignKey -- AddForeignKey
ALTER TABLE "Geolocation" ADD CONSTRAINT "Geolocation_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE "Geolocation" ADD CONSTRAINT "Geolocation_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ChallengeAction" ADD CONSTRAINT "ChallengeAction_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE "ChallengeAction" ADD CONSTRAINT "ChallengeAction_challengeId_fkey" FOREIGN KEY ("challengeId") REFERENCES "Challenge"("id") ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE "ChallengeAction" ADD CONSTRAINT "ChallengeAction_challengeId_fkey" FOREIGN KEY ("challengeId") REFERENCES "Challenge"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE "ChallengeAction" ADD CONSTRAINT "ChallengeAction_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE "TrainTrip" ADD CONSTRAINT "TrainTrip_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE "TrainTrip" ADD CONSTRAINT "TrainTrip_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE "MoneyUpdate" ADD CONSTRAINT "MoneyUpdate_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "Player"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE "MoneyUpdate" ADD CONSTRAINT "MoneyUpdate_actionId_fkey" FOREIGN KEY ("actionId") REFERENCES "ChallengeAction"("id") ON DELETE SET NULL ON UPDATE CASCADE; ALTER TABLE "MoneyUpdate" ADD CONSTRAINT "MoneyUpdate_actionId_fkey" FOREIGN KEY ("actionId") REFERENCES "ChallengeAction"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE "MoneyUpdate" ADD CONSTRAINT "MoneyUpdate_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "TrainTrip"("id") ON DELETE SET NULL ON UPDATE CASCADE; ALTER TABLE "MoneyUpdate" ADD CONSTRAINT "MoneyUpdate_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "TrainTrip"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "MoneyUpdate" ADD CONSTRAINT "MoneyUpdate_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -7,7 +7,7 @@ datasource db {
url = env("DATABASE_URL") url = env("DATABASE_URL")
} }
model User { model Player {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
name String @unique name String @unique
password String password String
@ -21,8 +21,8 @@ model User {
model Geolocation { model Geolocation {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id]) player Player @relation(fields: [playerId], references: [id])
userId Int playerId Int
longitude Float longitude Float
latitude Float latitude Float
speed Float speed Float
@ -42,8 +42,8 @@ model Challenge {
model ChallengeAction { model ChallengeAction {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id]) player Player @relation(fields: [playerId], references: [id])
userId Int playerId Int
challenge Challenge @relation(fields: [challengeId], references: [id]) challenge Challenge @relation(fields: [challengeId], references: [id])
challengeId Int @unique challengeId Int @unique
active Boolean @default(false) active Boolean @default(false)
@ -57,8 +57,8 @@ model ChallengeAction {
model TrainTrip { model TrainTrip {
id String @id id String @id
user User @relation(fields: [userId], references: [id]) player Player @relation(fields: [playerId], references: [id])
userId Int playerId Int
distance Float distance Float
from String from String
to String to String
@ -70,8 +70,8 @@ model TrainTrip {
model MoneyUpdate { model MoneyUpdate {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id]) player Player @relation(fields: [playerId], references: [id])
userId Int playerId Int
amount Int amount Int
reason MoneyUpdateType reason MoneyUpdateType
action ChallengeAction? @relation(fields: [actionId], references: [id]) action ChallengeAction? @relation(fields: [actionId], references: [id])

View File

@ -5,14 +5,14 @@ const prisma = new PrismaClient()
async function main() { async function main() {
const emmyPassword = await bcrypt.hash("Emmy", 10) const emmyPassword = await bcrypt.hash("Emmy", 10)
const emmy = await prisma.user.upsert({ const emmy = await prisma.player.upsert({
where: { id: 1 }, where: { id: 1 },
update: { name: 'Emmy' }, update: { name: 'Emmy' },
create: { name: 'Emmy', password: emmyPassword }, create: { name: 'Emmy', password: emmyPassword },
}) })
const taminaPassword = await bcrypt.hash("Tamina", 10) const taminaPassword = await bcrypt.hash("Tamina", 10)
const tamina = await prisma.user.upsert({ const tamina = await prisma.player.upsert({
where: { id: 2 }, where: { id: 2 },
update: { name: 'Tamina' }, update: { name: 'Tamina' },
create: { name: 'Tamina', password: taminaPassword }, create: { name: 'Tamina', password: taminaPassword },

View File

@ -1,7 +1,7 @@
import { Module } from '@nestjs/common' import { Module } from '@nestjs/common'
import { PrismaService } from './prisma/prisma.service' import { PrismaService } from './prisma/prisma.service'
import { PrismaModule } from './prisma/prisma.module' import { PrismaModule } from './prisma/prisma.module'
import { UsersModule } from './users/users.module' import { PlayersModule } from './players/players.module'
import { AuthModule } from './auth/auth.module' import { AuthModule } from './auth/auth.module'
import { GeolocationsModule } from './geolocations/geolocations.module' import { GeolocationsModule } from './geolocations/geolocations.module'
import { ChallengesModule } from './challenges/challenges.module' import { ChallengesModule } from './challenges/challenges.module'
@ -10,7 +10,7 @@ import { TrainsModule } from './trains/trains.module'
import { MoneyUpdatesModule } from './money-updates/money-updates.module' import { MoneyUpdatesModule } from './money-updates/money-updates.module'
@Module({ @Module({
imports: [PrismaModule, UsersModule, AuthModule, GeolocationsModule, ChallengesModule, ChallengeActionsModule, TrainsModule, MoneyUpdatesModule], imports: [PrismaModule, PlayersModule, AuthModule, GeolocationsModule, ChallengesModule, ChallengeActionsModule, TrainsModule, MoneyUpdatesModule],
providers: [PrismaService], providers: [PrismaService],
}) })
export class AppModule {} export class AppModule {}

View File

@ -5,7 +5,7 @@ import { PrismaModule } from 'src/prisma/prisma.module'
import { PassportModule } from '@nestjs/passport' import { PassportModule } from '@nestjs/passport'
import { JwtModule } from '@nestjs/jwt' import { JwtModule } from '@nestjs/jwt'
import { env } from 'process' import { env } from 'process'
import { UsersModule } from 'src/users/users.module' import { PlayersModule } from 'src/players/players.module'
import { JwtStrategy } from './jwt.strategy' import { JwtStrategy } from './jwt.strategy'
export const JWT_SECRET = env.JWT_SECRET export const JWT_SECRET = env.JWT_SECRET
@ -18,7 +18,7 @@ export const JWT_SECRET = env.JWT_SECRET
secret: JWT_SECRET, secret: JWT_SECRET,
signOptions: { expiresIn: '12h' }, signOptions: { expiresIn: '12h' },
}), }),
UsersModule, PlayersModule,
], ],
controllers: [AuthController], controllers: [AuthController],
providers: [AuthService, JwtStrategy], providers: [AuthService, JwtStrategy],

View File

@ -9,17 +9,17 @@ export class AuthService {
constructor(private prisma: PrismaService, private jwtService: JwtService) {} constructor(private prisma: PrismaService, private jwtService: JwtService) {}
async login(name: string, password: string): Promise<AuthEntity> { async login(name: string, password: string): Promise<AuthEntity> {
const user = await this.prisma.user.findUnique({ where: { name: name } }) const player = await this.prisma.player.findUnique({ where: { name: name } })
if (!user) { if (!player) {
throw new NotFoundException(`Aucun⋅e utilisateur⋅rice avec pour nom ${name}`) throw new NotFoundException(`Aucun⋅e joueur⋅se avec pour nom ${name}`)
} }
const isPasswordValid = await bcrypt.compare(password, user.password) const isPasswordValid = await bcrypt.compare(password, player.password)
if (!isPasswordValid) { if (!isPasswordValid) {
throw new UnauthorizedException('Mot de passe incorrect') throw new UnauthorizedException('Mot de passe incorrect')
} }
return { return {
accessToken: this.jwtService.sign({ userId: user.id }), accessToken: this.jwtService.sign({ playerId: player.id }),
} }
} }
} }

View File

@ -1,9 +1,9 @@
import { Injectable } from '@nestjs/common' import { Injectable } from '@nestjs/common'
import { AuthGuard } from '@nestjs/passport' import { AuthGuard } from '@nestjs/passport'
import { User } from '@prisma/client' import { Player } from '@prisma/client'
import { Request } from 'express' import { Request } from 'express'
@Injectable() @Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {} export class JwtAuthGuard extends AuthGuard('jwt') {}
export type AuthenticatedRequest = Request & { user: User } export type AuthenticatedRequest = Request & { user: Player }

View File

@ -2,23 +2,24 @@ import { Injectable, UnauthorizedException } from '@nestjs/common'
import { PassportStrategy } from '@nestjs/passport' import { PassportStrategy } from '@nestjs/passport'
import { ExtractJwt, Strategy } from 'passport-jwt' import { ExtractJwt, Strategy } from 'passport-jwt'
import { JWT_SECRET } from './auth.module' import { JWT_SECRET } from './auth.module'
import { UsersService } from 'src/users/users.service' import { PlayersService } from 'src/players/players.service'
import { User } from '@prisma/client' import { Player } from '@prisma/client'
@Injectable() @Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor(private usersService: UsersService) { constructor(private playersService: PlayersService) {
super({ super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: JWT_SECRET, secretOrKey: JWT_SECRET,
}) })
} }
async validate(payload: { userId: number }): Promise<User> { async validate(payload: { playerId: number }): Promise<Player> {
const user = await this.usersService.findOne(payload.userId) console.log(payload)
if (!user) { const player = await this.playersService.findOne(payload.playerId)
if (!player) {
throw new UnauthorizedException() throw new UnauthorizedException()
} }
return user return player
} }
} }

View File

@ -23,8 +23,7 @@ export class ChallengeActionsController {
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" }) @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
@ApiForbiddenResponse({ description: "Permission refusée" }) @ApiForbiddenResponse({ description: "Permission refusée" })
async create(@Req() request: AuthenticatedRequest, @Body() createChallengeActionDto: CreateChallengeActionDto): Promise<ChallengeActionEntity> { async create(@Req() request: AuthenticatedRequest, @Body() createChallengeActionDto: CreateChallengeActionDto): Promise<ChallengeActionEntity> {
const user = request.user const challenge = await this.challengeActionsService.create(request.user, createChallengeActionDto)
const challenge = await this.challengeActionsService.create(user, createChallengeActionDto)
return new ChallengeActionEntity(challenge) return new ChallengeActionEntity(challenge)
} }

View File

@ -1,7 +1,7 @@
import { Injectable, NotAcceptableException } from '@nestjs/common' import { Injectable, NotAcceptableException } from '@nestjs/common'
import { CreateChallengeActionDto } from './dto/create-challenge-action.dto' import { CreateChallengeActionDto } from './dto/create-challenge-action.dto'
import { UpdateChallengeActionDto } from './dto/update-challenge-action.dto' import { UpdateChallengeActionDto } from './dto/update-challenge-action.dto'
import { ChallengeAction, User } from '@prisma/client' import { ChallengeAction, Player } from '@prisma/client'
import { PrismaService } from 'src/prisma/prisma.service' import { PrismaService } from 'src/prisma/prisma.service'
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { paginate } from 'src/common/utils/pagination.utils' import { paginate } from 'src/common/utils/pagination.utils'
@ -11,8 +11,8 @@ import { FilterChallengeActionsDto } from './dto/filter-challenge-action.dto'
export class ChallengeActionsService { export class ChallengeActionsService {
constructor(private prisma: PrismaService) { } constructor(private prisma: PrismaService) { }
async create(authenticatedUser: User, createChallengeActionDto: CreateChallengeActionDto): Promise<ChallengeAction> { async create(authenticatedPlayer: Player, createChallengeActionDto: CreateChallengeActionDto): Promise<ChallengeAction> {
const data = { ...createChallengeActionDto, userId: authenticatedUser.id } const data = { ...createChallengeActionDto, playerId: authenticatedPlayer.id }
return await this.prisma.challengeAction.create({ return await this.prisma.challengeAction.create({
data: data, data: data,
}) })
@ -49,10 +49,10 @@ export class ChallengeActionsService {
}) })
} }
async endCurrentChallenge(user: User, success: boolean): Promise<ChallengeAction> { async endCurrentChallenge(player: Player, success: boolean): Promise<ChallengeAction> {
const challengeAction = await this.prisma.challengeAction.findFirst({ const challengeAction = await this.prisma.challengeAction.findFirst({
where: { where: {
userId: user.id, playerId: player.id,
active: true, active: true,
} }
}) })

View File

@ -7,8 +7,8 @@ export class FilterChallengeActionsDto {
@IsOptional() @IsOptional()
@IsInt() @IsInt()
@Type(() => Number) @Type(() => Number)
@ApiProperty({ description: "Identifiant de l'utilisateur⋅rice qui effectue le défi", required: false }) @ApiProperty({ description: "Identifiant de læ joueur⋅se qui effectue le défi", required: false })
userId?: number playerId?: number
@IsOptional() @IsOptional()
@IsInt() @IsInt()

View File

@ -10,8 +10,8 @@ export class ChallengeActionEntity implements ChallengeAction {
@ApiProperty({ description: "Identifiant unique" }) @ApiProperty({ description: "Identifiant unique" })
id: number id: number
@ApiProperty({ description: "Identifiant de l'utilisateur⋅rice effectuant le défi" }) @ApiProperty({ description: "Identifiant de læ joueur⋅se effectuant le défi" })
userId: number playerId: number
@ApiProperty({ description: "Identifiant du défi rattaché à l'action" }) @ApiProperty({ description: "Identifiant du défi rattaché à l'action" })
challengeId: number challengeId: number

View File

@ -1,7 +1,7 @@
import { Injectable, NotAcceptableException, NotFoundException } from '@nestjs/common' import { Injectable, NotAcceptableException, NotFoundException } from '@nestjs/common'
import { CreateChallengeDto } from './dto/create-challenge.dto' import { CreateChallengeDto } from './dto/create-challenge.dto'
import { UpdateChallengeDto } from './dto/update-challenge.dto' import { UpdateChallengeDto } from './dto/update-challenge.dto'
import { Challenge, User } from '@prisma/client' import { Challenge, Player } from '@prisma/client'
import { PrismaService } from 'src/prisma/prisma.service' import { PrismaService } from 'src/prisma/prisma.service'
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { paginate } from 'src/common/utils/pagination.utils' import { paginate } from 'src/common/utils/pagination.utils'
@ -56,10 +56,10 @@ export class ChallengesService {
}) })
} }
async drawRandom(user: User): Promise<ChallengeEntity> { async drawRandom(player: Player): Promise<ChallengeEntity> {
const currentChallengeAction = await this.prisma.challengeAction.findFirst({ const currentChallengeAction = await this.prisma.challengeAction.findFirst({
where: { where: {
userId: user.id, playerId: player.id,
active: true, active: true,
} }
}) })
@ -82,7 +82,7 @@ export class ChallengesService {
const challengeEntity: ChallengeEntity = new ChallengeEntity(challenge) const challengeEntity: ChallengeEntity = new ChallengeEntity(challenge)
const action = await this.prisma.challengeAction.create({ const action = await this.prisma.challengeAction.create({
data: { data: {
userId: user.id, playerId: player.id,
challengeId: challenge.id, challengeId: challenge.id,
active: true, active: true,
success: false, success: false,

View File

@ -1,9 +1,9 @@
import { Type } from "class-transformer" import { Type } from "class-transformer"
import { IsNumber, IsOptional } from "class-validator" import { IsNumber, IsOptional } from "class-validator"
export class UserFilterDto { export class PlayerFilterDto {
@IsOptional() @IsOptional()
@IsNumber() @IsNumber()
@Type(() => Number) @Type(() => Number)
userId?: number playerId?: number
} }

View File

@ -9,8 +9,8 @@ export class GeolocationEntity implements Geolocation {
@ApiProperty({description: "Identifiant unique"}) @ApiProperty({description: "Identifiant unique"})
id: number id: number
@ApiProperty({description: "Utilisateur⋅rice ayant émis la géolocalisation"}) @ApiProperty({description: "Joueur⋅se ayant émis la géolocalisation"})
userId: number playerId: number
@ApiProperty({description: "Longitude en degrés"}) @ApiProperty({description: "Longitude en degrés"})
longitude: number longitude: number

View File

@ -7,7 +7,7 @@ import { GeolocationEntity } from './entities/geolocation.entity'
import { ApiOkResponsePaginated, paginateOutput } from 'src/common/utils/pagination.utils' import { ApiOkResponsePaginated, paginateOutput } from 'src/common/utils/pagination.utils'
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { PaginateOutputDto } from 'src/common/dto/pagination-output.dto' import { PaginateOutputDto } from 'src/common/dto/pagination-output.dto'
import { UserFilterDto } from 'src/common/dto/user_filter.dto' import { PlayerFilterDto } from 'src/common/dto/player_filter.dto'
@Controller('geolocations') @Controller('geolocations')
export class GeolocationsController { export class GeolocationsController {
@ -21,8 +21,7 @@ export class GeolocationsController {
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" }) @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
@ApiForbiddenResponse({ description: "Permission refusée" }) @ApiForbiddenResponse({ description: "Permission refusée" })
async create(@Req() request: AuthenticatedRequest, @Body() createGeolocationDto: CreateGeolocationDto): Promise<GeolocationEntity> { async create(@Req() request: AuthenticatedRequest, @Body() createGeolocationDto: CreateGeolocationDto): Promise<GeolocationEntity> {
const user = request.user const geolocation = await this.geolocationsService.create(request.user, createGeolocationDto)
const geolocation = await this.geolocationsService.create(user, createGeolocationDto)
return new GeolocationEntity(geolocation) return new GeolocationEntity(geolocation)
} }
@ -32,8 +31,8 @@ export class GeolocationsController {
@ApiOkResponsePaginated(GeolocationEntity) @ApiOkResponsePaginated(GeolocationEntity)
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" }) @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
@ApiForbiddenResponse({ description: "Permission refusée" }) @ApiForbiddenResponse({ description: "Permission refusée" })
async findAll(@Query() queryPagination?: QueryPaginationDto, @Query() userFilter?: UserFilterDto): Promise<PaginateOutputDto<GeolocationEntity>> { async findAll(@Query() queryPagination?: QueryPaginationDto, @Query() playerFilter?: PlayerFilterDto): Promise<PaginateOutputDto<GeolocationEntity>> {
const [geolocations, total] = await this.geolocationsService.findAll(queryPagination, userFilter) const [geolocations, total] = await this.geolocationsService.findAll(queryPagination, playerFilter)
return paginateOutput<GeolocationEntity>(geolocations.map(geolocation => new GeolocationEntity(geolocation)), total, queryPagination) return paginateOutput<GeolocationEntity>(geolocations.map(geolocation => new GeolocationEntity(geolocation)), total, queryPagination)
} }
@ -51,17 +50,17 @@ export class GeolocationsController {
return new GeolocationEntity(geolocation) return new GeolocationEntity(geolocation)
} }
@Get('/last-location/:userId') @Get('/last-location/:playerId')
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@ApiBearerAuth() @ApiBearerAuth()
@ApiOkResponse({ type: GeolocationEntity }) @ApiOkResponse({ type: GeolocationEntity })
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" }) @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
@ApiForbiddenResponse({ description: "Permission refusée" }) @ApiForbiddenResponse({ description: "Permission refusée" })
@ApiNotFoundResponse({ description: "Aucune localisation trouvée" }) @ApiNotFoundResponse({ description: "Aucune localisation trouvée" })
async findLastLocation(@Param('userId', ParseIntPipe) userId: number): Promise<GeolocationEntity> { async findLastLocation(@Param('playerId', ParseIntPipe) playerId: number): Promise<GeolocationEntity> {
const geolocation = await this.geolocationsService.findLastLocation(userId) const geolocation = await this.geolocationsService.findLastLocation(playerId)
if (!geolocation) if (!geolocation)
throw new NotFoundException(`Géolocalisation inexistante pour l'utilisateur⋅rice ${userId}`) throw new NotFoundException(`Géolocalisation inexistante pour læ joueur⋅se ${playerId}`)
return new GeolocationEntity(geolocation) return new GeolocationEntity(geolocation)
} }

View File

@ -1,23 +1,23 @@
import { Injectable } from '@nestjs/common' import { Injectable } from '@nestjs/common'
import { CreateGeolocationDto } from './dto/create-geolocation.dto' import { CreateGeolocationDto } from './dto/create-geolocation.dto'
import { PrismaService } from 'src/prisma/prisma.service' import { PrismaService } from 'src/prisma/prisma.service'
import { Geolocation, Prisma, User } from '@prisma/client' import { Geolocation, Player, Prisma } from '@prisma/client'
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { paginate } from 'src/common/utils/pagination.utils' import { paginate } from 'src/common/utils/pagination.utils'
import { UserFilterDto } from 'src/common/dto/user_filter.dto' import { PlayerFilterDto } from 'src/common/dto/player_filter.dto'
@Injectable() @Injectable()
export class GeolocationsService { export class GeolocationsService {
constructor(private prisma: PrismaService) { } constructor(private prisma: PrismaService) { }
async create(authenticatedUser: User, createGeolocationDto: CreateGeolocationDto): Promise<Geolocation> { async create(authenticatedPlayer: Player, createGeolocationDto: CreateGeolocationDto): Promise<Geolocation> {
const data = { ...createGeolocationDto, userId: authenticatedUser.id } const data = { ...createGeolocationDto, playerId: authenticatedPlayer.id }
return await this.prisma.geolocation.create({ data: data }) return await this.prisma.geolocation.create({ data: data })
} }
async findAll(queryPagination?: QueryPaginationDto, userFilter?: UserFilterDto): Promise<[Geolocation[], number]> { async findAll(queryPagination?: QueryPaginationDto, playerFilter?: PlayerFilterDto): Promise<[Geolocation[], number]> {
const filter = { const filter = {
where: (userFilter?.userId ? { userId: userFilter.userId } : {}), where: (playerFilter?.playerId ? { playerId: playerFilter.playerId } : {}),
orderBy: { timestamp: Prisma.SortOrder.desc }, orderBy: { timestamp: Prisma.SortOrder.desc },
} }
return [ return [
@ -33,9 +33,9 @@ export class GeolocationsService {
return await this.prisma.geolocation.findUnique({ where: { id } }) return await this.prisma.geolocation.findUnique({ where: { id } })
} }
async findLastLocation(userId: number): Promise<Geolocation> { async findLastLocation(playerId: number): Promise<Geolocation> {
return await this.prisma.geolocation.findFirst({ return await this.prisma.geolocation.findFirst({
where: { userId: userId }, where: { playerId: playerId },
orderBy: { timestamp: Prisma.SortOrder.desc }, orderBy: { timestamp: Prisma.SortOrder.desc },
take: 1 take: 1
}) })

View File

@ -9,8 +9,8 @@ export class MoneyUpdateEntity implements MoneyUpdate {
@ApiProperty({ description: "Identifiant unique de la mise à jour de solde" }) @ApiProperty({ description: "Identifiant unique de la mise à jour de solde" })
id: number id: number
@ApiProperty({ description: "Utilisateur⋅rice concerné⋅e par la mise à jour de solde" }) @ApiProperty({ description: "Joueur⋅se concerné⋅e par la mise à jour de solde" })
userId: number playerId: number
@ApiProperty({ description: "Montant de la modification du solde" }) @ApiProperty({ description: "Montant de la modification du solde" })
amount: number amount: number

View File

@ -7,7 +7,7 @@ import { ApiBearerAuth, ApiCreatedResponse, ApiForbiddenResponse, ApiNotFoundRes
import { MoneyUpdateEntity } from './entities/money-update.entity' import { MoneyUpdateEntity } from './entities/money-update.entity'
import { ApiOkResponsePaginated, paginateOutput } from 'src/common/utils/pagination.utils' import { ApiOkResponsePaginated, paginateOutput } from 'src/common/utils/pagination.utils'
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { UserFilterDto } from 'src/common/dto/user_filter.dto' import { PlayerFilterDto } from 'src/common/dto/player_filter.dto'
import { PaginateOutputDto } from 'src/common/dto/pagination-output.dto' import { PaginateOutputDto } from 'src/common/dto/pagination-output.dto'
@Controller('money-updates') @Controller('money-updates')
@ -32,8 +32,8 @@ export class MoneyUpdatesController {
@ApiOkResponsePaginated(MoneyUpdateEntity) @ApiOkResponsePaginated(MoneyUpdateEntity)
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" }) @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
@ApiForbiddenResponse({ description: "Permission refusée" }) @ApiForbiddenResponse({ description: "Permission refusée" })
async findAll(@Query() queryPagination: QueryPaginationDto, @Query() userFilter: UserFilterDto): Promise<PaginateOutputDto<MoneyUpdateEntity>> { async findAll(@Query() queryPagination: QueryPaginationDto, @Query() playerFilter: PlayerFilterDto): Promise<PaginateOutputDto<MoneyUpdateEntity>> {
const [trains, total] = await this.moneyUpdatesService.findAll(queryPagination, userFilter) const [trains, total] = await this.moneyUpdatesService.findAll(queryPagination, playerFilter)
return paginateOutput<MoneyUpdateEntity>(trains.map(train => new MoneyUpdateEntity(train)), total, queryPagination) return paginateOutput<MoneyUpdateEntity>(trains.map(train => new MoneyUpdateEntity(train)), total, queryPagination)
} }

View File

@ -2,32 +2,32 @@ import { Injectable } from '@nestjs/common'
import { CreateMoneyUpdateDto } from './dto/create-money-update.dto' import { CreateMoneyUpdateDto } from './dto/create-money-update.dto'
import { UpdateMoneyUpdateDto } from './dto/update-money-update.dto' import { UpdateMoneyUpdateDto } from './dto/update-money-update.dto'
import { PrismaService } from 'src/prisma/prisma.service' import { PrismaService } from 'src/prisma/prisma.service'
import { MoneyUpdate, User } from '@prisma/client' import { MoneyUpdate, Player } from '@prisma/client'
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { UserFilterDto } from 'src/common/dto/user_filter.dto' import { PlayerFilterDto } from 'src/common/dto/player_filter.dto'
import { paginate } from 'src/common/utils/pagination.utils' import { paginate } from 'src/common/utils/pagination.utils'
@Injectable() @Injectable()
export class MoneyUpdatesService { export class MoneyUpdatesService {
constructor(private prisma: PrismaService) { } constructor(private prisma: PrismaService) { }
async create(user: User, createMoneyUpdateDto: CreateMoneyUpdateDto): Promise<MoneyUpdate> { async create(player: Player, createMoneyUpdateDto: CreateMoneyUpdateDto): Promise<MoneyUpdate> {
return await this.prisma.moneyUpdate.create({ return await this.prisma.moneyUpdate.create({
data: { data: {
...createMoneyUpdateDto, ...createMoneyUpdateDto,
userId: user.id, playerId: player.id,
} }
}) })
} }
async findAll(queryPagination: QueryPaginationDto, userFilter: UserFilterDto): Promise<[MoneyUpdate[], number]> { async findAll(queryPagination: QueryPaginationDto, playerFilter: PlayerFilterDto): Promise<[MoneyUpdate[], number]> {
return [ return [
await this.prisma.moneyUpdate.findMany({ await this.prisma.moneyUpdate.findMany({
where: userFilter, where: playerFilter,
...paginate(queryPagination), ...paginate(queryPagination),
}), }),
await this.prisma.moneyUpdate.count({ await this.prisma.moneyUpdate.count({
where: userFilter, where: playerFilter,
}), }),
] ]
} }

View File

@ -1,9 +1,9 @@
import { ApiProperty } from "@nestjs/swagger" import { ApiProperty } from "@nestjs/swagger"
import { User } from "@prisma/client" import { Player } from "@prisma/client"
import { Exclude } from 'class-transformer' import { Exclude } from 'class-transformer'
export class UserEntity implements User { export class PlayerEntity implements Player {
constructor(partial: Partial<UserEntity>) { constructor(partial: Partial<PlayerEntity>) {
Object.assign(this, partial) Object.assign(this, partial)
} }

View File

@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing'
import { PlayersController } from './players.controller'
import { PlayersService } from './players.service'
describe('PlayersController', () => {
let controller: PlayersController
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [PlayersController],
providers: [PlayersService],
}).compile()
controller = module.get<PlayersController>(PlayersController)
})
it('should be defined', () => {
expect(controller).toBeDefined()
})
})

View File

@ -1,40 +1,40 @@
import { Body, Controller, Get, HttpCode, NotFoundException, Param, ParseIntPipe, Patch, Query, Req, UseGuards } from '@nestjs/common' import { Body, Controller, Get, HttpCode, NotFoundException, Param, ParseIntPipe, Patch, Query, Req, UseGuards } from '@nestjs/common'
import { UsersService } from './users.service' import { PlayersService } from './players.service'
import { ApiBadRequestResponse, ApiBearerAuth, ApiForbiddenResponse, ApiNoContentResponse, ApiNotFoundResponse, ApiOkResponse, ApiUnauthorizedResponse } from '@nestjs/swagger' import { ApiBadRequestResponse, ApiBearerAuth, ApiForbiddenResponse, ApiNoContentResponse, ApiNotFoundResponse, ApiOkResponse, ApiUnauthorizedResponse } from '@nestjs/swagger'
import { UserEntity } from './entities/user.entity' import { PlayerEntity } from './entities/player.entity'
import { AuthenticatedRequest, JwtAuthGuard } from 'src/auth/jwt-auth.guard' import { AuthenticatedRequest, JwtAuthGuard } from 'src/auth/jwt-auth.guard'
import { UpdatePasswordDto } from './dto/user_password.dto' import { UpdatePasswordDto } from './dto/player_password.dto'
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { ApiOkResponsePaginated, paginateOutput } from 'src/common/utils/pagination.utils' import { ApiOkResponsePaginated, paginateOutput } from 'src/common/utils/pagination.utils'
import { PaginateOutputDto } from 'src/common/dto/pagination-output.dto' import { PaginateOutputDto } from 'src/common/dto/pagination-output.dto'
@Controller('users') @Controller('players')
export class UsersController { export class PlayersController {
constructor(private readonly usersService: UsersService) {} constructor(private readonly playersService: PlayersService) {}
@Get() @Get()
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@ApiBearerAuth() @ApiBearerAuth()
@ApiOkResponsePaginated(UserEntity) @ApiOkResponsePaginated(PlayerEntity)
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" }) @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
@ApiForbiddenResponse({ description: "Permission refusée" }) @ApiForbiddenResponse({ description: "Permission refusée" })
async findAll(@Query() queryPagination?: QueryPaginationDto): Promise<PaginateOutputDto<UserEntity>> { async findAll(@Query() queryPagination?: QueryPaginationDto): Promise<PaginateOutputDto<PlayerEntity>> {
const [users, total] = await this.usersService.findAll(queryPagination) const [players, total] = await this.playersService.findAll(queryPagination)
return paginateOutput<UserEntity>(users.map(user => new UserEntity(user)), total, queryPagination) return paginateOutput<PlayerEntity>(players.map(player => new PlayerEntity(player)), total, queryPagination)
} }
@Get(':id') @Get(':id')
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@ApiBearerAuth() @ApiBearerAuth()
@ApiOkResponse({ type: UserEntity }) @ApiOkResponse({ type: PlayerEntity })
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" }) @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
@ApiForbiddenResponse({ description: "Permission refusée" }) @ApiForbiddenResponse({ description: "Permission refusée" })
@ApiNotFoundResponse({ description: "Utilisateur⋅rice non trouvé⋅e" }) @ApiNotFoundResponse({ description: "Joueur⋅se non trouvé⋅e" })
async findOne(@Param('id', ParseIntPipe) id: number) { async findOne(@Param('id', ParseIntPipe) id: number) {
const user = await this.usersService.findOne(id) const player = await this.playersService.findOne(id)
if (!user) if (!player)
throw new NotFoundException(`L'utilisateur⋅rice avec l'identifiant ${id} n'existe pas`) throw new NotFoundException(`Læ joueur⋅se avec l'identifiant ${id} n'existe pas`)
return new UserEntity(user) return new PlayerEntity(player)
} }
@Patch('/update-password') @Patch('/update-password')
@ -46,7 +46,6 @@ export class UsersController {
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" }) @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
@ApiForbiddenResponse({ description: "Permission refusée" }) @ApiForbiddenResponse({ description: "Permission refusée" })
async updatePassword(@Req() request: AuthenticatedRequest, @Body() body: UpdatePasswordDto) { async updatePassword(@Req() request: AuthenticatedRequest, @Body() body: UpdatePasswordDto) {
const user = request.user await this.playersService.updatePassword(request.user, body)
await this.usersService.updatePassword(user, body)
} }
} }

View File

@ -0,0 +1,12 @@
import { Module } from '@nestjs/common'
import { PlayersService } from './players.service'
import { PlayersController } from './players.controller'
import { PrismaModule } from 'src/prisma/prisma.module'
@Module({
controllers: [PlayersController],
providers: [PlayersService],
imports: [PrismaModule],
exports: [PlayersService],
})
export class PlayersModule {}

View File

@ -1,15 +1,15 @@
import { Test, TestingModule } from '@nestjs/testing' import { Test, TestingModule } from '@nestjs/testing'
import { UsersService } from './users.service' import { PlayersService } from './players.service'
describe('UsersService', () => { describe('PlayersService', () => {
let service: UsersService let service: PlayersService
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
providers: [UsersService], providers: [PlayersService],
}).compile() }).compile()
service = module.get<UsersService>(UsersService) service = module.get<PlayersService>(PlayersService)
}) })
it('should be defined', () => { it('should be defined', () => {

View File

@ -1,29 +1,29 @@
import { Injectable } from '@nestjs/common' import { Injectable } from '@nestjs/common'
import { User } from '@prisma/client' import { Player } from '@prisma/client'
import { PrismaService } from 'src/prisma/prisma.service' import { PrismaService } from 'src/prisma/prisma.service'
import * as bcrypt from 'bcrypt' import * as bcrypt from 'bcrypt'
import { UpdatePasswordDto } from './dto/user_password.dto' import { UpdatePasswordDto } from './dto/player_password.dto'
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { paginate } from 'src/common/utils/pagination.utils' import { paginate } from 'src/common/utils/pagination.utils'
@Injectable() @Injectable()
export class UsersService { export class PlayersService {
constructor(private prisma: PrismaService) {} constructor(private prisma: PrismaService) {}
async findAll(queryPagination?: QueryPaginationDto): Promise<[User[], number]> { async findAll(queryPagination?: QueryPaginationDto): Promise<[Player[], number]> {
return [ return [
await this.prisma.user.findMany({ ...paginate(queryPagination) }), await this.prisma.player.findMany({ ...paginate(queryPagination) }),
await this.prisma.user.count() await this.prisma.player.count()
] ]
} }
async findOne(id: number): Promise<User> { async findOne(id: number): Promise<Player> {
return await this.prisma.user.findUnique({ where: { id } }) return await this.prisma.player.findUnique({ where: { id: id } })
} }
async updatePassword(user: User, { password }: UpdatePasswordDto): Promise<void> { async updatePassword(user: Player, { password }: UpdatePasswordDto): Promise<void> {
const hashedPassword = await bcrypt.hash(password, 10) const hashedPassword = await bcrypt.hash(password, 10)
await this.prisma.user.update({ await this.prisma.player.update({
where: { id: user.id }, where: { id: user.id },
data: { password: hashedPassword } data: { password: hashedPassword }
}) })

View File

@ -1,19 +1,19 @@
import { Injectable } from '@nestjs/common' import { Injectable } from '@nestjs/common'
import { PrismaClient, } from '@prisma/client' import { PrismaClient, } from '@prisma/client'
async function updateUserMoney(prisma: PrismaClient): Promise<void> { async function updatePlayerMoney(prisma: PrismaClient): Promise<void> {
// On calcule le solde par utilisateur⋅rice pour mettre à jour l'objet User // On calcule le solde par joueur⋅se pour mettre à jour l'objet Player
const moneyPerUser = await prisma.moneyUpdate.groupBy({ const moneyPerPlayer = await prisma.moneyUpdate.groupBy({
by: 'userId', by: 'playerId',
_sum: { _sum: {
amount: true, amount: true,
} }
}) })
for (const { userId, _sum } of moneyPerUser) { for (const { playerId, _sum } of moneyPerPlayer) {
const { amount } = _sum const { amount } = _sum
await prisma.user.update({ await prisma.player.update({
where: { where: {
id: userId, id: playerId,
}, },
data: { data: {
money: amount money: amount
@ -21,7 +21,7 @@ async function updateUserMoney(prisma: PrismaClient): Promise<void> {
}) })
} }
// On réinitialise le solde s'il n'y a plus aucun MoneyUpdate // On réinitialise le solde s'il n'y a plus aucun MoneyUpdate
await prisma.user.updateMany({ await prisma.player.updateMany({
where: { where: {
moneyUpdates: { none: {} } moneyUpdates: { none: {} }
}, },
@ -39,7 +39,7 @@ function extendPrismaClient() {
$allOperations({ model, operation, args, query }) { $allOperations({ model, operation, args, query }) {
const result = query(args) const result = query(args)
if (!operation.startsWith("find") && !['aggregate', 'count', 'groupBy'].includes(operation)) if (!operation.startsWith("find") && !['aggregate', 'count', 'groupBy'].includes(operation))
result.then(() => updateUserMoney(prisma)) result.then(() => updatePlayerMoney(prisma))
return result return result
} }
} }

View File

@ -10,8 +10,8 @@ export class CreateTrainDto {
@IsInt() @IsInt()
@Type(() => Number) @Type(() => Number)
@ApiProperty({ description: "Identifiant de l'utilisateur⋅rice effectuant le trajet" }) @ApiProperty({ description: "Identifiant de læ joueur⋅se effectuant le trajet" })
userId: number playerId: number
@IsNumber() @IsNumber()
@Type(() => Number) @Type(() => Number)

View File

@ -10,8 +10,8 @@ export class TrainEntity implements TrainTrip {
@ApiProperty({ description: "Identifiant du train, donné par l'identifiant de partage Interrail" }) @ApiProperty({ description: "Identifiant du train, donné par l'identifiant de partage Interrail" })
id: string id: string
@ApiProperty({ description: "Identifiant de l'utilisateur⋅rice effectuant le trajet" }) @ApiProperty({ description: "Identifiant de læ joueur⋅se effectuant le trajet" })
userId: number playerId: number
@ApiProperty({ description: "Distance estimée en mètres du trajet" }) @ApiProperty({ description: "Distance estimée en mètres du trajet" })
distance: number distance: number

View File

@ -9,7 +9,7 @@ import { ApiOkResponsePaginated, paginateOutput } from 'src/common/utils/paginat
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { PaginateOutputDto } from 'src/common/dto/pagination-output.dto' import { PaginateOutputDto } from 'src/common/dto/pagination-output.dto'
import { ImportTrainDto } from './dto/import-train.dto' import { ImportTrainDto } from './dto/import-train.dto'
import { UserFilterDto } from 'src/common/dto/user_filter.dto' import { PlayerFilterDto } from 'src/common/dto/player_filter.dto'
@Controller('trains') @Controller('trains')
export class TrainsController { export class TrainsController {
@ -33,8 +33,8 @@ export class TrainsController {
@ApiOkResponsePaginated(TrainEntity) @ApiOkResponsePaginated(TrainEntity)
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" }) @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
@ApiForbiddenResponse({ description: "Permission refusée" }) @ApiForbiddenResponse({ description: "Permission refusée" })
async findAll(@Query() queryPagination: QueryPaginationDto, @Query() userFilter: UserFilterDto): Promise<PaginateOutputDto<TrainEntity>> { async findAll(@Query() queryPagination: QueryPaginationDto, @Query() playerFilter: PlayerFilterDto): Promise<PaginateOutputDto<TrainEntity>> {
const [trains, total] = await this.trainsService.findAll(queryPagination, userFilter) const [trains, total] = await this.trainsService.findAll(queryPagination, playerFilter)
return paginateOutput<TrainEntity>(trains.map(train => new TrainEntity(train)), total, queryPagination) return paginateOutput<TrainEntity>(trains.map(train => new TrainEntity(train)), total, queryPagination)
} }

View File

@ -2,13 +2,13 @@ import { Injectable, NotAcceptableException } from '@nestjs/common'
import { CreateTrainDto } from './dto/create-train.dto' import { CreateTrainDto } from './dto/create-train.dto'
import { UpdateTrainDto } from './dto/update-train.dto' import { UpdateTrainDto } from './dto/update-train.dto'
import { PrismaService } from 'src/prisma/prisma.service' import { PrismaService } from 'src/prisma/prisma.service'
import { TrainTrip, User } from '@prisma/client' import { Player, TrainTrip } from '@prisma/client'
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto' import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { paginate } from 'src/common/utils/pagination.utils' import { paginate } from 'src/common/utils/pagination.utils'
import { ImportTrainDto } from './dto/import-train.dto' import { ImportTrainDto } from './dto/import-train.dto'
import { InterrailJourney, InterrailLegInfo, InterrailTravelInfo } from './dto/interrail-api.dto' import { InterrailJourney, InterrailLegInfo, InterrailTravelInfo } from './dto/interrail-api.dto'
import { distanceCoordinates } from 'src/common/utils/calculus.utils' import { distanceCoordinates } from 'src/common/utils/calculus.utils'
import { UserFilterDto } from 'src/common/dto/user_filter.dto' import { PlayerFilterDto } from 'src/common/dto/player_filter.dto'
@Injectable() @Injectable()
export class TrainsService { export class TrainsService {
@ -18,14 +18,14 @@ export class TrainsService {
return await this.prisma.trainTrip.create({ data: createTrainDto }) return await this.prisma.trainTrip.create({ data: createTrainDto })
} }
async findAll(queryPagination: QueryPaginationDto, userFilter: UserFilterDto): Promise<[TrainTrip[], number]> { async findAll(queryPagination: QueryPaginationDto, playerFilter: PlayerFilterDto): Promise<[TrainTrip[], number]> {
return [ return [
await this.prisma.trainTrip.findMany({ await this.prisma.trainTrip.findMany({
where: userFilter, where: playerFilter,
...paginate(queryPagination), ...paginate(queryPagination),
}), }),
await this.prisma.trainTrip.count({ await this.prisma.trainTrip.count({
where: userFilter, where: playerFilter,
}), }),
] ]
} }
@ -49,7 +49,7 @@ export class TrainsService {
}) })
} }
async import(user: User, { id: trainId }: ImportTrainDto): Promise<TrainTrip> { async import(player: Player, { id: trainId }: ImportTrainDto): Promise<TrainTrip> {
const interrailResult: InterrailJourney = await fetch(`https://3uiwjsimnh.execute-api.eu-central-1.amazonaws.com/Prod/journey-import?id=${trainId}`) const interrailResult: InterrailJourney = await fetch(`https://3uiwjsimnh.execute-api.eu-central-1.amazonaws.com/Prod/journey-import?id=${trainId}`)
.then(data => data.json()) .then(data => data.json())
if (interrailResult.data.travels.length !== 1) if (interrailResult.data.travels.length !== 1)
@ -83,7 +83,7 @@ export class TrainsService {
}, },
create: { create: {
id: trainId, id: trainId,
userId: user.id, playerId: player.id,
distance: distance, distance: distance,
from: travel.from, from: travel.from,
to: travel.to, to: travel.to,
@ -92,7 +92,7 @@ export class TrainsService {
infoJson: leg.infoJson, infoJson: leg.infoJson,
}, },
update: { update: {
userId: user.id, playerId: player.id,
distance: distance, distance: distance,
from: travel.from, from: travel.from,
to: travel.to, to: travel.to,

View File

@ -1,20 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing'
import { UsersController } from './users.controller'
import { UsersService } from './users.service'
describe('UsersController', () => {
let controller: UsersController
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [UsersController],
providers: [UsersService],
}).compile()
controller = module.get<UsersController>(UsersController)
})
it('should be defined', () => {
expect(controller).toBeDefined()
})
})

View File

@ -1,12 +0,0 @@
import { Module } from '@nestjs/common'
import { UsersService } from './users.service'
import { UsersController } from './users.controller'
import { PrismaModule } from 'src/prisma/prisma.module'
@Module({
controllers: [UsersController],
providers: [UsersService],
imports: [PrismaModule],
exports: [UsersService],
})
export class UsersModule {}