traintrape-moi/server/src/trains/trains.service.ts

112 lines
4.8 KiB
TypeScript

import { ConflictException, HttpException, Injectable, NotFoundException, UnprocessableEntityException } from '@nestjs/common'
import { CreateTrainDto } from './dto/create-train.dto'
import { UpdateTrainDto } from './dto/update-train.dto'
import { PrismaService } from 'src/prisma/prisma.service'
import { MoneyUpdateType, Player, TrainTrip } from '@prisma/client'
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
import { paginate } from 'src/common/utils/pagination.utils'
import { ImportTrainDto } from './dto/import-train.dto'
import { InterrailJourney, InterrailLegInfo, InterrailTravelInfo } from './dto/interrail-api.dto'
import { distanceCoordinates } from 'src/common/utils/calculus.utils'
import { PlayerFilterDto } from 'src/common/dto/player_filter.dto'
@Injectable()
export class TrainsService {
constructor(private prisma: PrismaService) { }
async create(createTrainDto: CreateTrainDto): Promise<TrainTrip> {
return await this.prisma.trainTrip.create({ data: createTrainDto })
}
async findAll(queryPagination: QueryPaginationDto, playerFilter: PlayerFilterDto): Promise<[TrainTrip[], number]> {
return [
await this.prisma.trainTrip.findMany({
where: playerFilter,
...paginate(queryPagination),
}),
await this.prisma.trainTrip.count({
where: playerFilter,
}),
]
}
async findOne(id: string): Promise<TrainTrip> {
return await this.prisma.trainTrip.findUnique({
where: { id },
})
}
async update(id: string, updateTrainDto: UpdateTrainDto): Promise<TrainTrip> {
if (!this.findOne(id))
throw new NotFoundException(`Le train à modifier n'existe pas avec l'identifiant ${id}`)
return await this.prisma.trainTrip.update({
where: { id },
data: updateTrainDto,
})
}
async remove(id: string): Promise<TrainTrip> {
if (!this.findOne(id))
throw new NotFoundException(`Le train à supprimer n'existe pas avec l'identifiant ${id}`)
return await this.prisma.trainTrip.delete({
where: { id },
})
}
async import(player: Player, { id: trainId }: ImportTrainDto): Promise<TrainTrip> {
if (this.findOne(trainId))
throw new ConflictException(`Le train avec l'identifiant ${trainId} est déjà importé`)
const interrailResult: InterrailJourney = await fetch(`https://3uiwjsimnh.execute-api.eu-central-1.amazonaws.com/Prod/journey-import?id=${trainId}`)
.then(data => data.json())
if (interrailResult.data.travels.length !== 1)
throw new UnprocessableEntityException(`Ce voyage contient ${interrailResult.data.travels.length} trajets. Merci d'ajouter les trajets un à un.`)
const travel = interrailResult.data.travels[0]
if (travel.legs.length !== 1)
throw new UnprocessableEntityException(`Ce trajet contient ${travel.legs.length} trains. Merci d'ajouter les trajets un à un.`)
const leg = travel.legs[0]
const travelInfoJson: InterrailTravelInfo = JSON.parse(travel.infoJson)
const departure = new Date(`${travelInfoJson.date.year}-${travelInfoJson.date.month.toString().padStart(2, "0")}-${travelInfoJson.date.day.toString().padStart(2, "0")}` +
`T${travelInfoJson.departureTime.hours.toString().padStart(2, "0")}:${travelInfoJson.departureTime.minutes.toString().padStart(2, "0")}:00+0100`)
departure.setDate(departure.getDate() + travelInfoJson.departureTime.offset)
const arrival = new Date(`${travelInfoJson.date.year}-${travelInfoJson.date.month.toString().padStart(2, "0")}-${travelInfoJson.date.day.toString().padStart(2, "0")}` +
`T${travelInfoJson.arrivalTime.hours.toString().padStart(2, "0")}:${travelInfoJson.arrivalTime.minutes.toString().padStart(2, "0")}:00+0100`)
arrival.setDate(arrival.getDate() + travelInfoJson.arrivalTime.offset)
const legInfoJson: InterrailLegInfo = JSON.parse(leg.infoJson)
const distance = legInfoJson.trainStopStations
.map(trainStopStation => trainStopStation.coordinates)
.reduce((distance, coordinates, index) => {
if (index === 0)
return distance
const oldCoordinates = legInfoJson.trainStopStations.at(index - 1).coordinates
return distance + distanceCoordinates({ from: oldCoordinates, to: coordinates })
}, 0)
const cost = 10 * 10 * Math.ceil(distance / 1000)
const train = await this.prisma.trainTrip.create({
data: {
id: trainId,
playerId: player.id,
distance: distance,
from: travel.from,
to: travel.to,
departureTime: departure,
arrivalTime: arrival,
infoJson: leg.infoJson,
},
})
// Ajout du trajet en points
await this.prisma.moneyUpdate.create({
data: {
playerId: player.id,
amount: -cost,
reason: MoneyUpdateType.BUY_TRAIN,
tripId: train.id,
}
})
return train
}
}