commit a2c335e8eba2d6ebdedad569d4dee5f76eab1679
Author: Petr Urban <urbanp@gapps.zcu.cz>
Date:   Sat Nov 18 12:29:09 2023 +0100

    https://kivprogrammers.atlassian.net/browse/TSP2-58

diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/management/CategoryController.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/management/CategoryController.java
index 9533bd3..26dd28a 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/management/CategoryController.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/controller/management/CategoryController.java
@@ -12,9 +12,12 @@ import java.util.List;
  * This class contains all endpoints connected to Categories
  */
 @Controller
+@RequiredArgsConstructor
 @RequestMapping("v2/management")
 public class CategoryController {
 
+    private final ICategories categories;
+
     @GetMapping("/getCategories")
     public ResponseEntity<String> getCategories() {
         //TODO
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/model/CategoryDto.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/model/CategoryDto.java
new file mode 100644
index 0000000..00d49f6
--- /dev/null
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/model/CategoryDto.java
@@ -0,0 +1,18 @@
+package cz.zcu.fav.kiv.antipatterndetectionapp.v2.model;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class CategoryDto {
+
+    private Long id;
+
+    private String name;
+
+    private String description;
+
+    public static CategoryDtoBuilder builder() { return new CategoryDtoBuilder(); }
+
+}
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/model/GeneralResponseDto.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/model/GeneralResponseDto.java
new file mode 100644
index 0000000..1b0e53c
--- /dev/null
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/model/GeneralResponseDto.java
@@ -0,0 +1,15 @@
+package cz.zcu.fav.kiv.antipatterndetectionapp.v2.model;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+public class GeneralResponseDto<T> {
+    private String message;
+    private List<T> categories;
+    public static <T> GeneralResponseDtoBuilder<T> builder() { return new GeneralResponseDtoBuilder<T>(); }
+
+}
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/management/category/ICategories.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/management/category/ICategories.java
new file mode 100644
index 0000000..3cec599
--- /dev/null
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/management/category/ICategories.java
@@ -0,0 +1,15 @@
+package cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.management.category;
+
+import cz.zcu.fav.kiv.antipatterndetectionapp.model.Project;
+import cz.zcu.fav.kiv.antipatterndetectionapp.v2.model.CategoryDto;
+import cz.zcu.fav.kiv.antipatterndetectionapp.v2.model.GeneralResponseDto;
+import org.springframework.http.ResponseEntity;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface ICategories {
+
+    ResponseEntity<GeneralResponseDto<CategoryDto>> getResponse(String projectId);
+
+}
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/management/category/impl/CategoriesImpl.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/management/category/impl/CategoriesImpl.java
new file mode 100644
index 0000000..4c9f2f6
--- /dev/null
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/service/management/category/impl/CategoriesImpl.java
@@ -0,0 +1,94 @@
+package cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.management.category.impl;
+
+import cz.zcu.fav.kiv.antipatterndetectionapp.model.Project;
+import cz.zcu.fav.kiv.antipatterndetectionapp.model.management.Category;
+import cz.zcu.fav.kiv.antipatterndetectionapp.model.management.ProjectInstance;
+import cz.zcu.fav.kiv.antipatterndetectionapp.service.ProjectService;
+import cz.zcu.fav.kiv.antipatterndetectionapp.v2.model.CategoryDto;
+import cz.zcu.fav.kiv.antipatterndetectionapp.v2.model.GeneralResponseDto;
+import cz.zcu.fav.kiv.antipatterndetectionapp.v2.service.management.category.ICategories;
+import cz.zcu.fav.kiv.antipatterndetectionapp.v2.utils.converters.CategoryToDto;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.lang.Nullable;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Service
+@RequiredArgsConstructor
+public class CategoriesImpl implements ICategories {
+
+    private final ProjectService projectService;
+    private CategoryToDto categoryMapper = new CategoryToDto();
+    private final String PROJECT_NOT_FOUND_MESSAGE = "Project not found!";
+    private final String CATEGORIES_NOT_FOUND_MESSAGE = "Categories not found for the project!";
+    private final String INVALID_PROJECT_ID = "Provided project ID is in invalid format!";
+
+    private Project getProjectById(Long id) {
+        return projectService.getProjectById(id);
+    }
+
+    private List<CategoryDto> getCategories(Project project) {
+
+        if (project == null) {
+            return null;
+        }
+
+        List<Category> categories = new ArrayList<>();
+        for (ProjectInstance projectInstance : project.getProjectInstances()) {
+            categories.addAll(projectInstance.getCategories());
+        }
+
+        List<CategoryDto> categoriesDto = categoryMapper.convert(categories);
+        categoriesDto.sort(Comparator.comparing(CategoryDto::getName, String.CASE_INSENSITIVE_ORDER));
+
+        return categoriesDto;
+    }
+
+    @Override
+    public ResponseEntity<GeneralResponseDto<CategoryDto>> getResponse(String projectId) {
+        // --- The value from the request body is String, so there must be a validation if the string is number or not.
+        final Long id = tryParse(projectId);
+        if (id == Long.MIN_VALUE)
+            return createResponseEntity(HttpStatus.BAD_REQUEST, INVALID_PROJECT_ID, null);
+
+        // --- get project by ID
+        final Project project = getProjectById(id);
+
+        if (project == null)
+            return createResponseEntity(HttpStatus.NOT_FOUND, PROJECT_NOT_FOUND_MESSAGE, null);
+
+        // --- Get all categories for the specific project
+        final List<CategoryDto> categories = getCategories(project);
+
+        if (categories == null)
+            return createResponseEntity(HttpStatus.NOT_FOUND, CATEGORIES_NOT_FOUND_MESSAGE, null);
+
+        return createResponseEntity(HttpStatus.OK, null, categories);
+    }
+
+    private ResponseEntity<GeneralResponseDto<CategoryDto>> createResponseEntity(@NonNull HttpStatus status,
+                                                                                 @Nullable String message,
+                                                                                 @Nullable List<CategoryDto> categories) {
+
+
+        return new ResponseEntity<>(
+                GeneralResponseDto
+                        .<CategoryDto>builder()
+                        .message(message)
+                        .categories(categories)
+                        .build(), status);
+    }
+
+    private Long tryParse(String valueToParse) {
+        try {
+            return Long.parseLong(valueToParse);
+        } catch (NumberFormatException e) {
+            return Long.MIN_VALUE;
+        }
+    }
+
+}
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/utils/converters/CategoryToDto.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/utils/converters/CategoryToDto.java
new file mode 100644
index 0000000..ec8995d
--- /dev/null
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/v2/utils/converters/CategoryToDto.java
@@ -0,0 +1,26 @@
+package cz.zcu.fav.kiv.antipatterndetectionapp.v2.utils.converters;
+
+import cz.zcu.fav.kiv.antipatterndetectionapp.model.management.Category;
+import cz.zcu.fav.kiv.antipatterndetectionapp.v2.model.CategoryDto;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CategoryToDto implements ClassToDto <Category, CategoryDto> {
+    @Override
+    public CategoryDto convert(Category source) {
+        return CategoryDto
+                .builder()
+                .id(source.getId())
+                .name(source.getName())
+                .description(source.getDescription())
+                .build();
+    }
+
+    @Override
+    public List<CategoryDto> convert(List<Category> source) {
+        List<CategoryDto> categories = new ArrayList<>();
+        source.stream().forEach(e -> categories.add(convert(e)));
+        return categories;
+    }
+}
