Compare commits
No commits in common. "138ff1df6549a5b83f5f126db5e0f9a7d01aec5d" and "1ae6b6634c0d38b54e24205b340f6f01dc2ccc61" have entirely different histories.
138ff1df65
...
1ae6b6634c
11
server/package-lock.json
generated
11
server/package-lock.json
generated
@ -17,7 +17,6 @@
|
||||
"@nestjs/swagger": "^8.1.0",
|
||||
"@prisma/client": "^6.0.1",
|
||||
"bcrypt": "^5.1.1",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
@ -3675,10 +3674,12 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/class-transformer": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
|
||||
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
|
||||
"license": "MIT"
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz",
|
||||
"integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/class-validator": {
|
||||
"version": "0.14.1",
|
||||
|
@ -28,7 +28,6 @@
|
||||
"@nestjs/swagger": "^8.1.0",
|
||||
"@prisma/client": "^6.0.1",
|
||||
"bcrypt": "^5.1.1",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
|
@ -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;
|
@ -20,16 +20,12 @@ model User {
|
||||
}
|
||||
|
||||
model Geolocation {
|
||||
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
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
longitude Float
|
||||
latitude Float
|
||||
timestamp DateTime
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
}
|
||||
|
||||
model Challenge {
|
||||
@ -42,18 +38,17 @@ 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
|
||||
@ -63,19 +58,20 @@ 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
|
||||
action ChallengeAction? @relation(fields: [actionId], references: [id])
|
||||
actionId Int? @unique
|
||||
trip TrainTrip? @relation(fields: [tripId], references: [id])
|
||||
tripId String? @unique
|
||||
action ChallengeAction? @relation(fields: [actionId], references: [id])
|
||||
trip TrainTrip? @relation(fields: [tripId], references: [id])
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
}
|
||||
|
||||
enum MoneyUpdateType {
|
||||
|
@ -3,10 +3,9 @@ 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, GeolocationsModule],
|
||||
imports: [PrismaModule, UsersModule, AuthModule],
|
||||
providers: [PrismaService],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
@ -1,9 +1,5 @@
|
||||
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 }
|
||||
|
@ -1,42 +0,0 @@
|
||||
import { ApiProperty } from "@nestjs/swagger"
|
||||
import { IsNumber, IsOptional } from "class-validator"
|
||||
|
||||
export const DEFAULT_PAGE_NUMBER = 1
|
||||
export const DEFAULT_PAGE_SIZE = 20
|
||||
|
||||
export class MetaPaginateOutputDto {
|
||||
@IsNumber()
|
||||
@ApiProperty()
|
||||
total: number
|
||||
|
||||
@IsNumber()
|
||||
@ApiProperty()
|
||||
lastPage: number
|
||||
|
||||
@IsNumber()
|
||||
@ApiProperty({ default: DEFAULT_PAGE_NUMBER })
|
||||
currentPage: number = DEFAULT_PAGE_NUMBER
|
||||
|
||||
@IsNumber()
|
||||
@ApiProperty({ default: DEFAULT_PAGE_SIZE })
|
||||
totalPerPage: number = DEFAULT_PAGE_SIZE
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@ApiProperty({ required: false, nullable: true, default: null })
|
||||
prevPage?: number | null
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@ApiProperty({ required: false, nullable: true, default: null })
|
||||
nextPage?: number | null
|
||||
}
|
||||
|
||||
export class PaginateOutputDto<T> {
|
||||
@ApiProperty({ isArray: true })
|
||||
data: T[]
|
||||
|
||||
@ApiProperty()
|
||||
meta: MetaPaginateOutputDto
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger'
|
||||
import { Type } from 'class-transformer'
|
||||
import { IsNumber, IsOptional } from 'class-validator'
|
||||
|
||||
export class QueryPaginationDto {
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@ApiProperty({default: 1, required: false, description: "Numéro de page à charger"})
|
||||
page?: number = 1
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
@ApiProperty({default: 20, required: false, description: "Nombre d'éléments à charger par page"})
|
||||
size?: number = 20
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
import { applyDecorators, NotFoundException, Type } from '@nestjs/common'
|
||||
import { QueryPaginationDto } from '../dto/pagination-query.dto'
|
||||
import { ApiExtraModels, ApiOkResponse, ApiResponseNoStatusOptions, getSchemaPath } from '@nestjs/swagger'
|
||||
import { DEFAULT_PAGE_NUMBER, DEFAULT_PAGE_SIZE, PaginateOutputDto } from '../dto/pagination-output.dto'
|
||||
|
||||
export interface PrismaPaginationParams {
|
||||
skip: number
|
||||
take: number
|
||||
}
|
||||
|
||||
export const paginate = (
|
||||
query: QueryPaginationDto,
|
||||
): PrismaPaginationParams => {
|
||||
const size = query.size || DEFAULT_PAGE_SIZE
|
||||
const page = query.page || DEFAULT_PAGE_NUMBER
|
||||
return {
|
||||
skip: size * (page - 1),
|
||||
take: size,
|
||||
}
|
||||
}
|
||||
|
||||
export const paginateOutput = <T>(
|
||||
data: T[],
|
||||
total: number,
|
||||
query: QueryPaginationDto,
|
||||
): PaginateOutputDto<T> => {
|
||||
const page = query.page || DEFAULT_PAGE_NUMBER
|
||||
const size = query.size || DEFAULT_PAGE_SIZE
|
||||
|
||||
const lastPage = Math.ceil(total / size)
|
||||
|
||||
// if data is empty, return empty array
|
||||
if (!data.length) {
|
||||
return {
|
||||
data,
|
||||
meta: {
|
||||
total,
|
||||
lastPage,
|
||||
currentPage: page,
|
||||
totalPerPage: size,
|
||||
prevPage: null,
|
||||
nextPage: null,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// if page is greater than last page, throw an error
|
||||
if (page > lastPage) {
|
||||
throw new NotFoundException(
|
||||
`Page ${page} not found. Last page is ${lastPage}`,
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
data,
|
||||
meta: {
|
||||
total,
|
||||
lastPage,
|
||||
currentPage: page,
|
||||
totalPerPage: size,
|
||||
prevPage: page > 1 ? page - 1 : null,
|
||||
nextPage: page < lastPage ? page + 1 : null,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const ApiOkResponsePaginated = <DataDto extends Type<unknown>>(dataDto: DataDto, options?: ApiResponseNoStatusOptions) =>
|
||||
applyDecorators(
|
||||
ApiExtraModels(PaginateOutputDto, dataDto),
|
||||
ApiOkResponse({
|
||||
...options,
|
||||
schema: {
|
||||
allOf: [
|
||||
{ $ref: getSchemaPath(PaginateOutputDto) },
|
||||
{
|
||||
properties: {
|
||||
data: {
|
||||
type: 'array',
|
||||
items: { $ref: getSchemaPath(dataDto) },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
)
|
@ -1,24 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
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()
|
||||
})
|
||||
})
|
@ -1,66 +0,0 @@
|
||||
import { Controller, Get, Post, Body, Patch, Param, Delete, ParseIntPipe, UseGuards, HttpCode, Req, NotFoundException, Query } 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'
|
||||
import { ApiOkResponsePaginated, paginateOutput } from 'src/common/utils/pagination.utils'
|
||||
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
|
||||
import { PaginateOutputDto } from 'src/common/dto/pagination-output.dto'
|
||||
|
||||
@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()
|
||||
@ApiOkResponsePaginated(GeolocationEntity)
|
||||
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
|
||||
@ApiForbiddenResponse({ description: "Permission refusée" })
|
||||
@ApiNotFoundResponse({ description: "Objet non trouvé" })
|
||||
async findAll(@Query() queryPagination?: QueryPaginationDto): Promise<PaginateOutputDto<GeolocationEntity>> {
|
||||
const [geolocations, total] = await this.geolocationsService.findAll(queryPagination)
|
||||
return paginateOutput<GeolocationEntity>(geolocations.map(geolocation => new GeolocationEntity(geolocation)), total, queryPagination)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
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 {}
|
@ -1,18 +0,0 @@
|
||||
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()
|
||||
})
|
||||
})
|
@ -1,34 +0,0 @@
|
||||
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'
|
||||
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
|
||||
import { paginate } from 'src/common/utils/pagination.utils'
|
||||
|
||||
@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(queryPagination?: QueryPaginationDto): Promise<[Geolocation[], number]> {
|
||||
return [
|
||||
await this.prisma.geolocation.findMany({
|
||||
...paginate(queryPagination),
|
||||
}),
|
||||
await this.prisma.geolocation.count(),
|
||||
]
|
||||
}
|
||||
|
||||
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 } })
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common'
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule)
|
||||
|
||||
app.useGlobalPipes(new ValidationPipe({ transform: true }))
|
||||
app.useGlobalPipes(new ValidationPipe())
|
||||
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)))
|
||||
|
||||
const config = new DocumentBuilder()
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Body, Controller, Get, HttpCode, NotFoundException, Param, ParseIntPipe, Patch, Query, Req, UseGuards } from '@nestjs/common'
|
||||
import { Body, Controller, Get, HttpCode, NotFoundException, Param, ParseIntPipe, Patch, Post, 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 { AuthenticatedRequest, JwtAuthGuard } from 'src/auth/jwt-auth.guard'
|
||||
import { JwtAuthGuard } from 'src/auth/jwt-auth.guard'
|
||||
import { User } from '@prisma/client'
|
||||
import { UpdatePasswordDto } from './dto/user_password.dto'
|
||||
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
|
||||
import { ApiOkResponsePaginated, paginateOutput } from 'src/common/utils/pagination.utils'
|
||||
import { PaginateOutputDto } from 'src/common/dto/pagination-output.dto'
|
||||
|
||||
export type AuthenticatedRequest = Request & { user: User }
|
||||
|
||||
@Controller('users')
|
||||
export class UsersController {
|
||||
@ -15,12 +15,12 @@ export class UsersController {
|
||||
@Get()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOkResponsePaginated(UserEntity)
|
||||
@ApiOkResponse({ type: UserEntity, isArray: true })
|
||||
@ApiUnauthorizedResponse({ description: "Non authentifié⋅e" })
|
||||
@ApiForbiddenResponse({ description: "Permission refusée" })
|
||||
async findAll(@Query() queryPagination?: QueryPaginationDto): Promise<PaginateOutputDto<UserEntity>> {
|
||||
const [users, total] = await this.usersService.findAll(queryPagination)
|
||||
return paginateOutput<UserEntity>(users.map(user => new UserEntity(user)), total, queryPagination)
|
||||
async findAll() {
|
||||
const users = await this.usersService.findAll()
|
||||
return users.map(user => new UserEntity(user))
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ -45,8 +45,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() body: UpdatePasswordDto) {
|
||||
async updatePassword(@Req() request: AuthenticatedRequest, @Body() { password }: UpdatePasswordDto) {
|
||||
const user = request.user
|
||||
await this.usersService.updatePassword(user, body)
|
||||
await this.usersService.updatePassword(user, password)
|
||||
}
|
||||
}
|
||||
|
@ -2,26 +2,20 @@ 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'
|
||||
import { QueryPaginationDto } from 'src/common/dto/pagination-query.dto'
|
||||
import { paginate } from 'src/common/utils/pagination.utils'
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
async findAll(queryPagination?: QueryPaginationDto): Promise<[User[], number]> {
|
||||
return [
|
||||
await this.prisma.user.findMany({ ...paginate(queryPagination) }),
|
||||
await this.prisma.user.count()
|
||||
]
|
||||
async findAll() {
|
||||
return await this.prisma.user.findMany()
|
||||
}
|
||||
|
||||
async findOne(id: number): Promise<User> {
|
||||
async findOne(id: number) {
|
||||
return await this.prisma.user.findUnique({ where: { id } })
|
||||
}
|
||||
|
||||
async updatePassword(user: User, { password }: UpdatePasswordDto): Promise<void> {
|
||||
async updatePassword(user: User, password: string) {
|
||||
const hashedPassword = await bcrypt.hash(password, 10)
|
||||
await this.prisma.user.update({
|
||||
where: { id: user.id },
|
||||
|
Loading…
x
Reference in New Issue
Block a user