Repository: js-tasks-ru/nodejs-20250303_sergei-chernoskutov
Pull request #2: 2-module 1-task
Author: login: segaChe
Created: 2025-03-20T16:47:24Z | Merged: 2025-03-22T09:00:02Z



Diff:
diff --git a/02-nestjs-basics/01-tasks-controller/package.json b/02-nestjs-basics/01-tasks-controller/package.json
index 1bb8bbe..f76ff17 100644
--- a/02-nestjs-basics/01-tasks-controller/package.json
+++ b/02-nestjs-basics/01-tasks-controller/package.json
@@ -2,5 +2,8 @@
   "scripts": {
     "start": "nest start --watch",
     "test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --no-warnings --experimental-vm-modules\" NODE_ENV=test jest --config jest.config.js --runInBand"
+  },
+  "dependencies": {
+    "uuid": "^11.1.0"
   }
 }
diff --git a/02-nestjs-basics/01-tasks-controller/tasks/task.model.ts b/02-nestjs-basics/01-tasks-controller/tasks/task.model.ts
index 270faa9..89d2061 100644
--- a/02-nestjs-basics/01-tasks-controller/tasks/task.model.ts
+++ b/02-nestjs-basics/01-tasks-controller/tasks/task.model.ts
@@ -1,12 +1,22 @@
+import { IsString, IsNotEmpty, IsEnum } from "class-validator";
+
 export enum TaskStatus {
   PENDING = "pending",
   IN_PROGRESS = "in_progress",
   COMPLETED = "completed",
 }
 
