Compare commits
6 Commits
3d72b85e6b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
423942d65e | ||
|
|
ff4d4cf892 | ||
|
|
68f8ca0ca5 | ||
|
|
6e254930b9 | ||
|
|
5088e0bb2e | ||
|
|
79a8db94f3 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -127,6 +127,11 @@ dist
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
.vscode/*
|
||||
|
||||
!.vscode/extensions.json
|
||||
!.vscode/settings.json
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
|
||||
16
.vscode/extensions.json
vendored
Normal file
16
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"Vue.volar",
|
||||
"atommaterial.a-file-icon-vscode"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
|
||||
]
|
||||
}
|
||||
14
.vscode/settings.json
vendored
Normal file
14
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"js/ts.tsdk.path": "node_modules/typescript/lib",
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[vue]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
services:
|
||||
# 1. Base de données : PostgreSQL
|
||||
db:
|
||||
image: postgres:18-alpine
|
||||
container_name: gim_db
|
||||
@@ -11,12 +10,10 @@ services:
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-gim_db_password}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-gim_db}
|
||||
volumes:
|
||||
# Persistance des données : crucial pour ne rien perdre au redémarrage
|
||||
- db_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- gim_network
|
||||
|
||||
# 2. Back-end : API NestJS
|
||||
api:
|
||||
build:
|
||||
context: ./packages/backend
|
||||
@@ -26,20 +23,17 @@ services:
|
||||
depends_on:
|
||||
- db
|
||||
environment:
|
||||
# Connexion à la BDD via le nom du conteneur ("db")
|
||||
- DB_HOST=db
|
||||
- DB_PORT=5432
|
||||
- DB_USER=${POSTGRES_USER:-gim_db_admin}
|
||||
- DB_PASSWORD=${POSTGRES_PASSWORD:-gim_db_password}
|
||||
- DB_NAME=${POSTGRES_DB:-gim_db}
|
||||
# Clé de chiffrement applicatif
|
||||
- ENCRYPTION_MASTER_KEY=${ENCRYPTION_MASTER_KEY}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
networks:
|
||||
- gim_network
|
||||
|
||||
# 3. Front-end : Vue.js servi par Nginx
|
||||
web:
|
||||
build:
|
||||
context: ./packages/frontend
|
||||
@@ -54,11 +48,9 @@ services:
|
||||
networks:
|
||||
- gim_network
|
||||
|
||||
# Définition du réseau virtuel privé pour isoler les conteneurs
|
||||
networks:
|
||||
gim_network:
|
||||
driver: bridge
|
||||
|
||||
# Définition du volume physique sur le serveur pour la base de données
|
||||
volumes:
|
||||
db_data:
|
||||
111
package-lock.json
generated
111
package-lock.json
generated
@@ -2715,26 +2715,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/config": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.3.tgz",
|
||||
"integrity": "sha512-FQ3M3Ohqfl+nHAn5tp7++wUQw0f2nAk+SFKe8EpNRnIifPqvfJP6JQxPKtFLMOHbyer4X646prFG4zSRYEssQQ==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.4.tgz",
|
||||
"integrity": "sha512-CJPjNitr0bAufSEnRe2N+JbnVmMmDoo6hvKCPzXgZoGwJSmp/dZPk9f/RMbuD/+Q1ZJPjwsRpq0vxna++Knwow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dotenv": "17.2.3",
|
||||
"dotenv": "17.4.1",
|
||||
"dotenv-expand": "12.0.3",
|
||||
"lodash": "4.17.23"
|
||||
"lodash": "4.18.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
||||
"rxjs": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/config/node_modules/lodash": {
|
||||
"version": "4.17.23",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
||||
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@nestjs/core": {
|
||||
"version": "11.1.18",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.18.tgz",
|
||||
@@ -4235,6 +4229,16 @@
|
||||
"@babel/types": "^7.28.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/bcrypt": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz",
|
||||
"integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/body-parser": {
|
||||
"version": "1.19.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
|
||||
@@ -4459,6 +4463,12 @@
|
||||
"@types/superagent": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/validator": {
|
||||
"version": "13.15.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz",
|
||||
"integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "17.0.35",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz",
|
||||
@@ -6065,6 +6075,20 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bcrypt": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
|
||||
"integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-addon-api": "^8.3.0",
|
||||
"node-gyp-build": "^4.8.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/birpc": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz",
|
||||
@@ -6436,6 +6460,23 @@
|
||||
"dev": true,
|
||||
"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"
|
||||
},
|
||||
"node_modules/class-validator": {
|
||||
"version": "0.15.1",
|
||||
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.15.1.tgz",
|
||||
"integrity": "sha512-LqoS80HBBSCVhz/3KloUly0ovokxpdOLR++Al3J3+dHXWt9sTKlKd4eYtoxhxyUjoe5+UcIM+5k9MIxyBWnRTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/validator": "^13.15.3",
|
||||
"libphonenumber-js": "^1.11.1",
|
||||
"validator": "^13.15.22"
|
||||
}
|
||||
},
|
||||
"node_modules/cli-cursor": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
|
||||
@@ -6990,9 +7031,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.2.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
||||
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
|
||||
"version": "17.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz",
|
||||
"integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -9694,6 +9735,12 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/libphonenumber-js": {
|
||||
"version": "1.12.41",
|
||||
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.41.tgz",
|
||||
"integrity": "sha512-lsmMmGXBxXIK/VMLEj0kL6MtUs1kBGj1nTCzi6zgQoG1DEwqwt2DQyHxcLykceIxAnfE3hya7NuIh6PpC6S3fA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||
@@ -10044,7 +10091,6 @@
|
||||
"version": "4.18.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
|
||||
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.memoize": {
|
||||
@@ -10534,6 +10580,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz",
|
||||
"integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18 || ^20 || >= 21"
|
||||
}
|
||||
},
|
||||
"node_modules/node-emoji": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
|
||||
@@ -10544,6 +10599,17 @@
|
||||
"lodash": "^4.17.21"
|
||||
}
|
||||
},
|
||||
"node_modules/node-gyp-build": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
|
||||
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"node-gyp-build": "bin.js",
|
||||
"node-gyp-build-optional": "optional.js",
|
||||
"node-gyp-build-test": "build-test.js"
|
||||
}
|
||||
},
|
||||
"node_modules/node-int64": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||
@@ -13497,6 +13563,15 @@
|
||||
"node": ">=10.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/validator": {
|
||||
"version": "13.15.35",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz",
|
||||
"integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
@@ -14374,11 +14449,16 @@
|
||||
"version": "0.0.1",
|
||||
"license": "UNLICENSED",
|
||||
"dependencies": {
|
||||
"@gim/shared": "*",
|
||||
"@nestjs/common": "^11.0.1",
|
||||
"@nestjs/config": "^4.0.3",
|
||||
"@nestjs/core": "^11.0.1",
|
||||
"@nestjs/mapped-types": "*",
|
||||
"@nestjs/platform-express": "^11.0.1",
|
||||
"@nestjs/typeorm": "^11.0.1",
|
||||
"bcrypt": "^6.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.15.1",
|
||||
"pg": "^8.20.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
@@ -14390,6 +14470,7 @@
|
||||
"@nestjs/cli": "^11.0.0",
|
||||
"@nestjs/schematics": "^11.0.0",
|
||||
"@nestjs/testing": "^11.0.1",
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^24.0.0",
|
||||
|
||||
@@ -30,6 +30,10 @@ export default tseslint.config(
|
||||
'@typescript-eslint/no-floating-promises': 'warn',
|
||||
'@typescript-eslint/no-unsafe-argument': 'warn',
|
||||
"prettier/prettier": ["error", { endOfLine: "auto" }],
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -20,11 +20,16 @@
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@gim/shared": "*",
|
||||
"@nestjs/common": "^11.0.1",
|
||||
"@nestjs/config": "^4.0.3",
|
||||
"@nestjs/core": "^11.0.1",
|
||||
"@nestjs/mapped-types": "*",
|
||||
"@nestjs/platform-express": "^11.0.1",
|
||||
"@nestjs/typeorm": "^11.0.1",
|
||||
"bcrypt": "^6.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.15.1",
|
||||
"pg": "^8.20.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
@@ -36,6 +41,7 @@
|
||||
"@nestjs/cli": "^11.0.0",
|
||||
"@nestjs/schematics": "^11.0.0",
|
||||
"@nestjs/testing": "^11.0.1",
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^24.0.0",
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { UsersModule } from './users/users.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -31,6 +32,8 @@ import { AppService } from './app.service';
|
||||
synchronize: true,
|
||||
}),
|
||||
}),
|
||||
|
||||
UsersModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({
|
||||
whitelist: true,
|
||||
forbidNonWhitelisted: true,
|
||||
transform: true,
|
||||
}),
|
||||
);
|
||||
await app.listen(process.env.PORT ?? 3000);
|
||||
}
|
||||
bootstrap();
|
||||
|
||||
17
packages/backend/src/users/dto/create-user.dto.ts
Normal file
17
packages/backend/src/users/dto/create-user.dto.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { IsEmail, IsNotEmpty, MinLength } from 'class-validator';
|
||||
import { ICreateUserDTO } from '@gim/shared';
|
||||
|
||||
export class CreateUserDto implements ICreateUserDTO {
|
||||
@IsEmail({}, { message: "L'email doit être valide" })
|
||||
email!: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@MinLength(8, { message: 'Le mot de passe doit faire au moins 8 caractères' })
|
||||
motDePasse!: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
nom!: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
prenom!: string;
|
||||
}
|
||||
4
packages/backend/src/users/dto/update-user.dto.ts
Normal file
4
packages/backend/src/users/dto/update-user.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { CreateUserDto } from './create-user.dto';
|
||||
|
||||
export class UpdateUserDto extends PartialType(CreateUserDto) {}
|
||||
28
packages/backend/src/users/entities/user.entity.ts
Normal file
28
packages/backend/src/users/entities/user.entity.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { IUser } from '@gim/shared';
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity('utilisateurs')
|
||||
export class User implements IUser {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id!: string;
|
||||
|
||||
@Column({ unique: true })
|
||||
email!: string;
|
||||
|
||||
@Column()
|
||||
motDePasse!: string;
|
||||
|
||||
@Column()
|
||||
nom!: string;
|
||||
|
||||
@Column()
|
||||
prenom!: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
dateCreation!: Date;
|
||||
}
|
||||
20
packages/backend/src/users/users.controller.spec.ts
Normal file
20
packages/backend/src/users/users.controller.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
42
packages/backend/src/users/users.controller.ts
Normal file
42
packages/backend/src/users/users.controller.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
} from '@nestjs/common';
|
||||
import { UsersService } from './users.service';
|
||||
import { CreateUserDto } from './dto/create-user.dto';
|
||||
import { UpdateUserDto } from './dto/update-user.dto';
|
||||
|
||||
@Controller('users')
|
||||
export class UsersController {
|
||||
constructor(private readonly usersService: UsersService) {}
|
||||
|
||||
@Post()
|
||||
create(@Body() createUserDto: CreateUserDto) {
|
||||
return this.usersService.create(createUserDto);
|
||||
}
|
||||
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.usersService.findAll();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.usersService.findOne(id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
|
||||
return this.usersService.update(id, updateUserDto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string) {
|
||||
return this.usersService.remove(id);
|
||||
}
|
||||
}
|
||||
12
packages/backend/src/users/users.module.ts
Normal file
12
packages/backend/src/users/users.module.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { UsersService } from './users.service';
|
||||
import { UsersController } from './users.controller';
|
||||
import { User } from './entities/user.entity';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([User])],
|
||||
controllers: [UsersController],
|
||||
providers: [UsersService],
|
||||
})
|
||||
export class UsersModule {}
|
||||
18
packages/backend/src/users/users.service.spec.ts
Normal file
18
packages/backend/src/users/users.service.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
describe('UsersService', () => {
|
||||
let service: UsersService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [UsersService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<UsersService>(UsersService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
70
packages/backend/src/users/users.service.ts
Normal file
70
packages/backend/src/users/users.service.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import {
|
||||
Injectable,
|
||||
ConflictException,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { CreateUserDto } from './dto/create-user.dto';
|
||||
import { User } from './entities/user.entity';
|
||||
import { UpdateUserDto } from './dto/update-user.dto';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(
|
||||
@InjectRepository(User)
|
||||
private readonly userRepository: Repository<User>,
|
||||
) {}
|
||||
|
||||
async create(createUserDto: CreateUserDto): Promise<User> {
|
||||
const utilisateurExistant = await this.userRepository.findOne({
|
||||
where: { email: createUserDto.email },
|
||||
});
|
||||
|
||||
if (utilisateurExistant) {
|
||||
throw new ConflictException('Cet email est déjà utilisé.');
|
||||
}
|
||||
|
||||
const motDePasseHache = await bcrypt.hash(createUserDto.motDePasse, 10);
|
||||
|
||||
const nouvelUtilisateur = this.userRepository.create({
|
||||
...createUserDto,
|
||||
motDePasse: motDePasseHache,
|
||||
});
|
||||
|
||||
return this.userRepository.save(nouvelUtilisateur);
|
||||
}
|
||||
|
||||
findAll(): Promise<User[]> {
|
||||
return this.userRepository.find();
|
||||
}
|
||||
|
||||
async findOne(id: string): Promise<User> {
|
||||
const user = await this.userRepository.findOne({ where: { id } });
|
||||
if (!user) {
|
||||
throw new NotFoundException(`Utilisateur avec l'ID ${id} introuvable.`);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
async update(id: string, updateUserDto: UpdateUserDto): Promise<User> {
|
||||
const user = await this.findOne(id);
|
||||
|
||||
if (updateUserDto.motDePasse) {
|
||||
updateUserDto.motDePasse = await bcrypt.hash(
|
||||
updateUserDto.motDePasse,
|
||||
10,
|
||||
);
|
||||
}
|
||||
|
||||
Object.assign(user, updateUserDto);
|
||||
|
||||
return this.userRepository.save(user);
|
||||
}
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
const user = await this.findOne(id);
|
||||
await this.userRepository.remove(user);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
"esModuleInterop": true,
|
||||
"isolatedModules": true,
|
||||
"declaration": true,
|
||||
"types": ["jest", "node"],
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"name": "@gim/shared",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js"
|
||||
"private": true,
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts"
|
||||
}
|
||||
1
packages/shared/src/index.ts
Normal file
1
packages/shared/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './users/user.interface';
|
||||
20
packages/shared/src/users/user.interface.ts
Normal file
20
packages/shared/src/users/user.interface.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Contrat pour les données envoyées lors de l'inscription
|
||||
*/
|
||||
export interface ICreateUserDTO {
|
||||
email: string;
|
||||
motDePasse: string;
|
||||
nom: string;
|
||||
prenom: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contrat pour les données renvoyées par l'API (profil public)
|
||||
*/
|
||||
export interface IUser {
|
||||
id: string;
|
||||
email: string;
|
||||
nom: string;
|
||||
prenom: string;
|
||||
dateCreation: Date;
|
||||
}
|
||||
Reference in New Issue
Block a user