Initial commit.

This commit is contained in:
Florian THIERRY
2025-11-14 14:22:56 +01:00
commit af253dcbe3
68 changed files with 1757 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
plugins {
kotlin("jvm")
}
dependencies {
implementation(kotlin("stdlib"))
}

View File

@@ -0,0 +1,3 @@
package org.takiguchi.imagora.domain.core.error
open class BusinessError(message: String) : DomainError(message)

View File

@@ -0,0 +1,3 @@
package org.takiguchi.imagora.domain.core.error
open class DomainError(val message: String)

View File

@@ -0,0 +1,3 @@
package org.takiguchi.imagora.domain.core.error
open class TechnicalError(message: String) : DomainError(message)

View File

@@ -0,0 +1,3 @@
package org.takiguchi.imagora.domain.user.error
class AuthenticationRequiredError() : UserError("Authentication is required.")

View File

@@ -0,0 +1,3 @@
package org.takiguchi.imagora.domain.user.error
class OperationNotPermittedError : UserError("Operation not permitted: You do not have rights to perform this operation.")

View File

@@ -0,0 +1,5 @@
package org.takiguchi.imagora.domain.user.error
import org.takiguchi.imagora.domain.core.error.BusinessError
open class UserError(message: String) : BusinessError(message)

View File

@@ -0,0 +1,11 @@
package org.takiguchi.imagora.domain.user.inputport
import com.github.michaelbull.result.Result
import org.takiguchi.imagora.domain.core.error.TechnicalError
import org.takiguchi.imagora.domain.user.error.UserError
interface PasswordInputPort {
fun encode(password: String): Result<String, TechnicalError>
fun checkPasswordsAreMatching(password: String, encodedPassword: String): Result<Unit, UserError>
}

View File

@@ -0,0 +1,21 @@
package org.takiguchi.imagora.domain.user.inputport
import com.github.michaelbull.result.Result
import org.takiguchi.imagora.domain.user.error.AuthenticationRequiredError
import org.takiguchi.imagora.domain.user.error.UserError
import org.takiguchi.imagora.domain.user.model.User
import org.takiguchi.imagora.domain.user.model.UserAuthenticationData
import java.util.UUID
interface UserInputPort {
fun getAuthenticatedUser(): Result<User, AuthenticationRequiredError>
fun getAll(): Result<List<User>, UserError>
fun getById(userId: UUID): Result<User?, UserError>
fun create(pseudo: String, email: String, password: String): Result<UserAuthenticationData, UserError>
fun setUserAdmin(userId: UUID): Result<Unit, UserError>
fun setUserStandard(userId: UUID): Result<Unit, UserError>
fun update(userId: UUID, pseudo: String, email: String): Result<Unit, UserError>
fun changePassword(userId: UUID, actualPassword: String, newPassword: String): Result<Unit, UserError>
fun deleteById(userId: UUID): Result<Unit, UserError>
fun login(pseudoOrEmail: String, password: String): Result<UserAuthenticationData, UserError>
}

View File

@@ -0,0 +1,10 @@
package org.takiguchi.imagora.domain.user.model
import java.time.ZonedDateTime
import java.util.*
data class RefreshToken(
val userId: UUID,
val value: UUID,
val expirationDate: ZonedDateTime
)

View File

@@ -0,0 +1,18 @@
package org.takiguchi.imagora.domain.user.model
import org.takiguchi.imagora.domain.user.model.UserRole.*
import java.util.UUID
data class User(
val id: UUID,
val pseudo: String,
val email: String,
val encryptedPassword: String,
val roles: List<UserRole>
) {
fun setAdmin(): User = copy(roles = listOf(STANDARD, ADMIN))
fun setStandard(): User = copy(roles = listOf(STANDARD))
fun isAdmin(): Boolean = roles.contains(ADMIN)
}

View File

@@ -0,0 +1,7 @@
package org.takiguchi.imagora.domain.user.model
data class UserAuthenticationData(
val tokenType: String,
val accessToken: String,
val refreshToken: RefreshToken
)

View File

@@ -0,0 +1,14 @@
package org.takiguchi.imagora.domain.user.model
enum class UserRole {
STANDARD,
ADMIN;
companion object {
fun fromString(roleAsString: String): UserRole? = when (roleAsString) {
"STANDARD" -> STANDARD
"ADMIN" -> ADMIN
else -> null
}
}
}

View File

@@ -0,0 +1,16 @@
package org.takiguchi.imagora.domain.user.outputport
import com.github.michaelbull.result.Result
import org.takiguchi.imagora.domain.core.error.TechnicalError
import org.takiguchi.imagora.domain.user.model.User
import java.util.*
interface UserOutputPort {
fun getAll(): Result<List<User>, TechnicalError>
fun getById(userId: UUID): Result<User?, TechnicalError>
fun save(user: User): Result<Unit, TechnicalError>
fun deleteById(user: User): Result<Unit, TechnicalError>
fun existsByEmail(email: String): Result<Boolean, TechnicalError>
fun existsByPseudo(pseudo: String): Result<Boolean, TechnicalError>
fun getByPseudoOrEmail(pseudoOrEmail: String): Result<User?, TechnicalError>
}