chore: remove deprecated horses, clubs, officials, and persons services
- Deleted obsolete modules related to horses, clubs, officials, and persons services, including their configurations, build files, and database provisioning scripts. - Cleaned up associated references in the project structure (e.g., `settings.gradle.kts`). - Removed unused database tables and Spring beans related to these domains. Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinJvm)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.platform.platformDependencies)
|
||||
implementation(projects.core.coreDomain)
|
||||
|
||||
testImplementation(projects.platform.platformTesting)
|
||||
testImplementation(libs.mockk)
|
||||
testImplementation(libs.kotlin.test)
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.identity.domain.model
|
||||
|
||||
import at.mocode.core.domain.serialization.InstantSerializer
|
||||
import at.mocode.core.domain.serialization.UuidSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.Instant
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Domain model representing an extended profile of a user.
|
||||
* This links a Keycloak User ID with an official ZNS Satznummer.
|
||||
*
|
||||
* @property profileId Unique internal identifier.
|
||||
* @property userId The Keycloak User ID (UUID string).
|
||||
* @property satznummer The official ZNS Satznummer (link to master-data-context).
|
||||
* @property logoUrl Optional URL to a logo or profile picture.
|
||||
* @property bio Optional short biography or description.
|
||||
* @property contactEmail Optional contact email (might differ from account email).
|
||||
* @property createdAt Timestamp of creation.
|
||||
* @property updatedAt Timestamp of the last update.
|
||||
*/
|
||||
@Serializable
|
||||
data class DomProfil(
|
||||
@Serializable(with = UuidSerializer::class)
|
||||
val profileId: Uuid = Uuid.random(),
|
||||
|
||||
val userId: String,
|
||||
val satznummer: String,
|
||||
|
||||
val logoUrl: String? = null,
|
||||
val bio: String? = null,
|
||||
val contactEmail: String? = null,
|
||||
|
||||
@Serializable(with = InstantSerializer::class)
|
||||
val createdAt: Instant = Clock.System.now(),
|
||||
@Serializable(with = InstantSerializer::class)
|
||||
var updatedAt: Instant = Clock.System.now()
|
||||
)
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.identity.domain.repository
|
||||
|
||||
import at.mocode.identity.domain.model.DomProfil
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
interface ProfileRepository {
|
||||
suspend fun findById(id: Uuid): DomProfil?
|
||||
suspend fun findByUserId(userId: String): DomProfil?
|
||||
suspend fun findBySatznummer(satznummer: String): List<DomProfil>
|
||||
suspend fun save(profil: DomProfil): DomProfil
|
||||
suspend fun delete(id: Uuid): Boolean
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.identity.domain.service
|
||||
|
||||
import at.mocode.identity.domain.model.DomProfil
|
||||
import at.mocode.identity.domain.repository.ProfileRepository
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Domain service for managing user profiles and ZNS links.
|
||||
*/
|
||||
class ProfileService(
|
||||
private val profileRepository: ProfileRepository
|
||||
) {
|
||||
suspend fun getProfileByUserId(userId: String): DomProfil? {
|
||||
return profileRepository.findByUserId(userId)
|
||||
}
|
||||
|
||||
suspend fun linkUserToZns(userId: String, satznummer: String): DomProfil {
|
||||
val existing = profileRepository.findByUserId(userId)
|
||||
val profil = if (existing != null) {
|
||||
existing.copy(satznummer = satznummer)
|
||||
} else {
|
||||
DomProfil(userId = userId, satznummer = satznummer)
|
||||
}
|
||||
return profileRepository.save(profil)
|
||||
}
|
||||
|
||||
suspend fun updateProfile(userId: String, logoUrl: String?, bio: String?, contactEmail: String?): DomProfil {
|
||||
val profil = profileRepository.findByUserId(userId)
|
||||
?: throw IllegalStateException("Profile for user $userId not found. Link to ZNS first.")
|
||||
|
||||
val updated = profil.copy(
|
||||
logoUrl = logoUrl ?: profil.logoUrl,
|
||||
bio = bio ?: profil.bio,
|
||||
contactEmail = contactEmail ?: profil.contactEmail
|
||||
)
|
||||
return profileRepository.save(updated)
|
||||
}
|
||||
|
||||
suspend fun deleteProfile(profileId: Uuid): Boolean {
|
||||
return profileRepository.delete(profileId)
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.identity.domain.service
|
||||
|
||||
import at.mocode.identity.domain.model.DomProfil
|
||||
import at.mocode.identity.domain.repository.ProfileRepository
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class ProfileServiceTest {
|
||||
|
||||
private val profileRepository = mockk<ProfileRepository>()
|
||||
private val profileService = ProfileService(profileRepository)
|
||||
|
||||
@Test
|
||||
fun `linkUserToZns should create new profile if none exists`() = runBlocking {
|
||||
val userId = "user-123"
|
||||
val satznummer = "0000123456"
|
||||
|
||||
coEvery { profileRepository.findByUserId(userId) } returns null
|
||||
coEvery { profileRepository.save(any()) } answers { it.invocation.args[0] as DomProfil }
|
||||
|
||||
val result = profileService.linkUserToZns(userId, satznummer)
|
||||
|
||||
assertNotNull(result)
|
||||
assertEquals(userId, result.userId)
|
||||
assertEquals(satznummer, result.satznummer)
|
||||
coVerify { profileRepository.save(match { it.userId == userId && it.satznummer == satznummer }) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `linkUserToZns should update existing profile`() = runBlocking {
|
||||
val userId = "user-123"
|
||||
val oldSatz = "old-123"
|
||||
val newSatz = "new-456"
|
||||
val existing = DomProfil(userId = userId, satznummer = oldSatz)
|
||||
|
||||
coEvery { profileRepository.findByUserId(userId) } returns existing
|
||||
coEvery { profileRepository.save(any()) } answers { it.invocation.args[0] as DomProfil }
|
||||
|
||||
val result = profileService.linkUserToZns(userId, newSatz)
|
||||
|
||||
assertEquals(newSatz, result.satznummer)
|
||||
coVerify { profileRepository.save(match { it.userId == userId && it.satznummer == newSatz }) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinJvm)
|
||||
alias(libs.plugins.kotlinSpring)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.platform.platformDependencies)
|
||||
implementation(projects.backend.services.identity.identityDomain)
|
||||
implementation(projects.core.coreDomain)
|
||||
implementation(projects.core.coreUtils)
|
||||
implementation(libs.exposed.core)
|
||||
implementation(libs.exposed.dao)
|
||||
implementation(libs.exposed.jdbc)
|
||||
implementation(libs.exposed.kotlin.datetime)
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
|
||||
package at.mocode.identity.infrastructure.persistence
|
||||
|
||||
import at.mocode.identity.domain.model.DomProfil
|
||||
import at.mocode.identity.domain.repository.ProfileRepository
|
||||
import org.jetbrains.exposed.v1.core.ResultRow
|
||||
import org.jetbrains.exposed.v1.core.eq
|
||||
import org.jetbrains.exposed.v1.core.statements.UpdateBuilder
|
||||
import org.jetbrains.exposed.v1.jdbc.deleteWhere
|
||||
import org.jetbrains.exposed.v1.jdbc.insert
|
||||
import org.jetbrains.exposed.v1.jdbc.selectAll
|
||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
import org.jetbrains.exposed.v1.jdbc.update
|
||||
import kotlin.time.Clock
|
||||
import kotlin.uuid.Uuid
|
||||
import kotlin.uuid.toJavaUuid
|
||||
import kotlin.uuid.toKotlinUuid
|
||||
|
||||
class ExposedProfileRepository : ProfileRepository {
|
||||
|
||||
override suspend fun findById(id: Uuid): DomProfil? = transaction {
|
||||
ProfileTable.selectAll().where { ProfileTable.id eq id.toJavaUuid() }
|
||||
.map { rowToProfile(it) }
|
||||
.singleOrNull()
|
||||
}
|
||||
|
||||
override suspend fun findByUserId(userId: String): DomProfil? = transaction {
|
||||
ProfileTable.selectAll().where { ProfileTable.userId eq userId }
|
||||
.map { rowToProfile(it) }
|
||||
.singleOrNull()
|
||||
}
|
||||
|
||||
override suspend fun findBySatznummer(satznummer: String): List<DomProfil> = transaction {
|
||||
ProfileTable.selectAll().where { ProfileTable.satznummer eq satznummer }
|
||||
.map { rowToProfile(it) }
|
||||
}
|
||||
|
||||
override suspend fun save(profil: DomProfil): DomProfil = transaction {
|
||||
val now = Clock.System.now()
|
||||
val updated = profil.copy(updatedAt = now)
|
||||
val javaId = profil.profileId.toJavaUuid()
|
||||
|
||||
val existing = ProfileTable.selectAll().where { ProfileTable.id eq javaId }.singleOrNull()
|
||||
if (existing != null) {
|
||||
ProfileTable.update({ ProfileTable.id eq javaId }) { profileToStatement(it, updated) }
|
||||
} else {
|
||||
ProfileTable.insert {
|
||||
it[id] = javaId
|
||||
profileToStatement(it, updated)
|
||||
}
|
||||
}
|
||||
updated
|
||||
}
|
||||
|
||||
override suspend fun delete(id: Uuid): Boolean = transaction {
|
||||
ProfileTable.deleteWhere { ProfileTable.id eq id.toJavaUuid() } > 0
|
||||
}
|
||||
|
||||
private fun rowToProfile(row: ResultRow): DomProfil = DomProfil(
|
||||
profileId = row[ProfileTable.id].toKotlinUuid(),
|
||||
userId = row[ProfileTable.userId],
|
||||
satznummer = row[ProfileTable.satznummer],
|
||||
logoUrl = row[ProfileTable.logoUrl],
|
||||
bio = row[ProfileTable.bio],
|
||||
contactEmail = row[ProfileTable.contactEmail],
|
||||
createdAt = row[ProfileTable.createdAt],
|
||||
updatedAt = row[ProfileTable.updatedAt]
|
||||
)
|
||||
|
||||
private fun profileToStatement(stmt: UpdateBuilder<*>, p: DomProfil) {
|
||||
stmt[ProfileTable.userId] = p.userId
|
||||
stmt[ProfileTable.satznummer] = p.satznummer
|
||||
stmt[ProfileTable.logoUrl] = p.logoUrl
|
||||
stmt[ProfileTable.bio] = p.bio
|
||||
stmt[ProfileTable.contactEmail] = p.contactEmail
|
||||
stmt[ProfileTable.createdAt] = p.createdAt
|
||||
stmt[ProfileTable.updatedAt] = p.updatedAt
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package at.mocode.identity.infrastructure.persistence
|
||||
|
||||
import org.jetbrains.exposed.v1.core.Table
|
||||
import org.jetbrains.exposed.v1.core.java.javaUUID
|
||||
import org.jetbrains.exposed.v1.datetime.timestamp
|
||||
|
||||
/**
|
||||
* Exposed Table definition for user profiles.
|
||||
* Links Keycloak user IDs to official ZNS satznummer.
|
||||
*/
|
||||
object ProfileTable : Table("identity_profiles") {
|
||||
val id = javaUUID("id").autoGenerate()
|
||||
override val primaryKey = PrimaryKey(id)
|
||||
|
||||
val userId = varchar("user_id", 100)
|
||||
val satznummer = varchar("satznummer", 20)
|
||||
|
||||
val logoUrl = text("logo_url").nullable()
|
||||
val bio = text("bio").nullable()
|
||||
val contactEmail = varchar("contact_email", 200).nullable()
|
||||
|
||||
val createdAt = timestamp("created_at")
|
||||
val updatedAt = timestamp("updated_at")
|
||||
|
||||
init {
|
||||
index(true, userId)
|
||||
index(false, satznummer)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinJvm)
|
||||
alias(libs.plugins.kotlinSpring)
|
||||
alias(libs.plugins.spring.boot)
|
||||
alias(libs.plugins.spring.dependencyManagement)
|
||||
}
|
||||
|
||||
springBoot {
|
||||
mainClass.set("at.mocode.identity.service.IdentityServiceApplicationKt")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.platform.platformDependencies)
|
||||
implementation(projects.core.coreDomain)
|
||||
implementation(projects.core.coreUtils)
|
||||
implementation(projects.backend.services.identity.identityDomain)
|
||||
implementation(projects.backend.services.identity.identityInfrastructure)
|
||||
|
||||
implementation(libs.spring.boot.starter.web)
|
||||
implementation(libs.spring.boot.starter.validation)
|
||||
implementation(libs.spring.boot.starter.security)
|
||||
implementation(libs.spring.boot.starter.oauth2.resource.server)
|
||||
|
||||
implementation(libs.exposed.core)
|
||||
implementation(libs.exposed.jdbc)
|
||||
implementation(libs.hikari.cp)
|
||||
runtimeOnly(libs.postgresql.driver)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package at.mocode.identity.service
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
@SpringBootApplication(scanBasePackages = ["at.mocode.identity", "at.mocode.infrastructure.security"])
|
||||
class IdentityServiceApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<IdentityServiceApplication>(*args)
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package at.mocode.identity.service.config
|
||||
|
||||
import at.mocode.identity.domain.repository.ProfileRepository
|
||||
import at.mocode.identity.domain.service.ProfileService
|
||||
import at.mocode.identity.infrastructure.persistence.ExposedProfileRepository
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
@Configuration
|
||||
class IdentityConfig {
|
||||
|
||||
@Bean
|
||||
fun profileRepository(): ProfileRepository = ExposedProfileRepository()
|
||||
|
||||
@Bean
|
||||
fun profileService(profileRepository: ProfileRepository): ProfileService =
|
||||
ProfileService(profileRepository)
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package at.mocode.identity.service.web
|
||||
|
||||
import at.mocode.identity.domain.model.DomProfil
|
||||
import at.mocode.identity.domain.service.ProfileService
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.security.oauth2.jwt.Jwt
|
||||
import org.springframework.web.bind.annotation.*
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/profiles")
|
||||
class ProfileController(
|
||||
private val profileService: ProfileService
|
||||
) {
|
||||
|
||||
@GetMapping("/me")
|
||||
suspend fun getMyProfile(@AuthenticationPrincipal jwt: Jwt): DomProfil? {
|
||||
return profileService.getProfileByUserId(jwt.subject)
|
||||
}
|
||||
|
||||
@PostMapping("/link/{satznummer}")
|
||||
suspend fun linkToZns(
|
||||
@AuthenticationPrincipal jwt: Jwt,
|
||||
@PathVariable satznummer: String
|
||||
): DomProfil {
|
||||
return profileService.linkUserToZns(jwt.subject, satznummer)
|
||||
}
|
||||
|
||||
@PutMapping("/me")
|
||||
suspend fun updateMyProfile(
|
||||
@AuthenticationPrincipal jwt: Jwt,
|
||||
@RequestBody request: ProfileUpdateRequest
|
||||
): DomProfil {
|
||||
return profileService.updateProfile(
|
||||
userId = jwt.subject,
|
||||
logoUrl = request.logoUrl,
|
||||
bio = request.bio,
|
||||
contactEmail = request.contactEmail
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class ProfileUpdateRequest(
|
||||
val logoUrl: String? = null,
|
||||
val bio: String? = null,
|
||||
val contactEmail: String? = null
|
||||
)
|
||||
Reference in New Issue
Block a user