Repository: BaghdadTeam/PlanMate
Pull request #19: feature/project-test
Author: login: Abdelrahman-El-Gendy
Created: 2025-05-04T08:32:33Z | Merged: 2025-05-07T16:40:54Z



Diff:
diff --git a/src/main/kotlin/data/datasource/mapper/project/ProjectMapper.kt b/src/main/kotlin/data/datasource/mapper/project/ProjectMapper.kt
index 098e867a..57ebea8e 100644
--- a/src/main/kotlin/data/datasource/mapper/project/ProjectMapper.kt
+++ b/src/main/kotlin/data/datasource/mapper/project/ProjectMapper.kt
@@ -4,7 +4,7 @@ import org.baghdad.data.datasource.CsvMapper
 import org.baghdad.logic.model.entities.ProjectEntity
 import java.util.UUID
 
-class ProjectMapper: CsvMapper<ProjectEntity> {
+class ProjectMapper : CsvMapper<ProjectEntity> {
     override fun header(): String {
         return "id,name,creatorId"
     }
diff --git a/src/main/kotlin/data/local/ProjectDataSource.kt b/src/main/kotlin/data/local/ProjectDataSource.kt
index 62bd0942..46d7c8e7 100644
--- a/src/main/kotlin/data/local/ProjectDataSource.kt
+++ b/src/main/kotlin/data/local/ProjectDataSource.kt
@@ -2,50 +2,15 @@ package org.baghdad.data.local
 
 import org.baghdad.data.datasource.DataSource
 import org.baghdad.logic.model.entities.ProjectEntity
-import org.baghdad.logic.model.entities.StateEntity
-import org.baghdad.logic.model.entities.TaskEntity
 
 class ProjectDataSource(
-    private val projectDataSource: DataSource<ProjectEntity>,
-    private val projectStatesDataSource: DataSource<StateEntity>,
-    private val taskDataSource: DataSource<TaskEntity>
+    private val csvDataSource: DataSource<ProjectEntity>
 ) {
 
-    fun createProject(project: ProjectEntity) {
-        projectDataSource.append(project)
-    }
-
-    fun getAllProjects(): List<ProjectEntity> {
-        return projectDataSource.loadAll()
-    }
-
-    fun getProjectById(id: String): ProjectEntity? {
-        return projectDataSource.loadAll().find { it.id.toString() == id }
-    }
-
-    fun updateProject(project: ProjectEntity) {
-        val allData = projectDataSource.loadAll().toMutableList()
-        val projectIndex = allData.indexOfFirst { it.id == project.id }
-        if (projectIndex == -1) throw Exception("No project found")
-        allData[projectIndex] = project
-        projectDataSource.update(allData)
-    }
-
-    fun deleteProject(projectId: String) {
-        val projects = projectDataSource.loadAll().toMutableList()
-        val project = projects.indexOfFirst { it.id.toString() == projectId }
-        if (project == -1) throw Exception("No project found")
-
-        val projectStates = projectStatesDataSource.loadAll().toMutableList()
-        val tasks = taskDataSource.loadAll().toMutableList()
-
-        val filteredProjectStates = projectStates.filterNot { it.projectId.toString() == projectId }
-        val filteredTasks = tasks.filterNot { it.projectId == projectId }
-
-        projects.removeAt(project)
-
-        projectDataSource.update(projects)
-        projectStatesDataSource.update(filteredProjectStates)
-        taskDataSource.update(filteredTasks)
+    fun createProject() {
+        csvDataSource.append(ProjectEntity(
+            name = "Plane Mate",
+            creatorId = "rtwo' unq3fq3[rkom "
+        ))
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/di/UiModule.kt b/src/main/kotlin/di/UiModule.kt
index 2b48c39c..d63c850b 100644
--- a/src/main/kotlin/di/UiModule.kt
+++ b/src/main/kotlin/di/UiModule.kt
@@ -1,41 +1,17 @@
 package org.baghdad.di
 
-import org.baghdad.logic.usecase.projectstates.DeleteStateForProjectUseCase
-import org.baghdad.presentation.authentication.LoginUi
-import org.baghdad.presentation.authentication.LogoutUi
-import org.baghdad.presentation.projectStates.AddStateToProjectUI
-import org.baghdad.presentation.projectStates.EditProjectStateUI
-import org.baghdad.presentation.projectStates.GetAllStatesPerProjectUI
-import org.baghdad.presentation.projectStates.GetStateByIdUI
+import org.baghdad.presentation.project.ProjectUi
 import org.baghdad.presentation.task.*
 import org.koin.dsl.module
 
 val uiModule = module {
 
-    // region  :: TASKS ::
     single { CreateTaskUI(get(), get(), get(), get()) }
     single { DeleteTaskUI(get(), get(), get(), get()) }
     single { GetTasksByStateIdUI(get(), get(), get()) }
     single { GetTasksByStateIdUI(get(), get(), get()) }
     single { UpdateTaskUI(get(), get(), get(), get()) }
     single { GetTaskByIdUI(get(), get(), get()) }
-    // endregion
 
-    // region  :: PROJECT STATES ::
-
-    single { AddStateToProjectUI(get(), get(), get(), get()) }
-    single { EditProjectStateUI(get(), get(), get(), get()) }
-    single { DeleteStateForProjectUseCase(get(), get(), get()) }
-    single { GetAllStatesPerProjectUI(get(), get(), get()) }
-    single { GetStateByIdUI(get(), get(), get()) }
-
-    // endregion
-
-    // region  :: PROJECTS ::
-    // endregion
-
-    // region  :: Auth ::
-    single { LoginUi(get(), get(), get()) }
-    single { LogoutUi(get(), get(), get()) }
-    // endregion
+    single { ProjectUi(get(), get(), get(), get()) }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/di/UseCaseModule.kt b/src/main/kotlin/di/UseCaseModule.kt
index ea976e53..6e60a574 100644
--- a/src/main/kotlin/di/UseCaseModule.kt
+++ b/src/main/kotlin/di/UseCaseModule.kt
@@ -1,9 +1,10 @@
 package org.baghdad.di
 
 import org.baghdad.logic.usecase.StateTransitionUseCase
-import org.baghdad.logic.usecase.authentication.LoginUseCase
-import org.baghdad.logic.usecase.authentication.LogoutUseCase
-import org.baghdad.logic.usecase.projectstates.*
+import org.baghdad.logic.usecase.project.CreateProjectUseCase
+import org.baghdad.logic.usecase.project.DeleteProjectUseCase
+import org.baghdad.logic.usecase.project.EditProjectUseCase
+import org.baghdad.logic.usecase.project.ListProjectsUseCase
 import org.baghdad.logic.usecase.task.*
 import org.koin.dsl.module
 
@@ -20,22 +21,12 @@ val useCaseModule = module {
     single { GetTaskByIdUseCase(get()) }
     single { GetAllTasksUseCase(get()) }
     single { GetTasksByProjectIdUseCase(get()) }
-    // endregion
-
-    // region  ::  Project States Use Cases  ::
-
-    single { AddStateToProjectUseCase(get(), get(), get()) }
-    single { DeleteStateForProjectUseCase(get(), get(), get()) }
-    single { GetAllStatesPerProjectUseCase(get()) }
-    single { GetStateByIdUseCase(get()) }
-    single { EditProjectStatesUseCase(get(), get(), get()) }
-
-    // endregion
-
-    // region  ::  Authentication Use Cases  ::
 
-    single { LoginUseCase(get(), get(), get()) }
-    single { LogoutUseCase(get()) }
+    // region  ::  Project Use Cases  ::
 
+    single { CreateProjectUseCase(get()) }
+    single { DeleteProjectUseCase(get(), get()) }
+    single { EditProjectUseCase(get()) }
+    single { ListProjectsUseCase(get()) }
     // endregion
 }
\ No newline at end of file
diff --git a/src/main/kotlin/logic/model/entities/ProjectEntity.kt b/src/main/kotlin/logic/model/entities/ProjectEntity.kt
index 717e90f1..12f133f2 100644
--- a/src/main/kotlin/logic/model/entities/ProjectEntity.kt
+++ b/src/main/kotlin/logic/model/entities/ProjectEntity.kt
@@ -6,4 +6,4 @@ data class ProjectEntity(
     val id: UUID = UUID.randomUUID(),
     val name: String,
     val creatorId: String
-)
+)
\ No newline at end of file
diff --git a/src/main/kotlin/logic/repositories/ProjectRepository.kt b/src/main/kotlin/logic/repositories/ProjectRepository.kt
index 2b3b23c3..eb7e1fae 100644
--- a/src/main/kotlin/logic/repositories/ProjectRepository.kt
+++ b/src/main/kotlin/logic/repositories/ProjectRepository.kt
@@ -8,4 +8,5 @@ interface ProjectRepository {
     fun getProjectById(id: String): ProjectEntity?
     fun getAllProjects(): List<ProjectEntity>
     fun deleteProject(id: String): Boolean
+    fun editProject(project: ProjectEntity)
 }
\ No newline at end of file
diff --git a/src/main/kotlin/logic/usecase/common/AccessPolicy.kt b/src/main/kotlin/logic/usecase/common/AccessPolicy.kt
new file mode 100644
index 00000000..ab174154
--- /dev/null
+++ b/src/main/kotlin/logic/usecase/common/AccessPolicy.kt
@@ -0,0 +1,14 @@
+package org.baghdad.logic.usecase.common
+
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.model.entities.UserType
+
+object AccessPolicy {
+    fun requireAdmin(user: UserEntity): Result<Unit> {
+        return if (user.type == UserType.Admin) {
+            Result.Success(Unit)
+        } else {
+            throw IllegalAccessException("Only Admins can perform this action!.")
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/logic/usecase/common/Result.kt b/src/main/kotlin/logic/usecase/common/Result.kt
new file mode 100644
index 00000000..53e586de
--- /dev/null
+++ b/src/main/kotlin/logic/usecase/common/Result.kt
@@ -0,0 +1,6 @@
+package org.baghdad.logic.usecase.common
+
+sealed class Result<out T> {
+    data class Success<T>(val data: T? = null) : Result<T>()
+    data class Failure(val message: String) : Result<Nothing>()
+}
\ No newline at end of file
diff --git a/src/main/kotlin/logic/usecase/project/CreateProjectUseCase.kt b/src/main/kotlin/logic/usecase/project/CreateProjectUseCase.kt
new file mode 100644
index 00000000..ceed5586
--- /dev/null
+++ b/src/main/kotlin/logic/usecase/project/CreateProjectUseCase.kt
@@ -0,0 +1,20 @@
+package org.baghdad.logic.usecase.project
+
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.usecase.common.AccessPolicy.requireAdmin
+import org.baghdad.logic.usecase.common.Result
+import java.util.UUID
+
+class CreateProjectUseCase(
+    private val projectRepository: ProjectRepository
+) {
+    operator fun invoke(projectName: String, user: UserEntity): Result<Unit> {
+        requireAdmin(user = user)
+        val projectId = UUID.randomUUID()
+        val project = ProjectEntity(id = projectId, name = projectName, creatorId = user.id.toString())
+        projectRepository.createProject(project)
+        return Result.Success()
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/logic/usecase/project/DeleteProjectUseCase.kt b/src/main/kotlin/logic/usecase/project/DeleteProjectUseCase.kt
new file mode 100644
index 00000000..492b1c42
--- /dev/null
+++ b/src/main/kotlin/logic/usecase/project/DeleteProjectUseCase.kt
@@ -0,0 +1,22 @@
+package org.baghdad.logic.usecase.project
+
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.repositories.TaskRepository
+import org.baghdad.logic.usecase.common.AccessPolicy
+import org.baghdad.logic.usecase.common.Result
+import java.util.UUID
+
+class DeleteProjectUseCase(
+    private val projectRepository: ProjectRepository,
+    private val taskRepository: TaskRepository
+) {
+    operator fun invoke(id: UUID, user: UserEntity): Result<Unit> {
+        val access = AccessPolicy.requireAdmin(user)
+        if (access is Result.Failure) return access
+        if (taskRepository.getTasksByProjectId(id.toString()).isNotEmpty())
+            return Result.Failure("Cannot delete project with active tasks.")
+        projectRepository.deleteProject(id.toString())
+        return Result.Success()
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/logic/usecase/project/EditProjectUseCase.kt b/src/main/kotlin/logic/usecase/project/EditProjectUseCase.kt
new file mode 100644
index 00000000..2ee12380
--- /dev/null
+++ b/src/main/kotlin/logic/usecase/project/EditProjectUseCase.kt
@@ -0,0 +1,21 @@
+package org.baghdad.logic.usecase.project
+
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.usecase.common.AccessPolicy
+import org.baghdad.logic.usecase.common.Result
+import java.util.UUID
+
+class EditProjectUseCase(
+    private val projectRepository: ProjectRepository
+) {
+    operator fun invoke(id: UUID, newName: String, user: UserEntity): Result<Unit> {
+        val access = AccessPolicy.requireAdmin(user)
+        if (access is Result.Failure) return access
+        val existing = projectRepository.getProjectById(id.toString())
+            ?: return Result.Failure("Project not found.")
+        val updated = existing.copy(name = newName)
+        projectRepository.editProject(updated)
+        return Result.Success()
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/logic/usecase/project/ListProjectsUseCase.kt b/src/main/kotlin/logic/usecase/project/ListProjectsUseCase.kt
new file mode 100644
index 00000000..0ab5ce17
--- /dev/null
+++ b/src/main/kotlin/logic/usecase/project/ListProjectsUseCase.kt
@@ -0,0 +1,11 @@
+package org.baghdad.logic.usecase.project
+
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.usecase.common.Result
+
+class ListProjectsUseCase(private val projectRepository: ProjectRepository) {
+    operator fun invoke(): Result<List<ProjectEntity>> {
+        return Result.Success(projectRepository.getAllProjects())
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/presentation/project/ProjectUi.kt b/src/main/kotlin/presentation/project/ProjectUi.kt
new file mode 100644
index 00000000..e467b72a
--- /dev/null
+++ b/src/main/kotlin/presentation/project/ProjectUi.kt
@@ -0,0 +1,93 @@
+package org.baghdad.presentation.project
+
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.repositories.ProjectRepository
+import java.util.UUID
+import org.baghdad.logic.usecase.common.Result
+import org.baghdad.logic.usecase.project.CreateProjectUseCase
+import org.baghdad.logic.usecase.project.DeleteProjectUseCase
+import org.baghdad.logic.usecase.project.EditProjectUseCase
+import org.baghdad.logic.usecase.project.ListProjectsUseCase
+import java.util.*
+
+class ProjectUi(
+    private val createProjectUseCase: CreateProjectUseCase,
+    private val editProjectUseCase: EditProjectUseCase,
+    private val deleteProjectUseCase: DeleteProjectUseCase,
+    private val listProjectsUseCase: ListProjectsUseCase
+) {
+
+    fun createProject(user: UserEntity) {
+        println("=== Create Project ===")
+        print("Enter project name: ")
+        val name = readln()
+
+        when (val result = createProjectUseCase(name, user)) {
+            is Result.Success -> println("Project \"$name\" created successfully.")
+            is Result.Failure -> println(result.message)
+        }
+    }
+
+    fun editProject(user: UserEntity) {
+        println("=== Edit Project ===")
+        print("Enter project ID: ")
+        val idInput = readln()
+        print("Enter new project name: ")
+        val newName = readln()
+
+        val projectId = idInput.toUUIDOrNull()
+        if (projectId == null) {
+            println("Invalid UUID format.")
+            return
+        }
+
+        when (val result = editProjectUseCase(projectId, newName, user)) {
+            is Result.Success -> println("Project updated successfully.")
+            is Result.Failure -> println(result.message)
+        }
+    }
+
+    fun deleteProject(user: UserEntity) {
+        println("=== Delete Project ===")
+        print("Enter project ID: ")
+        val idInput = readln()
+
+        val projectId = idInput.toUUIDOrNull()
+        if (projectId == null) {
+            println("Invalid UUID format.")
+            return
+        }
+
+        when (val result = deleteProjectUseCase(projectId, user)) {
+            is Result.Success -> println("Project deleted successfully.")
+            is Result.Failure -> println(result.message)
+        }
+    }
+
+    fun listProjects() {
+        println("=== List of Projects ===")
+        when (val result = listProjectsUseCase()) {
+            is Result.Failure -> println(" ${result.message}")
+            is Result.Success -> {
+                val projects = result.data.orEmpty()
+                if (projects.isEmpty()) {
+                    println("No projects found.")
+                    return
+                }
+
+                println("+--------------------------------------+----------------------+----------------------+")
+                println("| Project ID                           | Name                 | Created By           |")
+                println("+--------------------------------------+----------------------+----------------------+")
+                for (project in projects) {
+                    println("| ${project.id} | ${project.name.padEnd(20)} | ${project.creatorId.padEnd(20)} |")
+                }
+                println("+--------------------------------------+----------------------+----------------------+")
+            }
+        }
+    }
+
+    private fun String.toUUIDOrNull(): UUID? =
+        runCatching { UUID.fromString(this) }.getOrNull()
+}
+
diff --git a/src/test/kotlin/logic/usecase/project/CreateProjectUseCaseTest.kt b/src/test/kotlin/logic/usecase/project/CreateProjectUseCaseTest.kt
new file mode 100644
index 00000000..05d89d3b
--- /dev/null
+++ b/src/test/kotlin/logic/usecase/project/CreateProjectUseCaseTest.kt
@@ -0,0 +1,42 @@
+package logic.usecase.project
+
+import junit.framework.TestCase.assertEquals
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.usecase.project.CreateProjectUseCase
+import java.util.UUID
+import kotlin.test.Test
+import io.mockk.*
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.usecase.common.Result
+import java.util.*
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+class CreateProjectUseCaseTest {
+
+    @Test
+    fun `create project with unique name`() {
+        // Arrange
+        val repo = mockk<ProjectRepository>(relaxed = true)
+        val useCase = CreateProjectUseCase(repo)
+        val projectId = UUID.randomUUID()
+        val admin = UserEntity(projectId, "admin", "pass", "", UserType.Admin)
+
+        // Act
+        val result = useCase("My Project", admin)
+
+        // Assert
+        assertTrue(result is Result.Success)
+
+        // Verify that createProject was called once with a project matching the name and creator
+        verify(exactly = 1) {
+            repo.createProject(withArg {
+                assertEquals("My Project", it.name)
+                assertEquals(admin.id.toString(), it.creatorId)
+            })
+        }
+
+        confirmVerified(repo)
+    }
+}
diff --git a/src/test/kotlin/logic/usecase/project/DeleteProjectWIthNoTaskTest.kt b/src/test/kotlin/logic/usecase/project/DeleteProjectWIthNoTaskTest.kt
new file mode 100644
index 00000000..18f7f4e7
--- /dev/null
+++ b/src/test/kotlin/logic/usecase/project/DeleteProjectWIthNoTaskTest.kt
@@ -0,0 +1,50 @@
+package logic.usecase.project
+
+import com.google.common.truth.Truth.assertThat
+import io.mockk.mockk
+import org.baghdad.logic.model.entities.TaskEntity
+import org.baghdad.logic.usecase.project.DeleteProjectUseCase
+import java.util.UUID
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertNull
+import kotlin.test.assertTrue
+import io.mockk.*
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.repositories.TaskRepository
+import org.baghdad.logic.usecase.common.Result
+import java.util.*
+import kotlin.test.Test
+import kotlin.test.assertTrue
+
+class DeleteProjectWithNoTaskTest {
+
+    @Test
+    fun `delete project with no tasks`() {
+        // Arrange
+        val projectRepo = mockk<ProjectRepository>(relaxed = true)
+        val taskRepo = mockk<TaskRepository>()
+        val useCase = DeleteProjectUseCase(projectRepo, taskRepo)
+
+        val projectId = UUID.randomUUID()
+        val admin = UserEntity(UUID.randomUUID(), "admin", "pass", "", UserType.Admin)
+        val project = ProjectEntity(projectId, "Project", admin.id.toString())
+
+        every { taskRepo.getTasksByProjectId(projectId.toString()) } returns emptyList()
+        every { projectRepo.deleteProject(projectId.toString()) } returns true
+
+        // Act
+        val result = useCase(projectId, admin)
+
+        // Assert
+        assertTrue(result is Result.Success)
+
+        verify(exactly = 1) { taskRepo.getTasksByProjectId(projectId.toString()) }
+        verify(exactly = 1) { projectRepo.deleteProject(projectId.toString()) }
+
+        confirmVerified(projectRepo, taskRepo)
+    }
+}
diff --git a/src/test/kotlin/logic/usecase/project/EditProjectUseCaseTest.kt b/src/test/kotlin/logic/usecase/project/EditProjectUseCaseTest.kt
new file mode 100644
index 00000000..d78fdc92
--- /dev/null
+++ b/src/test/kotlin/logic/usecase/project/EditProjectUseCaseTest.kt
@@ -0,0 +1,44 @@
+package logic.usecase.project
+
+import io.mockk.mockk
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.repositories.ProjectRepository
+import org.baghdad.logic.usecase.project.EditProjectUseCase
+import java.util.UUID
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import io.mockk.*
+import org.baghdad.logic.usecase.common.Result
+import java.util.*
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+class EditProjectUseCaseTest {
+
+    @Test
+    fun `edit project name`() {
+        // Arrange
+        val projectRepo = mockk<ProjectRepository>()
+        val useCase = EditProjectUseCase(projectRepo)
+        val admin = UserEntity(UUID.randomUUID(), "admin", "pass", "", UserType.Admin)
+        val projectId = UUID.randomUUID()
+        val existingProject = ProjectEntity(projectId, "Initial", admin.id.toString())
+
+        every { projectRepo.getProjectById(projectId.toString()) } returns existingProject
+        every { projectRepo.editProject(any()) } just Runs
+
+        // Act
+        val result = useCase(projectId, "Updated Name", admin)
+
+        // Assert
+        assertTrue(result is Result.Success)
+
+        val expected = existingProject.copy(name = "Updated Name")
+        verify(exactly = 1) { projectRepo.getProjectById(projectId.toString()) }
+        verify(exactly = 1) { projectRepo.editProject(expected) }
+
+        confirmVerified(projectRepo)
+    }
+}


Reviews:
user: login: haideraljawasim
body: Please read the review messages and try to do the requested changes asap
also please next time write what things you have done in the PR description don't leave it empty like this 
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T12:51:21Z
user: login: Abdelrahman-El-Gendy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T16:20:46Z
user: login: Abdelrahman-El-Gendy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T16:21:49Z
user: login: Abdelrahman-El-Gendy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T16:22:46Z
user: login: haideraljawasim
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T16:34:34Z
user: login: haideraljawasim
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T16:38:23Z
user: login: Abdelrahman-El-Gendy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T16:46:12Z

Review comments:
diff_hunk: @@ -2,50 +2,15 @@ package org.baghdad.data.local
 
 import org.baghdad.data.datasource.DataSource
 import org.baghdad.logic.model.entities.ProjectEntity
-import org.baghdad.logic.model.entities.StateEntity
-import org.baghdad.logic.model.entities.TaskEntity
 
 class ProjectDataSource(
-    private val projectDataSource: DataSource<ProjectEntity>,
-    private val projectStatesDataSource: DataSource<StateEntity>,
-    private val taskDataSource: DataSource<TaskEntity>
+    private val csvDataSource: DataSource<ProjectEntity>
 ) {
 
-    fun createProject(project: ProjectEntity) {
-        projectDataSource.append(project)
-    }
-
-    fun getAllProjects(): List<ProjectEntity> {
-        return projectDataSource.loadAll()
-    }
-
-    fun getProjectById(id: String): ProjectEntity? {
-        return projectDataSource.loadAll().find { it.id.toString() == id }
-    }
-
-    fun updateProject(project: ProjectEntity) {
-        val allData = projectDataSource.loadAll().toMutableList()
-        val projectIndex = allData.indexOfFirst { it.id == project.id }
-        if (projectIndex == -1) throw Exception("No project found")
-        allData[projectIndex] = project
-        projectDataSource.update(allData)
-    }
-
-    fun deleteProject(projectId: String) {
-        val projects = projectDataSource.loadAll().toMutableList()
-        val project = projects.indexOfFirst { it.id.toString() == projectId }
-        if (project == -1) throw Exception("No project found")
-
-        val projectStates = projectStatesDataSource.loadAll().toMutableList()
-        val tasks = taskDataSource.loadAll().toMutableList()
-
-        val filteredProjectStates = projectStates.filterNot { it.projectId.toString() == projectId }
-        val filteredTasks = tasks.filterNot { it.projectId == projectId }
-
-        projects.removeAt(project)
-
-        projectDataSource.update(projects)
-        projectStatesDataSource.update(filteredProjectStates)
-        taskDataSource.update(filteredTasks)
+    fun createProject() {
+        csvDataSource.append(ProjectEntity(
+            name = "Plane Mate",
+            creatorId = "rtwo' unq3fq3[rkom "
+        ))
     }
path: src/main/kotlin/data/local/ProjectDataSource.kt
user: login: haideraljawasim
body: Man why would you delete all the Implementation of the ProjectDataSource and replaced it with these four lines , this doesn't make any sense 
created_at: 2025-05-05T12:23:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,6 @@
+package org.baghdad.logic.usecase.common
+
+sealed class Result<out T> {
+    data class Success<T>(val data: T? = null) : Result<T>()
+    data class Failure(val message: String) : Result<Nothing>()
+}
path: src/main/kotlin/logic/usecase/common/Result.kt
user: login: haideraljawasim
body: I don't get it ,  what the point of this sealed class 
please read the new requirement  for the task as it was request to use exception and not result or what ever you wrote here 
created_at: 2025-05-05T12:27:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,93 @@
+package org.baghdad.presentation.project
+
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.repositories.ProjectRepository
+import java.util.UUID
+import org.baghdad.logic.usecase.common.Result
+import org.baghdad.logic.usecase.project.CreateProjectUseCase
+import org.baghdad.logic.usecase.project.DeleteProjectUseCase
+import org.baghdad.logic.usecase.project.EditProjectUseCase
+import org.baghdad.logic.usecase.project.ListProjectsUseCase
+import java.util.*
+
+class ProjectUi(
+    private val createProjectUseCase: CreateProjectUseCase,
+    private val editProjectUseCase: EditProjectUseCase,
+    private val deleteProjectUseCase: DeleteProjectUseCase,
+    private val listProjectsUseCase: ListProjectsUseCase
+) {
+
+    fun createProject(user: UserEntity) {
+        println("=== Create Project ===")
+        print("Enter project name: ")
path: src/main/kotlin/presentation/project/ProjectUi.kt
user: login: haideraljawasim
body: here you could have used our costume class viewer and reader as it will make code more testable 
created_at: 2025-05-05T12:30:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,41 +1,17 @@
 package org.baghdad.di
 
-import org.baghdad.logic.usecase.projectstates.DeleteStateForProjectUseCase
-import org.baghdad.presentation.authentication.LoginUi
-import org.baghdad.presentation.authentication.LogoutUi
-import org.baghdad.presentation.projectStates.AddStateToProjectUI
-import org.baghdad.presentation.projectStates.EditProjectStateUI
-import org.baghdad.presentation.projectStates.GetAllStatesPerProjectUI
-import org.baghdad.presentation.projectStates.GetStateByIdUI
+import org.baghdad.presentation.project.ProjectUi
 import org.baghdad.presentation.task.*
 import org.koin.dsl.module
 
 val uiModule = module {
 
-    // region  :: TASKS ::
     single { CreateTaskUI(get(), get(), get(), get()) }
     single { DeleteTaskUI(get(), get(), get(), get()) }
     single { GetTasksByStateIdUI(get(), get(), get()) }
     single { GetTasksByStateIdUI(get(), get(), get()) }
     single { UpdateTaskUI(get(), get(), get(), get()) }
     single { GetTaskByIdUI(get(), get(), get()) }
-    // endregion
 
-    // region  :: PROJECT STATES ::
-
-    single { AddStateToProjectUI(get(), get(), get(), get()) }
-    single { EditProjectStateUI(get(), get(), get(), get()) }
-    single { DeleteStateForProjectUseCase(get(), get(), get()) }
-    single { GetAllStatesPerProjectUI(get(), get(), get()) }
-    single { GetStateByIdUI(get(), get(), get()) }
-
-    // endregion
-
-    // region  :: PROJECTS ::
-    // endregion
-
-    // region  :: Auth ::
-    single { LoginUi(get(), get(), get()) }
-    single { LogoutUi(get(), get(), get()) }
-    // endregion
path: src/main/kotlin/di/UiModule.kt
user: login: haideraljawasim
body: Why would you delete these two lines they are not related to the project feature 
created_at: 2025-05-05T12:34:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,27 @@
+package logic.usecase.project
+
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.model.entities.UserType
+import org.baghdad.logic.usecase.project.EditProjectUseCase
+import java.util.UUID
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class EditProjectUseCaseTest {
+    @Test
+    fun `edit project name`() {
path: src/test/kotlin/logic/usecase/project/EditProjectUseCaseTest.kt
user: login: haideraljawasim
body: The name not clear here , you should specify  what case of test you testing here whether to fail or success to edit name 
created_at: 2025-05-05T12:39:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,32 @@
+package logic.usecase.project
+
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.repositories.ProjectRepository
+import java.util.*
+
+class FakeProjectRepository : ProjectRepository {
path: src/test/kotlin/logic/usecase/project/FakeProjectRepository.kt
user: login: haideraljawasim
body: you could have used mocks or stubs here instead of implement a fake repo 
created_at: 2025-05-05T12:45:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,93 @@
+package org.baghdad.presentation.project
+
+import org.baghdad.logic.model.entities.ProjectEntity
+import org.baghdad.logic.model.entities.UserEntity
+import org.baghdad.logic.repositories.ProjectRepository
+import java.util.UUID
+import org.baghdad.logic.usecase.common.Result
+import org.baghdad.logic.usecase.project.CreateProjectUseCase
+import org.baghdad.logic.usecase.project.DeleteProjectUseCase
+import org.baghdad.logic.usecase.project.EditProjectUseCase
+import org.baghdad.logic.usecase.project.ListProjectsUseCase
+import java.util.*
+
+class ProjectUi(
+    private val createProjectUseCase: CreateProjectUseCase,
+    private val editProjectUseCase: EditProjectUseCase,
+    private val deleteProjectUseCase: DeleteProjectUseCase,
+    private val listProjectsUseCase: ListProjectsUseCase
+) {
path: src/main/kotlin/presentation/project/ProjectUi.kt
user: login: haideraljawasim
body: also  i think splitting this class make it cleaner and more readable 
created_at: 2025-05-05T12:48:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2,50 +2,15 @@ package org.baghdad.data.local
 
 import org.baghdad.data.datasource.DataSource
 import org.baghdad.logic.model.entities.ProjectEntity
-import org.baghdad.logic.model.entities.StateEntity
-import org.baghdad.logic.model.entities.TaskEntity
 
 class ProjectDataSource(
-    private val projectDataSource: DataSource<ProjectEntity>,
-    private val projectStatesDataSource: DataSource<StateEntity>,
-    private val taskDataSource: DataSource<TaskEntity>
+    private val csvDataSource: DataSource<ProjectEntity>
 ) {
 
-    fun createProject(project: ProjectEntity) {
-        projectDataSource.append(project)
-    }
-
-    fun getAllProjects(): List<ProjectEntity> {
-        return projectDataSource.loadAll()
-    }
-
-    fun getProjectById(id: String): ProjectEntity? {
-        return projectDataSource.loadAll().find { it.id.toString() == id }
-    }
-
-    fun updateProject(project: ProjectEntity) {
-        val allData = projectDataSource.loadAll().toMutableList()
-        val projectIndex = allData.indexOfFirst { it.id == project.id }
-        if (projectIndex == -1) throw Exception("No project found")
-        allData[projectIndex] = project
-        projectDataSource.update(allData)
-    }
-
-    fun deleteProject(projectId: String) {
-        val projects = projectDataSource.loadAll().toMutableList()
-        val project = projects.indexOfFirst { it.id.toString() == projectId }
-        if (project == -1) throw Exception("No project found")
-
-        val projectStates = projectStatesDataSource.loadAll().toMutableList()
-        val tasks = taskDataSource.loadAll().toMutableList()
-
-        val filteredProjectStates = projectStates.filterNot { it.projectId.toString() == projectId }
-        val filteredTasks = tasks.filterNot { it.projectId == projectId }
-
-        projects.removeAt(project)
-
-        projectDataSource.update(projects)
-        projectStatesDataSource.update(filteredProjectStates)
-        taskDataSource.update(filteredTasks)
+    fun createProject() {
+        csvDataSource.append(ProjectEntity(
+            name = "Plane Mate",
+            creatorId = "rtwo' unq3fq3[rkom "
+        ))
     }
path: src/main/kotlin/data/local/ProjectDataSource.kt
user: login: Abdelrahman-El-Gendy
body: I did not change any of these bro, the only thing I did is my task the project module and use cases beside the tests , if there any changes it would be from other contributor not me !!
created_at: 2025-05-05T16:20:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,6 @@
+package org.baghdad.logic.usecase.common
+
+sealed class Result<out T> {
+    data class Success<T>(val data: T? = null) : Result<T>()
+    data class Failure(val message: String) : Result<Nothing>()
+}
path: src/main/kotlin/logic/usecase/common/Result.kt
user: login: Abdelrahman-El-Gendy
body: Please read my code well to find out . Ok..!!
created_at: 2025-05-05T16:21:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,41 +1,17 @@
 package org.baghdad.di
 
-import org.baghdad.logic.usecase.projectstates.DeleteStateForProjectUseCase
-import org.baghdad.presentation.authentication.LoginUi
-import org.baghdad.presentation.authentication.LogoutUi
-import org.baghdad.presentation.projectStates.AddStateToProjectUI
-import org.baghdad.presentation.projectStates.EditProjectStateUI
-import org.baghdad.presentation.projectStates.GetAllStatesPerProjectUI
-import org.baghdad.presentation.projectStates.GetStateByIdUI
+import org.baghdad.presentation.project.ProjectUi
 import org.baghdad.presentation.task.*
 import org.koin.dsl.module
 
 val uiModule = module {
 
-    // region  :: TASKS ::
     single { CreateTaskUI(get(), get(), get(), get()) }
     single { DeleteTaskUI(get(), get(), get(), get()) }
     single { GetTasksByStateIdUI(get(), get(), get()) }
     single { GetTasksByStateIdUI(get(), get(), get()) }
     single { UpdateTaskUI(get(), get(), get(), get()) }
     single { GetTaskByIdUI(get(), get(), get()) }
-    // endregion
 
-    // region  :: PROJECT STATES ::
-
-    single { AddStateToProjectUI(get(), get(), get(), get()) }
-    single { EditProjectStateUI(get(), get(), get(), get()) }
-    single { DeleteStateForProjectUseCase(get(), get(), get()) }
-    single { GetAllStatesPerProjectUI(get(), get(), get()) }
-    single { GetStateByIdUI(get(), get(), get()) }
-
-    // endregion
-
-    // region  :: PROJECTS ::
-    // endregion
-
-    // region  :: Auth ::
-    single { LoginUi(get(), get(), get()) }
-    single { LogoutUi(get(), get(), get()) }
-    // endregion
path: src/main/kotlin/di/UiModule.kt
user: login: Abdelrahman-El-Gendy
body: I did not do that!!
created_at: 2025-05-05T16:22:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2,50 +2,15 @@ package org.baghdad.data.local
 
 import org.baghdad.data.datasource.DataSource
 import org.baghdad.logic.model.entities.ProjectEntity
-import org.baghdad.logic.model.entities.StateEntity
-import org.baghdad.logic.model.entities.TaskEntity
 
 class ProjectDataSource(
-    private val projectDataSource: DataSource<ProjectEntity>,
-    private val projectStatesDataSource: DataSource<StateEntity>,
-    private val taskDataSource: DataSource<TaskEntity>
+    private val csvDataSource: DataSource<ProjectEntity>
 ) {
 
-    fun createProject(project: ProjectEntity) {
-        projectDataSource.append(project)
-    }
-
-    fun getAllProjects(): List<ProjectEntity> {
-        return projectDataSource.loadAll()
-    }
-
-    fun getProjectById(id: String): ProjectEntity? {
-        return projectDataSource.loadAll().find { it.id.toString() == id }
-    }
-
-    fun updateProject(project: ProjectEntity) {
-        val allData = projectDataSource.loadAll().toMutableList()
-        val projectIndex = allData.indexOfFirst { it.id == project.id }
-        if (projectIndex == -1) throw Exception("No project found")
-        allData[projectIndex] = project
-        projectDataSource.update(allData)
-    }
-
-    fun deleteProject(projectId: String) {
-        val projects = projectDataSource.loadAll().toMutableList()
-        val project = projects.indexOfFirst { it.id.toString() == projectId }
-        if (project == -1) throw Exception("No project found")
-
-        val projectStates = projectStatesDataSource.loadAll().toMutableList()
-        val tasks = taskDataSource.loadAll().toMutableList()
-
-        val filteredProjectStates = projectStates.filterNot { it.projectId.toString() == projectId }
-        val filteredTasks = tasks.filterNot { it.projectId == projectId }
-
-        projects.removeAt(project)
-
-        projectDataSource.update(projects)
-        projectStatesDataSource.update(filteredProjectStates)
-        taskDataSource.update(filteredTasks)
+    fun createProject() {
+        csvDataSource.append(ProjectEntity(
+            name = "Plane Mate",
+            creatorId = "rtwo' unq3fq3[rkom "
+        ))
     }
path: src/main/kotlin/data/local/ProjectDataSource.kt
user: login: haideraljawasim
body: the ProjectDataSource is  a part of your task , so in way or another you should have implement it
created_at: 2025-05-05T16:34:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,6 @@
+package org.baghdad.logic.usecase.common
+
+sealed class Result<out T> {
+    data class Success<T>(val data: T? = null) : Result<T>()
+    data class Failure(val message: String) : Result<Nothing>()
+}
path: src/main/kotlin/logic/usecase/common/Result.kt
user: login: haideraljawasim
body: I already read it and know where you have used it  , but i what i was saying that the new task requirement is to use exceptions  and NOT RESULT kotlin class or what you have wrote here 
created_at: 2025-05-05T16:38:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2,50 +2,15 @@ package org.baghdad.data.local
 
 import org.baghdad.data.datasource.DataSource
 import org.baghdad.logic.model.entities.ProjectEntity
-import org.baghdad.logic.model.entities.StateEntity
-import org.baghdad.logic.model.entities.TaskEntity
 
 class ProjectDataSource(
-    private val projectDataSource: DataSource<ProjectEntity>,
-    private val projectStatesDataSource: DataSource<StateEntity>,
-    private val taskDataSource: DataSource<TaskEntity>
+    private val csvDataSource: DataSource<ProjectEntity>
 ) {
 
-    fun createProject(project: ProjectEntity) {
-        projectDataSource.append(project)
-    }
-
-    fun getAllProjects(): List<ProjectEntity> {
-        return projectDataSource.loadAll()
-    }
-
-    fun getProjectById(id: String): ProjectEntity? {
-        return projectDataSource.loadAll().find { it.id.toString() == id }
-    }
-
-    fun updateProject(project: ProjectEntity) {
-        val allData = projectDataSource.loadAll().toMutableList()
-        val projectIndex = allData.indexOfFirst { it.id == project.id }
-        if (projectIndex == -1) throw Exception("No project found")
-        allData[projectIndex] = project
-        projectDataSource.update(allData)
-    }
-
-    fun deleteProject(projectId: String) {
-        val projects = projectDataSource.loadAll().toMutableList()
-        val project = projects.indexOfFirst { it.id.toString() == projectId }
-        if (project == -1) throw Exception("No project found")
-
-        val projectStates = projectStatesDataSource.loadAll().toMutableList()
-        val tasks = taskDataSource.loadAll().toMutableList()
-
-        val filteredProjectStates = projectStates.filterNot { it.projectId.toString() == projectId }
-        val filteredTasks = tasks.filterNot { it.projectId == projectId }
-
-        projects.removeAt(project)
-
-        projectDataSource.update(projects)
-        projectStatesDataSource.update(filteredProjectStates)
-        taskDataSource.update(filteredTasks)
+    fun createProject() {
+        csvDataSource.append(ProjectEntity(
+            name = "Plane Mate",
+            creatorId = "rtwo' unq3fq3[rkom "
+        ))
     }
path: src/main/kotlin/data/local/ProjectDataSource.kt
user: login: Abdelrahman-El-Gendy
body: I supposed that it was implemented from the beginning , the base project code ,  by the way i will give it a look .
created_at: 2025-05-05T16:46:12Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-05T09:39:12Z
body: ### 🛡️ Code Coverage Report
|Overall Project|88.8%|:x:|
|:-|:-|:-:|

> There is no coverage information present for the Files changed
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-05T12:35:35Z
body: ### 🛡️ Code Coverage Report
|Overall Project|88.14%|:x:|
|:-|:-|:-:|

> There is no coverage information present for the Files changed
author_association: NONE