Ajout endpoint géolocalisation
This commit is contained in:
		@@ -0,0 +1,14 @@
 | 
			
		||||
/*
 | 
			
		||||
  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;
 | 
			
		||||
@@ -20,12 +20,16 @@ model User {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model Geolocation {
 | 
			
		||||
  id        Int      @id @default(autoincrement())
 | 
			
		||||
  userId    Int
 | 
			
		||||
  longitude Float
 | 
			
		||||
  latitude  Float
 | 
			
		||||
  timestamp DateTime
 | 
			
		||||
  user      User     @relation(fields: [userId], references: [id])
 | 
			
		||||
  id               Int      @id @default(autoincrement())
 | 
			
		||||
  user             User     @relation(fields: [userId], references: [id])
 | 
			
		||||
  userId           Int
 | 
			
		||||
  longitude        Float
 | 
			
		||||
  latitude         Float
 | 
			
		||||
  speed            Float
 | 
			
		||||
  accuracy         Float
 | 
			
		||||
  altitude         Float
 | 
			
		||||
  altitudeAccuracy Float
 | 
			
		||||
  timestamp        DateTime
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model Challenge {
 | 
			
		||||
@@ -38,17 +42,18 @@ model Challenge {
 | 
			
		||||
 | 
			
		||||
model ChallengeAction {
 | 
			
		||||
  id          Int          @id @default(autoincrement())
 | 
			
		||||
  user        User         @relation(fields: [userId], references: [id])
 | 
			
		||||
  userId      Int
 | 
			
		||||
  challenge   Challenge    @relation(fields: [challengeId], references: [id])
 | 
			
		||||
  challengeId Int          @unique
 | 
			
		||||
  active      Boolean      @default(false)
 | 
			
		||||
  success     Boolean      @default(false)
 | 
			
		||||
  challenge   Challenge    @relation(fields: [challengeId], references: [id])
 | 
			
		||||
  user        User         @relation(fields: [userId], references: [id])
 | 
			
		||||
  moneyUpdate MoneyUpdate?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model TrainTrip {
 | 
			
		||||
  id            String       @id
 | 
			
		||||
  user          User         @relation(fields: [userId], references: [id])
 | 
			
		||||
  userId        Int
 | 
			
		||||
  distance      Float
 | 
			
		||||
  from          String
 | 
			
		||||
@@ -58,20 +63,19 @@ model TrainTrip {
 | 
			
		||||
  infoJson      Json
 | 
			
		||||
  geometry      String
 | 
			
		||||
  moneyUpdate   MoneyUpdate?
 | 
			
		||||
  user          User         @relation(fields: [userId], references: [id])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model MoneyUpdate {
 | 
			
		||||
  id       Int              @id @default(autoincrement())
 | 
			
		||||
  user     User             @relation(fields: [userId], references: [id])
 | 
			
		||||
  userId   Int
 | 
			
		||||
  before   Int
 | 
			
		||||
  after    Int
 | 
			
		||||
  reason   MoneyUpdateType
 | 
			
		||||
  actionId Int?             @unique
 | 
			
		||||
  tripId   String?          @unique
 | 
			
		||||
  action   ChallengeAction? @relation(fields: [actionId], references: [id])
 | 
			
		||||
  actionId Int?             @unique
 | 
			
		||||
  trip     TrainTrip?       @relation(fields: [tripId], references: [id])
 | 
			
		||||
  user     User             @relation(fields: [userId], references: [id])
 | 
			
		||||
  tripId   String?          @unique
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum MoneyUpdateType {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,10 @@ import { PrismaService } from './prisma/prisma.service'
 | 
			
		||||
import { PrismaModule } from './prisma/prisma.module'
 | 
			
		||||
import { UsersModule } from './users/users.module'
 | 
			
		||||
import { AuthModule } from './auth/auth.module'
 | 
			
		||||
import { GeolocationsModule } from './geolocations/geolocations.module'
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
  imports: [PrismaModule, UsersModule, AuthModule],
 | 
			
		||||
  imports: [PrismaModule, UsersModule, AuthModule, GeolocationsModule],
 | 
			
		||||
  providers: [PrismaService],
 | 
			
		||||
})
 | 
			
		||||
export class AppModule {}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,9 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common'
 | 
			
		||||
import { AuthGuard } from '@nestjs/passport'
 | 
			
		||||
import { User } from '@prisma/client'
 | 
			
		||||
import { Request } from 'express'
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class JwtAuthGuard extends AuthGuard('jwt') {}
 | 
			
		||||
 | 
			
		||||
export type AuthenticatedRequest = Request & { user: User }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								server/src/geolocations/dto/create-geolocation.dto.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								server/src/geolocations/dto/create-geolocation.dto.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
import { ApiProperty } from "@nestjs/swagger"
 | 
			
		||||
 | 
			
		||||
export class CreateGeolocationDto {
 | 
			
		||||
    @ApiProperty({description: "Longitude en degrés"})
 | 
			
		||||
    longitude: number
 | 
			
		||||
  
 | 
			
		||||
    @ApiProperty({description: "Latitude en degrés"})
 | 
			
		||||
    latitude: number
 | 
			
		||||
  
 | 
			
		||||
    @ApiProperty({description: "Vitesse en mètres par seconde"})
 | 
			
		||||
    speed: number
 | 
			
		||||
  
 | 
			
		||||
    @ApiProperty({description: "Précision en mètres de la position obtenue"})
 | 
			
		||||
    accuracy: number
 | 
			
		||||
  
 | 
			
		||||
    @ApiProperty({description: "Altitude en mètres"})
 | 
			
		||||
    altitude: number
 | 
			
		||||
  
 | 
			
		||||
    @ApiProperty({description: "Précision de l'altitude en mètres"})
 | 
			
		||||
    altitudeAccuracy: number
 | 
			
		||||
  
 | 
			
		||||
    @ApiProperty({description: "Date et heure de capture de la géolocalisation"})
 | 
			
		||||
    timestamp: Date
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								server/src/geolocations/entities/geolocation.entity.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								server/src/geolocations/entities/geolocation.entity.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
import { ApiProperty } from "@nestjs/swagger"
 | 
			
		||||
import { Geolocation } from "@prisma/client"
 | 
			
		||||
 | 
			
		||||
export class GeolocationEntity implements Geolocation {
 | 
			
		||||
  constructor(partial: Partial<GeolocationEntity>) {
 | 
			
		||||
    Object.assign(this, partial)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({description: "Identifiant unique"})
 | 
			
		||||
  id: number
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({description: "Utilisateur⋅rice ayant émis la géolocalisation"})
 | 
			
		||||
  userId: number
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({description: "Longitude en degrés"})
 | 
			
		||||
  longitude: number
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({description: "Latitude en degrés"})
 | 
			
		||||
  latitude: number
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({description: "Vitesse en mètres par seconde"})
 | 
			
		||||
  speed: number
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({description: "Précision en mètres de la position obtenue"})
 | 
			
		||||
  accuracy: number
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({description: "Altitude en mètres"})
 | 
			
		||||
  altitude: number
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({description: "Précision de l'altitude en mètres"})
 | 
			
		||||
  altitudeAccuracy: number
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({description: "Date et heure de capture de la géolocalisation"})
 | 
			
		||||
  timestamp: Date
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								server/src/geolocations/geolocations.controller.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								server/src/geolocations/geolocations.controller.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import { Test, TestingModule } from '@nestjs/testing'
 | 
			
		||||
import { GeolocationsController } from './geolocations.controller'
 | 
			
		||||
import { GeolocationsService } from './geolocations.service'
 | 
			
		||||
 | 
			
		||||
describe('GeolocationsController', () => {
 | 
			
		||||
  let controller: GeolocationsController
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    const module: TestingModule = await Test.createTestingModule({
 | 
			
		||||
      controllers: [GeolocationsController],
 | 
			
		||||
      providers: [GeolocationsService],
 | 
			
		||||
    }).compile()
 | 
			
		||||
 | 
			
		||||
    controller = module.get<GeolocationsController>(GeolocationsController)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should be defined', () => {
 | 
			
		||||
    expect(controller).toBeDefined()
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										63
									
								
								server/src/geolocations/geolocations.controller.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								server/src/geolocations/geolocations.controller.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
import { Controller, Get, Post, Body, Patch, Param, Delete, ParseIntPipe, UseGuards, HttpCode, Req, NotFoundException } from '@nestjs/common'
 | 
			
		||||
import { GeolocationsService } from './geolocations.service'
 | 
			
		||||
import { CreateGeolocationDto } from './dto/create-geolocation.dto'
 | 
			
		||||
import { AuthenticatedRequest, JwtAuthGuard } from 'src/auth/jwt-auth.guard'
 | 
			
		||||
import { ApiBearerAuth, ApiCreatedResponse, ApiForbiddenResponse, ApiNoContentResponse, ApiNotFoundResponse, ApiOkResponse, ApiUnauthorizedResponse } from '@nestjs/swagger'
 | 
			
		||||
import { GeolocationEntity } from './entities/geolocation.entity'
 | 
			
		||||
 | 
			
		||||
@Controller('geolocations')
 | 
			
		||||
export class GeolocationsController {
 | 
			
		||||
  constructor(private readonly geolocationsService: GeolocationsService) {}
 | 
			
		||||
 | 
			
		||||
  @Post()
 | 
			
		||||
  @HttpCode(201)
 | 
			
		||||
  @UseGuards(JwtAuthGuard)
 | 
			
		||||
  @ApiBearerAuth()
 | 
			
		||||
  @ApiCreatedResponse({ type: GeolocationEntity, description: "Objet créé avec succès" })
 | 
			
		||||
  @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
 | 
			
		||||
  @ApiForbiddenResponse({ description: "Permission refusée" })
 | 
			
		||||
  @ApiNotFoundResponse({ description: "Object non trouvé" })
 | 
			
		||||
  async create(@Req() request: AuthenticatedRequest, @Body() createGeolocationDto: CreateGeolocationDto): Promise<GeolocationEntity> {
 | 
			
		||||
    const user = request.user
 | 
			
		||||
    const geolocation = await this.geolocationsService.create(user, createGeolocationDto)
 | 
			
		||||
    return new GeolocationEntity(geolocation)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Get()
 | 
			
		||||
  @UseGuards(JwtAuthGuard)
 | 
			
		||||
  @ApiBearerAuth()
 | 
			
		||||
  @ApiOkResponse({ type: GeolocationEntity, isArray: true })
 | 
			
		||||
  @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
 | 
			
		||||
  @ApiForbiddenResponse({ description: "Permission refusée" })
 | 
			
		||||
  @ApiNotFoundResponse({ description: "Objet non trouvé" })
 | 
			
		||||
  async findAll(): Promise<GeolocationEntity[]> {
 | 
			
		||||
    const geolocations = await this.geolocationsService.findAll()
 | 
			
		||||
    return geolocations.map(geolocation => new GeolocationEntity(geolocation))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Get(':id')
 | 
			
		||||
  @UseGuards(JwtAuthGuard)
 | 
			
		||||
  @ApiBearerAuth()
 | 
			
		||||
  @ApiOkResponse({ type: GeolocationEntity })
 | 
			
		||||
  @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
 | 
			
		||||
  @ApiForbiddenResponse({ description: "Permission refusée" })
 | 
			
		||||
  @ApiNotFoundResponse({ description: "Objet non trouvé" })
 | 
			
		||||
  async findOne(@Param('id', ParseIntPipe) id: number): Promise<GeolocationEntity> {
 | 
			
		||||
    const geolocation = await this.geolocationsService.findOne(+id)
 | 
			
		||||
    if (!geolocation)
 | 
			
		||||
      throw new NotFoundException(`Géolocalisation inexistante avec l'identifiant ${id}`)
 | 
			
		||||
    return new GeolocationEntity(geolocation)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Delete(':id')
 | 
			
		||||
  @HttpCode(204)
 | 
			
		||||
  @UseGuards(JwtAuthGuard)
 | 
			
		||||
  @ApiBearerAuth()
 | 
			
		||||
  @ApiNoContentResponse({ description: "Objet supprimé avec succès" })
 | 
			
		||||
  @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
 | 
			
		||||
  @ApiForbiddenResponse({ description: "Permission refusée" })
 | 
			
		||||
  @ApiNotFoundResponse({ description: "Objet non trouvé" })
 | 
			
		||||
  async remove(@Param('id', ParseIntPipe) id: number): Promise<void> {
 | 
			
		||||
    await this.geolocationsService.remove(+id)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								server/src/geolocations/geolocations.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								server/src/geolocations/geolocations.module.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
import { Module } from '@nestjs/common'
 | 
			
		||||
import { GeolocationsService } from './geolocations.service'
 | 
			
		||||
import { GeolocationsController } from './geolocations.controller'
 | 
			
		||||
import { PrismaModule } from 'src/prisma/prisma.module'
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
  controllers: [GeolocationsController],
 | 
			
		||||
  providers: [GeolocationsService],
 | 
			
		||||
  imports: [PrismaModule],
 | 
			
		||||
})
 | 
			
		||||
export class GeolocationsModule {}
 | 
			
		||||
							
								
								
									
										18
									
								
								server/src/geolocations/geolocations.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								server/src/geolocations/geolocations.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
import { Test, TestingModule } from '@nestjs/testing'
 | 
			
		||||
import { GeolocationsService } from './geolocations.service'
 | 
			
		||||
 | 
			
		||||
describe('GeolocationsService', () => {
 | 
			
		||||
  let service: GeolocationsService
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    const module: TestingModule = await Test.createTestingModule({
 | 
			
		||||
      providers: [GeolocationsService],
 | 
			
		||||
    }).compile()
 | 
			
		||||
 | 
			
		||||
    service = module.get<GeolocationsService>(GeolocationsService)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should be defined', () => {
 | 
			
		||||
    expect(service).toBeDefined()
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										27
									
								
								server/src/geolocations/geolocations.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								server/src/geolocations/geolocations.service.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import { Injectable } from '@nestjs/common'
 | 
			
		||||
import { CreateGeolocationDto } from './dto/create-geolocation.dto'
 | 
			
		||||
import { PrismaService } from 'src/prisma/prisma.service'
 | 
			
		||||
import { Geolocation, User } from '@prisma/client'
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class GeolocationsService {
 | 
			
		||||
  constructor(private prisma: PrismaService) { }
 | 
			
		||||
 | 
			
		||||
  async create(authenticatedUser: User, createGeolocationDto: CreateGeolocationDto): Promise<Geolocation> {
 | 
			
		||||
    const data = { ...createGeolocationDto, userId: authenticatedUser.id }
 | 
			
		||||
    return await this.prisma.geolocation.create({ data: data })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async findAll(): Promise<Geolocation[]> {
 | 
			
		||||
    return await this.prisma.geolocation.findMany()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async findOne(id: number): Promise<Geolocation> {
 | 
			
		||||
    return await this.prisma.geolocation.findUnique({ where: { id } })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  async remove(id: number): Promise<Geolocation> {
 | 
			
		||||
    return await this.prisma.geolocation.delete({ where: { id } })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +1,10 @@
 | 
			
		||||
import { Body, Controller, Get, HttpCode, NotFoundException, Param, ParseIntPipe, Patch, Post, Req, UseGuards } from '@nestjs/common'
 | 
			
		||||
import { Body, Controller, Get, HttpCode, NotFoundException, Param, ParseIntPipe, Patch, Req, UseGuards } from '@nestjs/common'
 | 
			
		||||
import { UsersService } from './users.service'
 | 
			
		||||
import { ApiBadRequestResponse, ApiBearerAuth, ApiForbiddenResponse, ApiNoContentResponse, ApiNotFoundResponse, ApiOkResponse, ApiUnauthorizedResponse } from '@nestjs/swagger'
 | 
			
		||||
import { UserEntity } from './entities/user.entity'
 | 
			
		||||
import { JwtAuthGuard } from 'src/auth/jwt-auth.guard'
 | 
			
		||||
import { User } from '@prisma/client'
 | 
			
		||||
import { AuthenticatedRequest, JwtAuthGuard } from 'src/auth/jwt-auth.guard'
 | 
			
		||||
import { UpdatePasswordDto } from './dto/user_password.dto'
 | 
			
		||||
 | 
			
		||||
export type AuthenticatedRequest = Request & { user: User }
 | 
			
		||||
 | 
			
		||||
@Controller('users')
 | 
			
		||||
export class UsersController {
 | 
			
		||||
  constructor(private readonly usersService: UsersService) {}
 | 
			
		||||
@@ -45,8 +42,8 @@ export class UsersController {
 | 
			
		||||
  @ApiBadRequestResponse({description: "Erreur dans la saisie du nouveau mot de passe."})
 | 
			
		||||
  @ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
 | 
			
		||||
  @ApiForbiddenResponse({ description: "Permission refusée" })
 | 
			
		||||
  async updatePassword(@Req() request: AuthenticatedRequest, @Body() { password }: UpdatePasswordDto) {
 | 
			
		||||
  async updatePassword(@Req() request: AuthenticatedRequest, @Body() body: UpdatePasswordDto) {
 | 
			
		||||
    const user = request.user
 | 
			
		||||
    await this.usersService.updatePassword(user, password)
 | 
			
		||||
    await this.usersService.updatePassword(user, body)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'
 | 
			
		||||
import { User } from '@prisma/client'
 | 
			
		||||
import { PrismaService } from 'src/prisma/prisma.service'
 | 
			
		||||
import * as bcrypt from 'bcrypt'
 | 
			
		||||
import { UpdatePasswordDto } from './dto/user_password.dto'
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class UsersService {
 | 
			
		||||
@@ -15,7 +16,7 @@ export class UsersService {
 | 
			
		||||
    return await this.prisma.user.findUnique({ where: { id } })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async updatePassword(user: User, password: string) {
 | 
			
		||||
  async updatePassword(user: User, { password }: UpdatePasswordDto) {
 | 
			
		||||
    const hashedPassword = await bcrypt.hash(password, 10)
 | 
			
		||||
    await this.prisma.user.update({
 | 
			
		||||
      where: { id: user.id },
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user