(fix) Umbau zu SCS

This commit is contained in:
stefan
2025-07-19 11:26:09 +02:00
parent e1125a3fc0
commit e76db7e924
39 changed files with 1107 additions and 342 deletions
@@ -123,6 +123,10 @@ class CreateBerechtigungUseCase(
errors.add(ValidationError("aktion", "Aktion must not exceed 50 characters"))
}
return ValidationResult(errors)
return if (errors.isEmpty()) {
ValidationResult.Valid
} else {
ValidationResult.Invalid(errors)
}
}
}
@@ -1,20 +0,0 @@
package at.mocode.members.infrastructure.repository
import at.mocode.enums.BerechtigungE
import org.jetbrains.exposed.dao.id.UUIDTable
import org.jetbrains.exposed.sql.kotlin.datetime.datetime
/**
* Database table definition for permissions (Berechtigungen).
*/
object BerechtigungTable : UUIDTable("berechtigung") {
val berechtigungTyp = enumerationByName("berechtigung_typ", 50, BerechtigungE::class)
val name = varchar("name", 100)
val beschreibung = text("beschreibung").nullable()
val ressource = varchar("ressource", 50)
val aktion = varchar("aktion", 50)
val istAktiv = bool("ist_aktiv").default(true)
val istSystemBerechtigung = bool("ist_system_berechtigung").default(false)
val createdAt = datetime("created_at")
val updatedAt = datetime("updated_at")
}
@@ -1,60 +0,0 @@
package at.mocode.members.infrastructure.repository
import at.mocode.enums.DatenQuelleE
import at.mocode.enums.GeschlechtE
import org.jetbrains.exposed.dao.id.UUIDTable
import org.jetbrains.exposed.sql.kotlin.datetime.datetime
import org.jetbrains.exposed.sql.kotlin.datetime.date
/**
* Exposed table definition for Person entities.
*
* This table represents the database schema for storing person data
* in the member management bounded context.
*/
object PersonTable : UUIDTable("persons") {
// Basic person information
val oepsSatzNr = varchar("oeps_satz_nr", 6).nullable().uniqueIndex()
val nachname = varchar("nachname", 100)
val vorname = varchar("vorname", 100)
val titel = varchar("titel", 50).nullable()
// Personal details
val geburtsdatum = date("geburtsdatum").nullable()
val geschlecht = enumerationByName("geschlecht", 10, GeschlechtE::class).nullable()
val nationalitaetLandId = uuid("nationalitaet_land_id").nullable()
val feiId = varchar("fei_id", 20).nullable()
// Contact information
val telefon = varchar("telefon", 50).nullable()
val email = varchar("email", 100).nullable()
// Address information
val strasse = varchar("strasse", 200).nullable()
val plz = varchar("plz", 10).nullable()
val ort = varchar("ort", 100).nullable()
val adresszusatzZusatzinfo = varchar("adresszusatz_zusatzinfo", 200).nullable()
// Club membership
val stammVereinId = uuid("stamm_verein_id").nullable()
val mitgliedsNummerBeiStammVerein = varchar("mitglieds_nummer_bei_stamm_verein", 50).nullable()
// Status and restrictions
val istGesperrt = bool("ist_gesperrt").default(false)
val sperrGrund = varchar("sperr_grund", 500).nullable()
// OEPS specific data
val altersklasseOepsCodeRaw = varchar("altersklasse_oeps_code_raw", 10).nullable()
val istJungerReiterOepsFlag = bool("ist_junger_reiter_oeps_flag").default(false)
val kaderStatusOepsRaw = varchar("kader_status_oeps_raw", 10).nullable()
// Metadata
val datenQuelle = enumerationByName("daten_quelle", 20, DatenQuelleE::class).default(DatenQuelleE.MANUELL)
val istAktiv = bool("ist_aktiv").default(true)
val notizenIntern = text("notizen_intern").nullable()
// Audit fields
val createdAt = datetime("created_at")
val updatedAt = datetime("updated_at")
}
@@ -1,32 +0,0 @@
package at.mocode.members.infrastructure.repository
import at.mocode.enums.RolleE
import org.jetbrains.exposed.dao.id.UUIDTable
import org.jetbrains.exposed.sql.kotlin.datetime.datetime
/**
* Exposed table definition for Rolle entities.
*
* This table represents the database schema for storing role data
* in the member management bounded context.
*/
object RolleTable : UUIDTable("rollen") {
// Role identification
val rolleTyp = enumerationByName("rolle_typ", 20, RolleE::class)
val name = varchar("name", 100)
val beschreibung = text("beschreibung").nullable()
// Status flags
val istAktiv = bool("ist_aktiv").default(true)
val istSystemRolle = bool("ist_system_rolle").default(false)
// Audit fields
val createdAt = datetime("created_at")
val updatedAt = datetime("updated_at")
// Unique constraint on rolle_typ to ensure each role type exists only once
init {
uniqueIndex(rolleTyp)
}
}
@@ -10,6 +10,12 @@ import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.SqlExpressionBuilder.like
// Import table definition and extension functions
import at.mocode.members.infrastructure.repository.BerechtigungTable
import at.mocode.members.infrastructure.repository.insertOrUpdate
import at.mocode.members.infrastructure.repository.toLocalDateTime
import at.mocode.members.infrastructure.repository.toInstant
/**
* Exposed-based implementation of BerechtigungRepository.
*
@@ -31,8 +37,8 @@ class BerechtigungRepositoryImpl : BerechtigungRepository {
it[aktion] = berechtigung.aktion
it[istAktiv] = berechtigung.istAktiv
it[istSystemBerechtigung] = berechtigung.istSystemBerechtigung
it[createdAt] = berechtigung.createdAt.toJavaInstant()
it[updatedAt] = updatedBerechtigung.updatedAt.toJavaInstant()
it[createdAt] = berechtigung.createdAt.toLocalDateTime()
it[updatedAt] = updatedBerechtigung.updatedAt.toLocalDateTime()
}
return updatedBerechtigung
@@ -80,7 +86,7 @@ class BerechtigungRepositoryImpl : BerechtigungRepository {
val now = Clock.System.now()
val updatedRows = BerechtigungTable.update({ BerechtigungTable.id eq berechtigungId }) {
it[istAktiv] = false
it[updatedAt] = now.toJavaInstant()
it[updatedAt] = now.toLocalDateTime()
}
return updatedRows > 0
}
@@ -114,8 +120,8 @@ class BerechtigungRepositoryImpl : BerechtigungRepository {
aktion = row[BerechtigungTable.aktion],
istAktiv = row[BerechtigungTable.istAktiv],
istSystemBerechtigung = row[BerechtigungTable.istSystemBerechtigung],
createdAt = row[BerechtigungTable.createdAt].toKotlinInstant(),
updatedAt = row[BerechtigungTable.updatedAt].toKotlinInstant()
createdAt = row[BerechtigungTable.createdAt].toInstant(),
updatedAt = row[BerechtigungTable.updatedAt].toInstant()
)
}
}
@@ -0,0 +1,57 @@
package at.mocode.members.infrastructure.repository
import kotlinx.datetime.*
import kotlinx.datetime.toJavaInstant as kotlinxToJavaInstant
import kotlinx.datetime.toKotlinInstant as javaToKotlinInstant
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.InsertStatement
import org.jetbrains.exposed.sql.statements.UpdateStatement
import org.jetbrains.exposed.sql.transactions.TransactionManager
/**
* Extension function to convert Kotlin Instant to LocalDateTime for database storage.
*/
fun Instant.toLocalDateTime(): LocalDateTime = this.toLocalDateTime(TimeZone.UTC)
/**
* Extension function to convert LocalDateTime to Kotlin Instant.
*/
fun LocalDateTime.toInstant(): Instant = this.toInstant(TimeZone.UTC)
/**
* Extension function for upsert (insert or update) operation on tables.
* If a record with the given key exists, it updates it; otherwise, it inserts a new record.
*/
fun <T : Table> T.insertOrUpdate(
vararg keys: Column<*>,
body: T.(InsertStatement<Number>) -> Unit
) = InsertOrUpdate<Number>(this, keys = keys).apply {
body(this)
}.execute(this)
/**
* Custom InsertOrUpdate statement implementation for PostgreSQL.
*/
class InsertOrUpdate<Key : Any>(
table: Table,
isIgnore: Boolean = false,
private vararg val keys: Column<*>
) : InsertStatement<Key>(table, isIgnore) {
override fun prepareSQL(transaction: Transaction, prepared: Boolean): String {
val tm = TransactionManager.current()
val updateSetter = (table.columns - keys.toSet()).joinToString { "${tm.identity(it)} = EXCLUDED.${tm.identity(it)}" }
val keyColumns = keys.joinToString { tm.identity(it) }
val insertSQL = super.prepareSQL(transaction, prepared)
return "$insertSQL ON CONFLICT ($keyColumns) DO UPDATE SET $updateSetter"
}
}
/**
* Extension function to execute the InsertOrUpdate statement.
*/
fun InsertOrUpdate<*>.execute(table: Table): InsertOrUpdate<*> {
TransactionManager.current().exec(this)
return this
}
@@ -10,6 +10,12 @@ import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.SqlExpressionBuilder.like
// Import table definition and extension functions
import at.mocode.members.infrastructure.repository.PersonTable
import at.mocode.members.infrastructure.repository.insertOrUpdate
import at.mocode.members.infrastructure.repository.toLocalDateTime
import at.mocode.members.infrastructure.repository.toInstant
/**
* Exposed-based implementation of PersonRepository.
*
@@ -81,8 +87,8 @@ class PersonRepositoryImpl : PersonRepository {
it[datenQuelle] = person.datenQuelle
it[istAktiv] = person.istAktiv
it[notizenIntern] = person.notizenIntern
it[createdAt] = person.createdAt.toJavaInstant()
it[updatedAt] = updatedPerson.updatedAt.toJavaInstant()
it[createdAt] = person.createdAt.toLocalDateTime()
it[updatedAt] = updatedPerson.updatedAt.toLocalDateTime()
}
return updatedPerson
@@ -133,8 +139,8 @@ class PersonRepositoryImpl : PersonRepository {
datenQuelle = row[PersonTable.datenQuelle],
istAktiv = row[PersonTable.istAktiv],
notizenIntern = row[PersonTable.notizenIntern],
createdAt = row[PersonTable.createdAt].toKotlinInstant(),
updatedAt = row[PersonTable.updatedAt].toKotlinInstant()
createdAt = row[PersonTable.createdAt].toInstant(),
updatedAt = row[PersonTable.updatedAt].toInstant()
)
}
}
@@ -9,6 +9,12 @@ import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.SqlExpressionBuilder.like
// Import table definition and extension functions
import at.mocode.members.infrastructure.repository.VereinTable
import at.mocode.members.infrastructure.repository.insertOrUpdate
import at.mocode.members.infrastructure.repository.toLocalDateTime
import at.mocode.members.infrastructure.repository.toInstant
/**
* Exposed-based implementation of VereinRepository.
*
@@ -85,8 +91,8 @@ class VereinRepositoryImpl : VereinRepository {
it[datenQuelle] = verein.datenQuelle
it[istAktiv] = verein.istAktiv
it[notizenIntern] = verein.notizenIntern
it[createdAt] = verein.createdAt.toJavaInstant()
it[updatedAt] = updatedVerein.updatedAt.toJavaInstant()
it[createdAt] = verein.createdAt.toLocalDateTime()
it[updatedAt] = updatedVerein.updatedAt.toLocalDateTime()
}
return updatedVerein
@@ -134,8 +140,8 @@ class VereinRepositoryImpl : VereinRepository {
datenQuelle = row[VereinTable.datenQuelle],
istAktiv = row[VereinTable.istAktiv],
notizenIntern = row[VereinTable.notizenIntern],
createdAt = row[VereinTable.createdAt].toKotlinInstant(),
updatedAt = row[VereinTable.updatedAt].toKotlinInstant()
createdAt = row[VereinTable.createdAt].toInstant(),
updatedAt = row[VereinTable.updatedAt].toInstant()
)
}
}