From 576fbbba5625d4a3fdd8595068235fca532b81fb Mon Sep 17 00:00:00 2001
From: Julian PEREZ-RAMIREZ <julian.perez-ramirez@imt-atlantique.net>
Date: Wed, 12 Mar 2025 09:14:32 +0100
Subject: [PATCH] adding validations to UserController

---
 .../web_app/src/Controller/UserController.php | 137 ++++++++++++++++--
 server/web_app/src/Entity/User.php            |   4 +
 .../web_app/src/Repository/UserRepository.php |   8 +
 3 files changed, 134 insertions(+), 15 deletions(-)

diff --git a/server/web_app/src/Controller/UserController.php b/server/web_app/src/Controller/UserController.php
index 0ebd3f9..170923b 100644
--- a/server/web_app/src/Controller/UserController.php
+++ b/server/web_app/src/Controller/UserController.php
@@ -16,6 +16,8 @@ use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
 use Symfony\Component\Validator\Validator\ValidatorInterface;
 
+use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
+
 #[Route('/users')]
 final class UserController extends AbstractController implements UserControllerInterface
 {
@@ -45,14 +47,30 @@ final class UserController extends AbstractController implements UserControllerI
         $user->setUserName($data['userName'] ?? null);
         $user->setName($data['name'] ?? null);
         $user->setSurname($data['surname'] ?? null);
-        $user->setEmail($data['email'] ?? null);
-        $user->setRole(UserRole::from($data['role'] ?? 'ROLE_USER')); 
+        $user->setEmail($data['email'] ?? null); 
         $user->setCreatedAt(new \DateTimeImmutable());
 
         if (isset($data['password'])) {
             $user->setPassword($this->passwordHasher->hashPassword($user, $data['password']));
         }
 
+        if (isset($data['role'])) { 
+            try {
+                $user->setRole(UserRole::from($data['role']));
+            } catch (\ValueError $e) {
+                return new JsonResponse(['error' => 'Invalid role value. Allowed values: admin, user'], Response::HTTP_BAD_REQUEST);
+            }
+        }else {
+            $user->setRole(UserRole::from('user'));
+        }
+
+        if (isset($data['isBlocked'])) {
+            if (!is_bool($data['isBlocked']) ) {
+                return new JsonResponse(['error' => 'Invalid value for isBlocked. Allowed type boolean: true, false'], Response::HTTP_BAD_REQUEST);
+            }
+            $user->setIsBlocked($data['isBlocked']);
+        }
+
         // Validate the User entity
         $errors = $this->validator->validate($user);
         if (count($errors) > 0) {
@@ -63,8 +81,12 @@ final class UserController extends AbstractController implements UserControllerI
             return new JsonResponse(['errors' => $errorMessages], Response::HTTP_BAD_REQUEST);
         }
 
-        $this->entityManager->persist($user);
-        $this->entityManager->flush();
+        try {
+            $this->entityManager->persist($user);
+            $this->entityManager->flush();
+        } catch (UniqueConstraintViolationException $e) {
+            return new JsonResponse(['error' => 'This email is already registered.'], Response::HTTP_BAD_REQUEST);
+        }
 
         return $this->json([
             'message' => 'User created successfully',
@@ -76,7 +98,7 @@ final class UserController extends AbstractController implements UserControllerI
     public function getAllUsers(): JsonResponse
     {
         $users = $this->userRepository->findAllUsers();
-        $userArray = array_map(fn($user) => ['id' => $user->getId(), 'username' => $user->getUsername()], $users);
+        $userArray = array_map(fn($user) => ['id' => $user->getId(), 'username' => $user->getUserName(), 'mail' => $user->getEmail(), 'createdAt' => $user->getCreatedAt()], $users);
 
         return $this->json([
             'users' => $userArray,
@@ -84,29 +106,114 @@ final class UserController extends AbstractController implements UserControllerI
         ]);
     }
 
-    #[Route('/{id}', methods: ['GET'])]
+    #[Route('/{userId}', methods: ['GET'])]
     public function getUserById(int $userId): JsonResponse
     {
+        $user = $this->userRepository->findOneById($userId);
+
+        if (!$user) {
+            return new JsonResponse(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
+        }
+
+        $userDTO = [
+            'id' => $user->getId(),
+            'username' => $user->getUsername(),
+            'mail' => $user->getEmail(),
+            'createdAt' => $user->getCreatedAt()    
+        ];
         return $this->json([
-            'message' => 'Welcome to your new controller!',
+            'user' => $userDTO,
             'path' => 'src/Controller/ItemController.php',
         ]);
     }
 
-    #[Route('/{id}', methods: ['UPDATE'])]
+    #[Route('/{userId}', methods: ['PUT'])]
     public function updateUser(int $userId, Request $req): JsonResponse
-    {
-        return $this->json([
-            'message' => 'Welcome to your new controller!',
-            'path' => 'src/Controller/ItemController.php',
-        ]);
+    {   
+        $user = $this->userRepository->findOneById($userId);
+
+        if (!$user) {
+            return new JsonResponse(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
+        }
+    
+        $data = json_decode($req->getContent(), true);
+    
+        if (!$data) {
+            return new JsonResponse(['error' => 'Invalid JSON'], Response::HTTP_BAD_REQUEST);
+        }
+    
+        if (isset($data['username'])) {
+            $user->setUserName($data['username']);
+        }
+        if (isset($data['name'])) {
+            $user->setName($data['name']);
+        }
+        if (isset($data['surname'])) {
+            $user->setSurname($data['surname']);
+        }
+        if (isset($data['email'])) {
+            $user->setEmail($data['email']);
+        }
+        if (isset($data['isBlocked'])) {
+            if (!is_bool($data['isBlocked']) ) {
+                return new JsonResponse(['error' => 'Invalid value for isBlocked. Allowed type boolean: true, false'], Response::HTTP_BAD_REQUEST);
+            }
+            $user->setIsBlocked($data['isBlocked']);
+        }
+        if (isset($data['role'])) {
+            try {
+                $user->setRole(UserRole::from($data['role']));
+            } catch (\ValueError $e) {
+                return new JsonResponse(['error' => 'Invalid role value. Allowed values: admin, user'], Response::HTTP_BAD_REQUEST);
+            }
+        }
+    
+        // Validate the user entity
+        $errors = $this->validator->validate($user);
+        if (count($errors) > 0) {
+            $errorMessages = [];
+            foreach ($errors as $error) {
+                $errorMessages[] = $error->getMessage();
+            }
+            return new JsonResponse(['errors' => $errorMessages], Response::HTTP_BAD_REQUEST);
+        }
+    
+        try {
+            $this->entityManager->persist($user);
+            $this->entityManager->flush();
+        } catch (UniqueConstraintViolationException $e) { 
+            return new JsonResponse(['error' => 'This email is already registered.'], Response::HTTP_BAD_REQUEST);
+        }
+    
+        return new JsonResponse([
+            'message' => 'User updated successfully',
+            'user' => [
+                'id' => $user->getId(),
+                'username' => $user->getUserName(),
+                'name' => $user->getName(),
+                'surname' => $user->getSurname(),
+                'email' => $user->getEmail(),
+                'isBlocked' => $user->isBlocked(),
+                'role' => $user->getRole()->value,
+            ],
+            'path' => 'src/Controller/ItemController.php'
+        ], Response::HTTP_OK);
     }
 
-    #[Route('/{id}', methods: ['DELETE'])]
+    #[Route('/{userId}', methods: ['DELETE'])]
     public function deleteUser(int $userId): JsonResponse
     {
+        $user = $this->userRepository->findOneById($userId);
+
+        if (!$user) {
+            return new JsonResponse(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
+        }
+
+        $this->entityManager->remove($user);
+        $this->entityManager->flush();
+
         return $this->json([
-            'message' => 'Welcome to your new controller!',
+            'message' => 'User deleted successfully',
             'path' => 'src/Controller/ItemController.php',
         ]);
     }
diff --git a/server/web_app/src/Entity/User.php b/server/web_app/src/Entity/User.php
index e7b7731..3e31285 100644
--- a/server/web_app/src/Entity/User.php
+++ b/server/web_app/src/Entity/User.php
@@ -46,6 +46,10 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
     private ?bool $isBlocked = null;
 
     #[ORM\Column(enumType: UserRole::class)]
+    #[Assert\Choice(
+        callback: [UserRole::class, 'cases'],
+        message: "Invalid role value. Allowed values: {{ choices }}."
+    )]
     private ?UserRole $role = null;
 
     #[ORM\Column]
diff --git a/server/web_app/src/Repository/UserRepository.php b/server/web_app/src/Repository/UserRepository.php
index 8e1efc7..af2a91a 100644
--- a/server/web_app/src/Repository/UserRepository.php
+++ b/server/web_app/src/Repository/UserRepository.php
@@ -6,6 +6,8 @@ use App\Entity\User;
 use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
 use Doctrine\Persistence\ManagerRegistry;
 
+use App\Enum\UserRole;
+
 /**
  * @extends ServiceEntityRepository<User>
  */
@@ -30,6 +32,12 @@ class UserRepository extends ServiceEntityRepository
             ->getResult();
     }
 
+    // Custom query method to find a user by id
+    public function findOneById(int $id): ?User
+    {
+        return $this->findOneBy(['id' => $id]);
+    }
+
     // Custom query method to find a user by email
     public function findOneByEmail(string $email): ?User
     {
-- 
GitLab