Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
214ac97
move the csv files package into the local package.
K-M-9 May 17, 2025
453f161
move the mongo package into the remote package.
K-M-9 May 17, 2025
b5e35fd
add dto for remote.
K-M-9 May 17, 2025
67bb892
implement mappers to convert data dtos into domain models.
K-M-9 May 17, 2025
4006a4d
separate the data provider into a local data source and a remote data…
K-M-9 May 17, 2025
e182263
add a custom database exception to the data layer.
K-M-9 May 17, 2025
acc5422
move the mapper to the util package.
K-M-9 May 17, 2025
5c5694f
apply dtos and handle database exception in audit log mongodb impl.
K-M-9 May 17, 2025
a024b75
apply dtos and handle database exception in project repo.
K-M-9 May 17, 2025
d5cdc20
implement dtos and handle database exceptions in the State repository…
K-M-9 May 17, 2025
e0c4453
implement dtos and handle database exceptions in the task repository,…
K-M-9 May 17, 2025
3ee01c4
implement dtos and handle database exceptions in the user repository,…
K-M-9 May 17, 2025
a4df67c
add a custom authentication exception to the data layer.
K-M-9 May 17, 2025
237e757
implement dtos and handle database exceptions in the authentication r…
K-M-9 May 17, 2025
be83bad
implement exception handling in the task repository.
K-M-9 May 17, 2025
fd4c228
implement exception handling in the state repository.
K-M-9 May 17, 2025
3ce80f0
introduce a custom file exception in the data layer and apply it to a…
K-M-9 May 17, 2025
a2bb5d0
use file exception in task csv impl test.
K-M-9 May 17, 2025
3c8bcdc
update state test cases.
K-M-9 May 17, 2025
b013405
update the test cases for change exception handling.
K-M-9 May 17, 2025
3d661bc
update the app module in the di configuration to accommodate the stru…
K-M-9 May 17, 2025
cbfed47
move the entity into the logic package and rename it from entity to m…
K-M-9 May 17, 2025
a6c01ee
rename the package from logic to domain.
K-M-9 May 17, 2025
7f48241
move the util package into the domain package.
K-M-9 May 17, 2025
1b8eb1e
move the screen classes into the console package.
K-M-9 May 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ src/
│ │ │ └── repository/ # Repository implementations
│ │ ├── di/ # Dependency injection
│ │ ├── entity/ # Domain entities
│ │ ├── logic/ # Business logic
│ │ ├── domain/ # Business domain
│ │ │ └── usecase/ # Use cases
│ │ ├── presentation/ # UI layer
│ │ └── utils/ # Utilities
Expand Down
9 changes: 0 additions & 9 deletions src/main/kotlin/data/AuthProvider.kt

This file was deleted.

9 changes: 9 additions & 0 deletions src/main/kotlin/data/Authentication.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.example.data

import org.example.data.remote.dto.UserDto

