From 295b94a53cbce732076650d341a729e7ac8e0bac Mon Sep 17 00:00:00 2001
From: KHLIFI <hicham.khlifi.externe@swisslife.fr>
Date: Fri, 13 May 2022 18:15:27 +0200
Subject: [PATCH] develop(todoService): methods

---
 .eslintrc.js                |  3 +-
 .prettierrc                 |  6 ++--
 package-lock.json           | 24 +++++++++++++++
 package.json                |  2 ++
 src/_dto/todo.dto.ts        | 40 +++++++++++++++++++++++++
 src/_enum/errors.enum.ts    |  5 ++++
 src/_enum/states.enum.ts    |  8 +++++
 src/main.ts                 | 11 ++++++-
 src/todo/todo.controller.ts | 26 ++++++++++++++++
 src/todo/todo.service.ts    | 60 +++++++++++++++++++++++++++++++++++++
 10 files changed, 181 insertions(+), 4 deletions(-)
 create mode 100644 src/_dto/todo.dto.ts
 create mode 100644 src/_enum/errors.enum.ts
 create mode 100644 src/_enum/states.enum.ts
 create mode 100644 src/todo/todo.controller.ts
 create mode 100644 src/todo/todo.service.ts

diff --git a/.eslintrc.js b/.eslintrc.js
index 8f5aedb..12eef49 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -2,7 +2,7 @@ module.exports = {
   parser: '@typescript-eslint/parser',
   parserOptions: {
     project: 'tsconfig.json',
-    tsconfigRootDir : __dirname, 
+    tsconfigRootDir : __dirname,
     sourceType: 'module',
   },
   plugins: ['@typescript-eslint/eslint-plugin'],
@@ -21,5 +21,6 @@ module.exports = {
     '@typescript-eslint/explicit-function-return-type': 'off',
     '@typescript-eslint/explicit-module-boundary-types': 'off',
     '@typescript-eslint/no-explicit-any': 'off',
+    '@typescript-eslint/rule-empty-line-before': 'off',
   },
 };
diff --git a/.prettierrc b/.prettierrc
index dcb7279..79caa54 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,4 +1,6 @@
 {
   "singleQuote": true,
-  "trailingComma": "all"
-}
\ No newline at end of file
+  "trailingComma": "all",
+  "bracketSpacing": true,
+  rule-empty-line-before
+}
diff --git a/package-lock.json b/package-lock.json
index 7911006..7680970 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2327,6 +2327,20 @@
       "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
       "dev": true
     },
+    "class-transformer": {
+      "version": "0.5.1",
+      "resolved": "https://nexus.swisslife.lan/repository/npm-group/class-transformer/-/class-transformer-0.5.1.tgz",
+      "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
+    },
+    "class-validator": {
+      "version": "0.13.2",
+      "resolved": "https://nexus.swisslife.lan/repository/npm-group/class-validator/-/class-validator-0.13.2.tgz",
+      "integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==",
+      "requires": {
+        "libphonenumber-js": "^1.9.43",
+        "validator": "^13.7.0"
+      }
+    },
     "cli-cursor": {
       "version": "3.1.0",
       "resolved": "https://nexus.swisslife.lan/repository/npm-group/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -4629,6 +4643,11 @@
         "type-check": "~0.4.0"
       }
     },
+    "libphonenumber-js": {
+      "version": "1.9.53",
+      "resolved": "https://nexus.swisslife.lan/repository/npm-group/libphonenumber-js/-/libphonenumber-js-1.9.53.tgz",
+      "integrity": "sha512-3cuMrA2CY3TbKVC0wKye5dXYgxmVVi4g13gzotprQSguFHMqf0pIrMM2Z6ZtMsSWqvtIqi5TuQhGjMhxz0O9Mw=="
+    },
     "light-my-request": {
       "version": "4.10.1",
       "resolved": "https://nexus.swisslife.lan/repository/npm-group/light-my-request/-/light-my-request-4.10.1.tgz",
@@ -6095,6 +6114,11 @@
         "convert-source-map": "^1.6.0"
       }
     },