-export interface Task {
+export class Task {
   id?: string;
+
+  @IsString()
+  @IsNotEmpty()
   title: string;
+
+  @IsString()
+  @IsNotEmpty()
   description: string;
+
+  @IsEnum(TaskStatus)
   status: TaskStatus;
 }
diff --git a/02-nestjs-basics/01-tasks-controller/tasks/tasks.controller.ts b/02-nestjs-basics/01-tasks-controller/tasks/tasks.controller.ts
index 013e8d3..fbb31d0 100644
--- a/02-nestjs-basics/01-tasks-controller/tasks/tasks.controller.ts
+++ b/02-nestjs-basics/01-tasks-controller/tasks/tasks.controller.ts
@@ -6,6 +6,9 @@ import {
   Param,
   Patch,
   Post,
+  NotFoundException,
+  UsePipes,
+  ValidationPipe,
 } from "@nestjs/common";
 import { TasksService } from "./tasks.service";
 import { Task } from "./task.model";
@@ -15,17 +18,41 @@ export class TasksController {
   constructor(private readonly tasksService: TasksService) {}
 
   @Get()
-  getAllTasks() {}
+  getAllTasks() {
+    return this.tasksService.getAllTasks();
+  }
 
   @Get(":id")
-  getTaskById(@Param("id") id: string) {}
+  getTaskById(@Param("id") id: string) {
+    const task = this.tasksService.getTaskById(id);
+    if (!task) {
+      throw new NotFoundException(`Resource with id ${id} not found`);
+    }
+    return task;
+  }
 
   @Post()
-  createTask(@Body() task: Task) {}
+  @UsePipes(new ValidationPipe({ whitelist: true }))
+  createTask(@Body() task: Task) {
+    return this.tasksService.createTask(task);
+  }
 
   @Patch(":id")
-  updateTask(@Param("id") id: string, @Body() task: Task) {}
+  @UsePipes(new ValidationPipe({ whitelist: true }))
+  updateTask(@Param("id") id: string, @Body() task: Task) {
+    const updatedTask = this.tasksService.updateTask(id, task);
+    if (!updatedTask) {
+      throw new NotFoundException(`Resource with id ${id} not found`);
+    }
+    return updatedTask;
+  }
 
   @Delete(":id")
-  deleteTask(@Param("id") id: string) {}
+  deleteTask(@Param("id") id: string) {
+    const deletedTask = this.tasksService.deleteTask(id);
+    if (!deletedTask) {
+      throw new NotFoundException(`Resource with id ${id} not found`);
+    }
+    return deletedTask;
+  }
 }
diff --git a/02-nestjs-basics/01-tasks-controller/tasks/tasks.service.ts b/02-nestjs-basics/01-tasks-controller/tasks/tasks.service.ts
index 8036598..508b2cd 100644
--- a/02-nestjs-basics/01-tasks-controller/tasks/tasks.service.ts
+++ b/02-nestjs-basics/01-tasks-controller/tasks/tasks.service.ts
@@ -1,17 +1,46 @@
-import { Injectable, NotFoundException } from "@nestjs/common";
+import { Injectable } from "@nestjs/common";
+import { v4 as uuid } from "uuid";
 import { Task } from "./task.model";
 
 @Injectable()
 export class TasksService {
   private tasks: Task[] = [];
 
-  getAllTasks(): Task[] {}
+  getAllTasks(): Task[] {
+    return this.tasks;
+  }
 
-  getTaskById(id: string): Task {}
+  getTaskById(id: string): Task | null {
+    return this.tasks.find((task) => task.id === id) || null;
+  }
 
-  createTask(task: Task): Task {}
+  createTask(task: Task): Task {
+    const newTask: Task = {
+      id: uuid(),
+      ...task,
+    };
+    this.setTasks([...this.tasks, newTask]);
+    return newTask;
+  }
 
-  updateTask(id: string, update: Task): Task {}
+  updateTask(id: string, update: Task): Task {
+    const index = this.tasks.findIndex((task) => task.id === id);
+    const tasks = [...this.tasks];
+    tasks[index] = { ...tasks[index], ...update };
+    this.setTasks(tasks);
 
-  deleteTask(id: string): Task {}
+    return tasks[index];
+  }
+
+  deleteTask(id: string): Task {
+    const task = this.getTaskById(id);
+    if (task) {
+      this.setTasks(this.tasks.filter((task) => task.id !== id));
+    }
+    return task;
+  }
+
+  private setTasks(tasks: Task[]) {
+    this.tasks = tasks;
+  }
 }


Reviews:
user: login: tadjik1
body: Ваше решение близко к цели, но присутствуют критические моменты, которые требуют внимательной переработки: обработка null-значений, улучшение производительности.
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-03-21T11:32:28Z
user: login: tadjik1
body: спасибо за исправления, все отлично 👍 
state: APPROVED
author_association: NONE
submitted_at: 2025-03-22T08:59:43Z

Review comments:
diff_hunk: @@ -1,17 +1,46 @@
-import { Injectable, NotFoundException } from "@nestjs/common";
+import { Injectable } from "@nestjs/common";
+import { v4 as uuid } from "uuid";
 import { Task } from "./task.model";
 
 @Injectable()
 export class TasksService {
   private tasks: Task[] = [];
 
-  getAllTasks(): Task[] {}
+  getAllTasks(): Task[] {
+    return this.tasks;
+  }
 
-  getTaskById(id: string): Task {}
+  getTaskById(id: string): Task | null {
+    return this.tasks.find((task) => task.id === id);
+  }
path: 02-nestjs-basics/01-tasks-controller/tasks/tasks.service.ts
user: login: tadjik1
body: Метод getTaskById может вернуть undefined, хотя указан тип Task | null. Следует явно вернуть null, если задача не найдена, чтобы соответствовать объявлению типов.
created_at: 2025-03-21T11:30:36Z
author_association: NONE
diff_hunk: @@ -1,17 +1,46 @@
-import { Injectable, NotFoundException } from "@nestjs/common";
+import { Injectable } from "@nestjs/common";
+import { v4 as uuid } from "uuid";
 import { Task } from "./task.model";
 
 @Injectable()
 export class TasksService {
   private tasks: Task[] = [];
 
-  getAllTasks(): Task[] {}
+  getAllTasks(): Task[] {
+    return this.tasks;
+  }
 
-  getTaskById(id: string): Task {}
+  getTaskById(id: string): Task | null {
+    return this.tasks.find((task) => task.id === id);
+  }
 
-  createTask(task: Task): Task {}
+  createTask(task: Task): Task {
+    const newTask: Task = {
+      id: uuid(),
+      ...task,
+    };
+    this.setTasks([...this.tasks, newTask]);
+    return newTask;
+  }
 
-  updateTask(id: string, update: Task): Task {}
+  updateTask(id: string, update: Task): Task {
+    const index = this.tasks.findIndex((task) => task.id === id);
+    const tasks = JSON.parse(JSON.stringify(this.tasks));
+    tasks[index] = { ...tasks[index], ...update };
path: 02-nestjs-basics/01-tasks-controller/tasks/tasks.service.ts
user: login: tadjik1
body: Использование JSON.parse(JSON.stringify(...)) неоптимально для клонирования массива объектов. Лучше использовать spread-оператор: [...this.tasks] для простой копии или structuredClone, если требуется глубокое копирование.
created_at: 2025-03-21T11:30:36Z
author_association: NONE
diff_hunk: @@ -15,17 +18,41 @@ export class TasksController {
   constructor(private readonly tasksService: TasksService) {}
 
   @Get()
-  getAllTasks() {}
+  getAllTasks() {
+    return this.tasksService.getAllTasks();
+  }
 
   @Get(":id")
-  getTaskById(@Param("id") id: string) {}
+  getTaskById(@Param("id") id: string) {
+    const task = this.tasksService.getTaskById(id);
+    if (!task) {
+      throw new NotFoundException(`Resource with id ${id} not found`);
path: 02-nestjs-basics/01-tasks-controller/tasks/tasks.controller.ts
user: login: tadjik1
body: Отлично, что вы явно возвращаете исключение NotFoundException — это хороший пример обдуманного подхода к обработке ошибок. Конкретное сообщение также облегчает дебаггинг.
created_at: 2025-03-21T11:30:36Z
author_association: NONE

PR comments:
user: login: jsru-1
created_at: 2025-03-20T16:48:45Z
body: Добавляю преподавателя (@tadjik1) для код-ревью.
author_association: CONTRIBUTOR
user: login: jsru-1
created_at: 2025-03-22T03:38:04Z
body: Добавляю преподавателя (@tadjik1) для код-ревью.
author_association: CONTRIBUTOR