interface Authentication {
suspend fun addCurrentUser(user: UserDto)
suspend fun deleteCurrentUser()
suspend fun getCurrentUser(): UserDto?
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.example.data

import java.util.*
import java.util.UUID

interface DataProvider<Entity> {
interface LocalDataSource <Entity>{
suspend fun add(item: Entity)
suspend fun get(): List<Entity>
suspend fun getById(id: UUID): Entity?
Expand Down
11 changes: 11 additions & 0 deletions src/main/kotlin/data/RemoteDataSource.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.example.data

import java.util.UUID

interface RemoteDataSource<Entity> {
suspend fun add(item: Entity)
suspend fun get(): List<Entity>
suspend fun getById(id: UUID): Entity?
suspend fun update(item: Entity)
suspend fun delete(id: UUID)
}
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
package data.csvfile
package org.example.data.local.csvfile

import kotlinx.datetime.LocalDateTime
import org.example.data.DataProvider
import org.example.entity.AuditAction
import org.example.entity.AuditLogEntity
import org.example.entity.AuditedEntityType
import org.example.utils.PlanMateException
import org.example.data.LocalDataSource
import org.example.data.util.exception.FileException
import domain.model.AuditAction
import domain.model.AuditLog
import domain.model.AuditedType
import java.io.File
import java.io.IOException
import java.util.*
import java.util.UUID

class AuditLogCsvImpl(
fileName: String
) : DataProvider<AuditLogEntity> {
) : LocalDataSource<AuditLog> {

private val file: File = File(fileName)

override suspend fun add(item: AuditLogEntity) {
override suspend fun add(item: AuditLog) {
try {
val items = loadFromCsv().toMutableList()
items.add(item)
saveToCsv(items)
} catch (e: Exception) {
throw PlanMateException.FileWriteException("Error adding audit log: ${e.message}")
throw FileException.FileWriteException("Error adding audit log: ${e.message}")
}
}

override suspend fun get(): List<AuditLogEntity> = loadFromCsv()
override suspend fun get(): List<AuditLog> = loadFromCsv()

override suspend fun getById(id: UUID): AuditLogEntity? = loadFromCsv().find { it.id == id }
override suspend fun getById(id: UUID): AuditLog? = loadFromCsv().find { it.id == id }

override suspend fun update(item: AuditLogEntity) {
override suspend fun update(item: AuditLog) {
val items = loadFromCsv().toMutableList()
val index = items.indexOfFirst { it.id == item.id }

if (index == -1) {
throw PlanMateException.ItemNotFoundException("Audit log with ID ${item.id} not found.")
throw FileException.FileItemNotFoundException("Audit log with ID ${item.id} not found.")
}

items[index] = item
try {
saveToCsv(items)
} catch (e: Exception) {
throw PlanMateException.FileWriteException("Error updating audit log: ${e.message}")
throw FileException.FileWriteException("Error updating audit log: ${e.message}")
}
}

Expand All @@ -51,18 +51,18 @@ class AuditLogCsvImpl(
val logToDelete = items.find { it.id == id }

if (logToDelete == null) {
throw PlanMateException.ItemNotFoundException("Audit log with ID $id not found.")
throw FileException.FileItemNotFoundException("Audit log with ID $id not found.")
}

items.remove(logToDelete)
try {
saveToCsv(items)
} catch (e: Exception) {
throw PlanMateException.FileWriteException("Error deleting audit log: ${e.message}")
throw FileException.FileWriteException("Error deleting audit log: ${e.message}")
}
}

private fun loadFromCsv(): List<AuditLogEntity> {
private fun loadFromCsv(): List<AuditLog> {
ensureFileExists()
return readAndParseFile()
}
Expand All @@ -73,43 +73,43 @@ class AuditLogCsvImpl(
try {
file.createNewFile()
} catch (e: IOException) {
throw PlanMateException.FileWriteException("Error creating file '${file.name}': ${e.message}")
throw FileException.FileWriteException("Error creating file '${file.name}': ${e.message}")
}
}

private fun readAndParseFile(): List<AuditLogEntity> {
return file.readLines()
.filter { it.isNotBlank() }
.map { fromCSVLine(it) }
private fun readAndParseFile(): List<AuditLog> {
return file.readLines()
.filter { it.isNotBlank() }
.map { fromCSVLine(it) }
}

private fun saveToCsv(data: List<AuditLogEntity>) {
private fun saveToCsv(data: List<AuditLog>) {
try {
val content = data.joinToString("\n") { toCSVLine(it) }
file.writeText(content)
} catch (e: IOException) {
throw PlanMateException.FileWriteException("Error writing to file '${file.name}': ${e.message}")
throw FileException.FileWriteException("Error writing to file '${file.name}': ${e.message}")
}
}

private fun fromCSVLine(line: String): AuditLogEntity {
private fun fromCSVLine(line: String): AuditLog {
try {
val parts = line.split(",")
return AuditLogEntity(
return AuditLog(
id = UUID.fromString(parts[0]),
userId = UUID.fromString(parts[1]),
entityType = AuditedEntityType.valueOf(parts[2]),
entityType = AuditedType.valueOf(parts[2]),
entityId = UUID.fromString(parts[3]),
action = AuditAction.valueOf(parts[4]),
changeDetails = parts[5],
timestamp = LocalDateTime.parse(parts[6])
)
} catch (e: Exception) {
throw PlanMateException.InvalidFormatException("Malformed CSV line: $line. ${e.message}")
throw FileException.FileInvalidFormatException("Malformed CSV line: $line. ${e.message}")
}
}

private fun toCSVLine(entity: AuditLogEntity): String {
private fun toCSVLine(entity: AuditLog): String {
return "${entity.id},${entity.userId},${entity.entityType},${entity.entityId},${entity.action},${entity.changeDetails},${entity.timestamp}"
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
package org.example.data.csvfile
package org.example.data.local.csvfile

import org.example.data.AuthProvider
import org.example.entity.UserEntity
import org.example.data.Authentication
import org.example.data.remote.dto.UserDto
import org.example.data.util.exception.FileException
import org.example.data.util.mapper.toUserDto
import org.example.entity.User
import org.example.entity.UserType
import org.example.utils.PlanMateException
import java.io.File
import java.io.IOException
import java.util.*
import java.util.UUID

class AuthProviderImpl(
class AuthCsvImpl(
fileName: String
) : AuthProvider {
) : Authentication {

private val file = File(fileName)

override suspend fun addCurrentUser(user: UserEntity) {
override suspend fun addCurrentUser(user: UserDto) {
ensureFileExists()
try {
file.writeText(toCSVLine(user))
} catch (e: IOException) {
throw PlanMateException.FileWriteException("Error writing current user to file: ${e.message}")
throw FileException.FileWriteException("Error writing current user to file: ${e.message}")
}
}

Expand All @@ -29,38 +31,38 @@ class AuthProviderImpl(
file.writeText("")
file.delete()
} catch (e: IOException) {
throw PlanMateException.FileWriteException("Error deleting current user: ${e.message}")
throw FileException.FileWriteException("Error deleting current user: ${e.message}")
}
}

override suspend fun getCurrentUser(): UserEntity {
override suspend fun getCurrentUser(): UserDto {
ensureFileExists()
val content = file.readText().trim()
if (content.isBlank()) {
throw PlanMateException.ItemNotFoundException("No current user found.")
throw FileException.FileItemNotFoundException("No current user found.")
}
return try {
fromCSVLine(content)
fromCSVLine(content).toUserDto()
} catch (e: Exception) {
throw PlanMateException.InvalidFormatException("Malformed current user data: ${e.message}")
throw FileException.FileInvalidFormatException("Malformed current user data: ${e.message}")
}
}

private fun toCSVLine(user: UserEntity): String {
private fun toCSVLine(user: UserDto): String {
return "${user.id},${user.username},${user.password},${user.type}"
}

private fun fromCSVLine(line: String): UserEntity {
private fun fromCSVLine(line: String): User {
val parts = line.split(",")
return try {
UserEntity(
User(
id = UUID.fromString(parts[0]),
username = parts[1],
password = parts[2],
type = UserType.valueOf(parts[3])
)
} catch (e: Exception) {
throw PlanMateException.InvalidFormatException("Malformed CSV line: $line. ${e.message}")
throw FileException.FileInvalidFormatException("Malformed CSV line: $line. ${e.message}")
}
}

Expand All @@ -69,7 +71,7 @@ class AuthProviderImpl(
try {
file.createNewFile()
} catch (e: IOException) {
throw PlanMateException.FileWriteException("Could not create file: ${e.message}")
throw FileException.FileWriteException("Could not create file: ${e.message}")
}
}
}
Expand Down
Loading
Loading