+    "validator": {
+      "version": "13.7.0",
+      "resolved": "https://nexus.swisslife.lan/repository/npm-group/validator/-/validator-13.7.0.tgz",
+      "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw=="
+    },
     "vary": {
       "version": "1.1.2",
       "resolved": "https://nexus.swisslife.lan/repository/npm-group/vary/-/vary-1.1.2.tgz",
diff --git a/package.json b/package.json
index f346975..e02b141 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,8 @@
     "@nestjs/common": "^8.0.0",
     "@nestjs/core": "^8.0.0",
     "@nestjs/platform-fastify": "^8.0.0",
+    "class-transformer": "^0.5.1",
+    "class-validator": "^0.13.2",
     "reflect-metadata": "^0.1.13",
     "rimraf": "^3.0.2",
     "rxjs": "^7.2.0"
diff --git a/src/_dto/todo.dto.ts b/src/_dto/todo.dto.ts
new file mode 100644
index 0000000..f714a71
--- /dev/null
+++ b/src/_dto/todo.dto.ts
@@ -0,0 +1,40 @@
+import {
+  IsDate,
+  IsEnum,
+  IsNumber,
+  IsOptional,
+  IsString,
+} from 'class-validator';
+import { StatesEnum } from '../_enum/states.enum';
+
+export class TodoDto {
+  @IsString()
+  id: string;
+
+  @IsString()
+  title: string;
+
+  @IsString()
+  author: string;
+
+  @IsDate()
+  createdAt: Date = new Date();
+
+  @IsDate()
+  @IsOptional()
+  expiredAt: Date;
+
+  @IsString()
+  @IsOptional()
+  content: string;
+
+  @IsNumber()
+  @IsOptional()
+  priority: number;
+
+  @IsEnum(StatesEnum)
+  state: StatesEnum = StatesEnum.CREATED;
+
+  @IsNumber()
+  index: number;
+}
diff --git a/src/_enum/errors.enum.ts b/src/_enum/errors.enum.ts
new file mode 100644
index 0000000..1023626
--- /dev/null
+++ b/src/_enum/errors.enum.ts
@@ -0,0 +1,5 @@
+export enum ErrorsEnum {
+  SAVE = 'SAVE',
+  FETCH_ALL = 'FETCH_ALL',
+  DELETE = 'DELETE',
+}
diff --git a/src/_enum/states.enum.ts b/src/_enum/states.enum.ts
new file mode 100644
index 0000000..4089848
--- /dev/null
+++ b/src/_enum/states.enum.ts
@@ -0,0 +1,8 @@
+export enum StatesEnum {
+  CREATED = 'CREATED',
+  READY = 'READY',
+  IN_PROGRESS = 'IN_PROGRESS',
+  BLOCKED = 'BLOCKED',
+  DONE = 'DONE',
+  CANCELED = 'CANCELED',
+}
diff --git a/src/main.ts b/src/main.ts
index 13cad38..fc98c8e 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,8 +1,17 @@
 import { NestFactory } from '@nestjs/core';
 import { AppModule } from './app.module';
+import {
+  FastifyAdapter,
+  NestFastifyApplication,
+} from '@nestjs/platform-fastify';
+import { ValidationPipe } from '@nestjs/common';
 
 async function bootstrap() {
-  const app = await NestFactory.create(AppModule);
+  const app = await NestFactory.create<NestFastifyApplication>(
+    AppModule,
+    new FastifyAdapter({ logger: true }),
+  );
+  app.useGlobalPipes(new ValidationPipe());
   await app.listen(3000);
 }
 bootstrap();
diff --git a/src/todo/todo.controller.ts b/src/todo/todo.controller.ts
new file mode 100644
index 0000000..53c42f6
--- /dev/null
+++ b/src/todo/todo.controller.ts
@@ -0,0 +1,26 @@
+import { Controller, Delete, Get, Param, Post } from '@nestjs/common';
+import { TodoDto } from '../_dto/todo.dto';
+import { Type } from 'class-transformer';
+import { TodoService } from './todo.service';
+import { Observable } from 'rxjs';
+
+@Controller('Todo')
+export class TodoController {
+  constructor(private readonly _todoService: TodoService) {}
+
+  @Get()
+  getAllTodos(): Observable<TodoDto[]> {
+    return this._todoService.getAllTodos();
+  }
+
+  @Post()
+  @Type(() => TodoDto)
+  saveTodo(td: TodoDto): Observable<void> {
+    return this._todoService.saveTodo(td);
+  }
+
+  @Delete('/:id')
+  deleteTodo(@Param('id') id: string): void {
+    this._todoService.deleteTodo(id);
+  }
+}
diff --git a/src/todo/todo.service.ts b/src/todo/todo.service.ts
new file mode 100644
index 0000000..b8b8e88
--- /dev/null
+++ b/src/todo/todo.service.ts
@@ -0,0 +1,60 @@
+import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common';
+import { TodoDto } from '../_dto/todo.dto';
+import { catchError, Observable, tap, Observer } from 'rxjs';
+import { ErrorsEnum } from '../_enum/errors.enum';
+
+@Injectable()
+export class TodoService {
+  private _logger = new Logger('TodoService');
+
+  /**
+   * Méthode permettant la sauvegarde d'un todo
+   * @param {TodoDto} td La todo à sauvegarder
+   * @returns {Observable<void>}
+   */
+  saveTodo(td: TodoDto): Observable<void> {
+    this._logger.log(`[APPEL] Initialisation de la sauvegarde de la todo ${td.id}`);
+    return new Observable<void>().pipe(
+      tap(() => this._logger.log(`[SUCCESS] La todo ${td.id} est sauvegardé`)),
+      catchError((err) => {
+        const error = err;
+        error.name = ErrorsEnum.SAVE;
+        this._logger.error('[ERROR] La sauvegarde a échoué');
+        throw new InternalServerErrorException(error, 'La sauvegarde a échoué');
+      }),
+    );
+  }
+
+  /**
+   * Méthode qui retourne tous les todos
+   * @returns {Observable<TodoDto[]>} Tableau de todo
+   */
+  getAllTodos(): Observable<TodoDto[]> {
+    this._logger.log(`[APPEL] Initialisation du fetch de tous les todos`);
+    return new Observable<TodoDto[]>().pipe(
+      tap(() => {
+        this._logger.log('[SUCCESS] Tous les todos ont été retournés');
+        return [];
+      }),
+      catchError((err) => {
+        const error = err;
+        error.name = ErrorsEnum.FETCH_ALL;
+        this._logger.error('[ERROR] Le fetch a échoué');
+        throw new InternalServerErrorException(error, 'Le fetch a échoué')
+      })
+    )
+  }
+
+  deleteTodo(id: string): Observable<void> {
+    this._logger.log(`[APPEL] Initialisation de la délétion d'un todo`);
+    return new Observable<void>().pipe(
+      tap(() => this._logger.log('[SUCCESS] Le todo a été supprimé')),
+      catchError((err) => {
+        const error = err;
+        error.name = ErrorsEnum.DELETE;
+        this._logger.error('[ERROR] La suppression a échoué');
+        throw new InternalServerErrorException(error, 'La suppression a échoué')
+      })
+    );
+  }
+}
-- 
GitLab