Initial commit.
This commit is contained in:
15
imagora-infrastructure/build.gradle.kts
Normal file
15
imagora-infrastructure/build.gradle.kts
Normal file
@@ -0,0 +1,15 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("io.spring.dependency-management") version "1.1.7"
|
||||
kotlin("plugin.jpa") version "2.2.21"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib"))
|
||||
implementation(project(":imagora-domain"))
|
||||
implementation(project(":imagora-application"))
|
||||
implementation("org.springframework:spring-context")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
implementation("org.jetbrains.kotlin:kotlin-noarg:2.2.21")
|
||||
implementation("org.postgresql:postgresql:42.7.8")
|
||||
}
|
||||
15
imagora-infrastructure/docker/docker-compose.yaml
Normal file
15
imagora-infrastructure/docker/docker-compose.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
services:
|
||||
imagora_database:
|
||||
image: postgres:17
|
||||
container_name: imagora_database
|
||||
environment:
|
||||
POSTGRES_USER: imagora_admin
|
||||
POSTGRES_PASSWORD: P@ssword!
|
||||
POSTGRES_DB: imagora_database
|
||||
ports:
|
||||
- "11979:5432"
|
||||
volumes:
|
||||
- "./postgres_data:/var/lib/postgresql/data"
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
10
imagora-infrastructure/sql/000_database_initialisation.sql
Normal file
10
imagora-infrastructure/sql/000_database_initialisation.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
CREATE USER imagora_user
|
||||
WITH PASSWORD 'P@ssword!'
|
||||
NOCREATEDB;
|
||||
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE
|
||||
ON ALL TABLES
|
||||
IN SCHEMA public
|
||||
TO imagora_user;
|
||||
16
imagora-infrastructure/sql/001_tables_creation.sql
Normal file
16
imagora-infrastructure/sql/001_tables_creation.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
CREATE TABLE IF NOT EXISTS "user" (
|
||||
id UUID NOT NULL,
|
||||
pseudo VARCHAR(256) NOT NULL,
|
||||
email VARCHAR(256) NOT NULL,
|
||||
encrypted_password VARCHAR(512) NOT NULL,
|
||||
CONSTRAINT user_pk PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_roles (
|
||||
user_id UUID NOT NULL,
|
||||
role SMALLINT NOT NULL,
|
||||
CONSTRAINT user_roles_pk PRIMARY KEY (user_id, role),
|
||||
CONSTRAINT user_roles_user_id_fk FOREIGN KEY (user_id) REFERENCES "user" (id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS user_roles_user_id_idx ON user_roles (user_id);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.takiguchi.imagora.infrastructure.core.configuration
|
||||
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
|
||||
|
||||
@Configuration
|
||||
@EnableJpaRepositories("org.takiguchi.imagora.infrastructure")
|
||||
@EntityScan("org.takiguchi.imagora.infrastructure")
|
||||
open class JpaConfiguration
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.takiguchi.imagora.infrastructure.user
|
||||
|
||||
import com.github.michaelbull.result.Result
|
||||
import com.github.michaelbull.result.mapError
|
||||
import com.github.michaelbull.result.runCatching
|
||||
import org.springframework.stereotype.Component
|
||||
import org.takiguchi.imagora.domain.core.error.TechnicalError
|
||||
import org.takiguchi.imagora.domain.user.model.User
|
||||
import org.takiguchi.imagora.domain.user.outputport.UserOutputPort
|
||||
import org.takiguchi.imagora.infrastructure.user.model.UserEntity
|
||||
import org.takiguchi.imagora.infrastructure.user.repository.UserJpaRepository
|
||||
import java.util.*
|
||||
|
||||
@Component
|
||||
class UserJpaAdapter(
|
||||
private val userJpaRepository: UserJpaRepository
|
||||
) : UserOutputPort {
|
||||
override fun getAll(): Result<List<User>, TechnicalError> = runCatching {
|
||||
userJpaRepository.findAll()
|
||||
.map(UserEntity::toDomain)
|
||||
}.mapError { throwable ->
|
||||
TechnicalError(throwable.message ?: "Unknown error while retrieving all users.")
|
||||
}
|
||||
|
||||
override fun getById(userId: UUID): Result<User?, TechnicalError> = runCatching {
|
||||
userJpaRepository.findById(userId)
|
||||
.map(UserEntity::toDomain)
|
||||
.orElse(null)
|
||||
}.mapError { throwable ->
|
||||
TechnicalError(throwable.message ?: "Unknown error while retrieving user by its id.")
|
||||
}
|
||||
|
||||
override fun save(user: User): Result<Unit, TechnicalError> = runCatching {
|
||||
UserEntity(user).also(userJpaRepository::save)
|
||||
|
||||
Unit
|
||||
}.mapError { throwable ->
|
||||
TechnicalError(throwable.message ?: "Unknown error while saving user.")
|
||||
}
|
||||
|
||||
override fun deleteById(user: User): Result<Unit, TechnicalError> = runCatching {
|
||||
userJpaRepository.deleteById(user.id)
|
||||
}.mapError { throwable ->
|
||||
TechnicalError(throwable.message ?: "Unknown error while deleting user.")
|
||||
}
|
||||
|
||||
override fun existsByEmail(email: String): Result<Boolean, TechnicalError> = runCatching {
|
||||
userJpaRepository.existsByEmail(email)
|
||||
}.mapError { throwable ->
|
||||
TechnicalError(throwable.message ?: "Unknown error while checking user existence by its email.")
|
||||
}
|
||||
|
||||
override fun existsByPseudo(pseudo: String): Result<Boolean, TechnicalError> = runCatching {
|
||||
userJpaRepository.existsByEmail(pseudo)
|
||||
}.mapError { throwable ->
|
||||
TechnicalError(throwable.message ?: "Unknown error while checking user existence by its pseudo.")
|
||||
}
|
||||
|
||||
override fun getByPseudoOrEmail(pseudoOrEmail: String): Result<User?, TechnicalError> = runCatching {
|
||||
userJpaRepository.getByPseudoOrEmail(pseudoOrEmail)
|
||||
?.toDomain()
|
||||
}.mapError { throwable ->
|
||||
TechnicalError(throwable.message ?: "Unknown error while retrieving user by its pseudo or email.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.takiguchi.imagora.infrastructure.user.model
|
||||
|
||||
import jakarta.persistence.*
|
||||
import org.takiguchi.imagora.domain.user.model.User
|
||||
import org.takiguchi.imagora.domain.user.model.UserRole
|
||||
import java.util.*
|
||||
|
||||
@Entity
|
||||
@Table(name = "`user`")
|
||||
data class UserEntity(
|
||||
@Id
|
||||
val id: UUID,
|
||||
@Column(nullable = false)
|
||||
val pseudo: String,
|
||||
@Column(nullable = false)
|
||||
val email: String,
|
||||
@Column(nullable = false)
|
||||
val encryptedPassword: String,
|
||||
@ElementCollection(targetClass = UserRole::class)
|
||||
@CollectionTable(
|
||||
name = "user_roles",
|
||||
joinColumns = [JoinColumn(name = "user_id")]
|
||||
)
|
||||
@Column(name = "role")
|
||||
val roles: List<UserRole>
|
||||
) {
|
||||
constructor(user: User) : this (
|
||||
id = user.id,
|
||||
pseudo = user.pseudo,
|
||||
email = user.email,
|
||||
encryptedPassword = user.encryptedPassword,
|
||||
roles = user.roles,
|
||||
)
|
||||
|
||||
fun toDomain() = User(
|
||||
id = id,
|
||||
pseudo = pseudo,
|
||||
email = email,
|
||||
encryptedPassword = encryptedPassword,
|
||||
roles = roles
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.takiguchi.imagora.infrastructure.user.repository
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.data.jpa.repository.Query
|
||||
import org.springframework.data.repository.query.Param
|
||||
import org.springframework.stereotype.Repository
|
||||
import org.takiguchi.imagora.infrastructure.user.model.UserEntity
|
||||
import java.util.*
|
||||
|
||||
@Repository
|
||||
interface UserJpaRepository : JpaRepository<UserEntity, UUID> {
|
||||
fun existsByEmail(email: String): Boolean
|
||||
|
||||
@Query("SELECT u FROM UserEntity u JOIN FETCH u.roles WHERE u.pseudo = :pseudoOrEmail OR u.email = :pseudoOrEmail")
|
||||
fun getByPseudoOrEmail(@Param("pseudoOrEmail") pseudoOrEmail: String): UserEntity?
|
||||
|
||||
@Query("SELECT u FROM UserEntity u JOIN FETCH u.roles")
|
||||
override fun findAll(): List<UserEntity>
|
||||
|
||||
@Query("SELECT u FROM UserEntity u JOIN FETCH u.roles WHERE u.id = :userId")
|
||||
override fun findById(@Param("userId") userId: UUID): Optional<UserEntity>
|
||||
}
|
||||
Reference in New Issue
Block a user