(fix) API Endpoints Creation for All Tables
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
# Code Organization Improvements
|
||||
|
||||
This document describes the recent reorganization of the codebase to improve maintainability, extensibility, and clarity.
|
||||
|
||||
## Overview
|
||||
|
||||
The codebase has been restructured to follow better software engineering practices, making it more organized, maintainable, and easier to extend.
|
||||
|
||||
## Key Improvements
|
||||
|
||||
### 1. Service Locator Pattern (`ServiceLocator.kt`)
|
||||
|
||||
**Location**: `server/src/main/kotlin/at/mocode/services/ServiceLocator.kt`
|
||||
|
||||
**Purpose**: Centralized dependency management for repository instances.
|
||||
|
||||
**Benefits**:
|
||||
- Single point of access for all repositories
|
||||
- Easy to switch implementations (e.g., for testing or different databases)
|
||||
- Lazy initialization for better performance
|
||||
- Simplified dependency injection
|
||||
|
||||
**Usage**:
|
||||
```kotlin
|
||||
val artikelRepository = ServiceLocator.artikelRepository
|
||||
val vereinRepository = ServiceLocator.vereinRepository
|
||||
```
|
||||
|
||||
### 2. Standardized API Responses (`ApiResponse.kt`)
|
||||
|
||||
**Location**: `server/src/main/kotlin/at/mocode/utils/ApiResponse.kt`
|
||||
|
||||
**Purpose**: Consistent response format across all API endpoints.
|
||||
|
||||
**Benefits**:
|
||||
- Uniform error handling
|
||||
- Standardized success/error response structure
|
||||
- Reduced code duplication
|
||||
- Better client-side error handling
|
||||
|
||||
**Usage**:
|
||||
```kotlin
|
||||
call.respondSuccess(data)
|
||||
call.respondError("Error message")
|
||||
call.respondNotFound("Resource")
|
||||
```
|
||||
|
||||
### 3. Route Utilities (`RouteUtils.kt`)
|
||||
|
||||
**Location**: `server/src/main/kotlin/at/mocode/utils/RouteUtils.kt`
|
||||
|
||||
**Purpose**: Common route operations and parameter validation.
|
||||
|
||||
**Benefits**:
|
||||
- Consistent parameter validation
|
||||
- Reduced boilerplate code
|
||||
- Standardized error responses
|
||||
- Type-safe parameter extraction
|
||||
|
||||
**Usage**:
|
||||
```kotlin
|
||||
val uuid = call.getUuidParameter("id", "artikel") ?: return
|
||||
val query = call.getQueryParameter("q") ?: return
|
||||
val data = call.safeReceive<Artikel>() ?: return
|
||||
```
|
||||
|
||||
### 4. Centralized Route Configuration (`RouteConfiguration.kt`)
|
||||
|
||||
**Location**: `server/src/main/kotlin/at/mocode/routes/RouteConfiguration.kt`
|
||||
|
||||
**Purpose**: Organized route registration by domain and functionality.
|
||||
|
||||
**Benefits**:
|
||||
- Clear API structure
|
||||
- Logical grouping of related endpoints
|
||||
- Easy to understand and maintain
|
||||
- Scalable for future additions
|
||||
|
||||
**Structure**:
|
||||
```
|
||||
/api
|
||||
├── /artikel (core routes)
|
||||
├── /personen
|
||||
├── /vereine
|
||||
├── /domain
|
||||
│ ├── /lizenzen
|
||||
│ ├── /pferde
|
||||
│ └── /qualifikationen
|
||||
└── /events
|
||||
├── /veranstaltungen
|
||||
├── /turniere
|
||||
├── /bewerbe
|
||||
└── /abteilungen
|
||||
```
|
||||
|
||||
### 5. Configuration Management (`AppConfig.kt`)
|
||||
|
||||
**Location**: `server/src/main/kotlin/at/mocode/config/AppConfig.kt`
|
||||
|
||||
**Purpose**: Centralized application configuration management.
|
||||
|
||||
**Benefits**:
|
||||
- Environment-specific settings
|
||||
- Type-safe configuration
|
||||
- Default values for development
|
||||
- Easy to extend for new settings
|
||||
|
||||
**Features**:
|
||||
- Application info (name, version, environment)
|
||||
- Database configuration
|
||||
- API settings
|
||||
- Security configuration
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### For Existing Routes
|
||||
|
||||
1. **Update Repository Access**:
|
||||
```kotlin
|
||||
// Before
|
||||
val repository = PostgresArtikelRepository()
|
||||
|
||||
// After
|
||||
val repository = ServiceLocator.artikelRepository
|
||||
```
|
||||
|
||||
2. **Update Route Paths**:
|
||||
```kotlin
|
||||
// Before
|
||||
route("/api/artikel") { ... }
|
||||
|
||||
// After
|
||||
route("/artikel") { ... } // /api prefix handled by RouteConfiguration
|
||||
```
|
||||
|
||||
3. **Use Response Utilities**:
|
||||
```kotlin
|
||||
// Before
|
||||
call.respond(HttpStatusCode.OK, data)
|
||||
|
||||
// After
|
||||
call.respondSuccess(data)
|
||||
```
|
||||
|
||||
4. **Use Route Utilities**:
|
||||
```kotlin
|
||||
// Before
|
||||
val id = call.parameters["id"] ?: return@get call.respond(...)
|
||||
val uuid = uuidFrom(id)
|
||||
|
||||
// After
|
||||
val uuid = call.getUuidParameter("id") ?: return
|
||||
```
|
||||
|
||||
### For New Routes
|
||||
|
||||
1. Add repository interface to `ServiceLocator`
|
||||
2. Create route function using utilities
|
||||
3. Register in appropriate section of `RouteConfiguration`
|
||||
4. Update route paths to exclude `/api` prefix
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Repository Pattern
|
||||
- Always use interfaces for repositories
|
||||
- Implement PostgreSQL versions for production
|
||||
- Use ServiceLocator for dependency injection
|
||||
|
||||
### Error Handling
|
||||
- Use ResponseUtils for consistent error responses
|
||||
- Handle common exceptions with `handleException()`
|
||||
- Provide meaningful error messages
|
||||
|
||||
### Route Organization
|
||||
- Group related routes logically
|
||||
- Use descriptive route names
|
||||
- Follow RESTful conventions
|
||||
- Document complex endpoints
|
||||
|
||||
### Configuration
|
||||
- Use AppConfig for all settings
|
||||
- Provide sensible defaults
|
||||
- Support environment-specific overrides
|
||||
- Keep sensitive data in environment variables
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Improvements
|
||||
1. **Authentication & Authorization**
|
||||
- JWT token support
|
||||
- Role-based access control
|
||||
- Session management
|
||||
|
||||
2. **API Documentation**
|
||||
- OpenAPI/Swagger integration
|
||||
- Automatic documentation generation
|
||||
- Interactive API explorer
|
||||
|
||||
3. **Monitoring & Logging**
|
||||
- Structured logging
|
||||
- Performance metrics
|
||||
- Health checks
|
||||
|
||||
4. **Testing Framework**
|
||||
- Unit test utilities
|
||||
- Integration test helpers
|
||||
- Mock repository implementations
|
||||
|
||||
### Extension Points
|
||||
- Add new repositories to ServiceLocator
|
||||
- Extend RouteConfiguration for new domains
|
||||
- Add configuration sections to AppConfig
|
||||
- Create new utility functions as needed
|
||||
|
||||
## Benefits Summary
|
||||
|
||||
1. **Maintainability**: Clear separation of concerns and consistent patterns
|
||||
2. **Extensibility**: Easy to add new features and endpoints
|
||||
3. **Testability**: Dependency injection and clear interfaces
|
||||
4. **Consistency**: Standardized responses and error handling
|
||||
5. **Documentation**: Self-documenting code structure
|
||||
6. **Performance**: Lazy loading and efficient resource management
|
||||
|
||||
This reorganization provides a solid foundation for future development while maintaining backward compatibility and improving code quality.
|
||||
@@ -300,6 +300,152 @@ Delete an article.
|
||||
|
||||
---
|
||||
|
||||
## Horses (Pferde) API
|
||||
|
||||
### GET /api/horses
|
||||
Get all horses.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"pferdId": "uuid",
|
||||
"oepsSatzNrPferd": "string",
|
||||
"oepsKopfNr": "string",
|
||||
"name": "string",
|
||||
"lebensnummer": "string",
|
||||
"feiPassNr": "string",
|
||||
"geburtsjahr": 2015,
|
||||
"geschlecht": "WALLACH|STUTE|HENGST",
|
||||
"farbe": "string",
|
||||
"rasse": "string",
|
||||
"abstammungVaterName": "string",
|
||||
"abstammungMutterName": "string",
|
||||
"abstammungMutterVaterName": "string",
|
||||
"abstammungZusatzInfo": "string",
|
||||
"besitzerPersonId": "uuid",
|
||||
"verantwortlichePersonId": "uuid",
|
||||
"heimatVereinId": "uuid",
|
||||
"letzteZahlungPferdegebuehrJahrOeps": 2023,
|
||||
"stockmassCm": 165,
|
||||
"datenQuelle": "MANUELL|ZNS_IMPORT",
|
||||
"istAktiv": true,
|
||||
"notizenIntern": "string",
|
||||
"createdAt": "2023-01-01T00:00:00Z",
|
||||
"updatedAt": "2023-01-01T00:00:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### GET /api/horses/{id}
|
||||
Get horse by ID.
|
||||
|
||||
**Parameters:**
|
||||
- `id` (path) - UUID of the horse
|
||||
|
||||
### GET /api/horses/oeps/{oepsSatzNr}
|
||||
Get horse by OEPS registration number.
|
||||
|
||||
**Parameters:**
|
||||
- `oepsSatzNr` (path) - OEPS registration number
|
||||
|
||||
### GET /api/horses/lebensnummer/{lebensnummer}
|
||||
Get horse by life number (UELN).
|
||||
|
||||
**Parameters:**
|
||||
- `lebensnummer` (path) - Horse life number
|
||||
|
||||
### GET /api/horses/search?q={query}
|
||||
Search horses by name or other attributes.
|
||||
|
||||
**Parameters:**
|
||||
- `q` (query) - Search query string
|
||||
|
||||
### GET /api/horses/name/{name}
|
||||
Get horses by name.
|
||||
|
||||
**Parameters:**
|
||||
- `name` (path) - Horse name
|
||||
|
||||
### GET /api/horses/owner/{ownerId}
|
||||
Get horses by owner ID.
|
||||
|
||||
**Parameters:**
|
||||
- `ownerId` (path) - UUID of the owner person
|
||||
|
||||
### GET /api/horses/responsible/{personId}
|
||||
Get horses by responsible person ID.
|
||||
|
||||
**Parameters:**
|
||||
- `personId` (path) - UUID of the responsible person
|
||||
|
||||
### GET /api/horses/club/{clubId}
|
||||
Get horses by home club ID.
|
||||
|
||||
**Parameters:**
|
||||
- `clubId` (path) - UUID of the home club
|
||||
|
||||
### GET /api/horses/breed/{breed}
|
||||
Get horses by breed.
|
||||
|
||||
**Parameters:**
|
||||
- `breed` (path) - Horse breed
|
||||
|
||||
### GET /api/horses/birth-year/{year}
|
||||
Get horses by birth year.
|
||||
|
||||
**Parameters:**
|
||||
- `year` (path) - Birth year (integer)
|
||||
|
||||
### GET /api/horses/active
|
||||
Get only active horses.
|
||||
|
||||
### POST /api/horses
|
||||
Create a new horse.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"oepsSatzNrPferd": "string",
|
||||
"oepsKopfNr": "string",
|
||||
"name": "string",
|
||||
"lebensnummer": "string",
|
||||
"feiPassNr": "string",
|
||||
"geburtsjahr": 2015,
|
||||
"geschlecht": "WALLACH",
|
||||
"farbe": "string",
|
||||
"rasse": "string",
|
||||
"abstammungVaterName": "string",
|
||||
"abstammungMutterName": "string",
|
||||
"abstammungMutterVaterName": "string",
|
||||
"abstammungZusatzInfo": "string",
|
||||
"besitzerPersonId": "uuid",
|
||||
"verantwortlichePersonId": "uuid",
|
||||
"heimatVereinId": "uuid",
|
||||
"letzteZahlungPferdegebuehrJahrOeps": 2023,
|
||||
"stockmassCm": 165,
|
||||
"datenQuelle": "MANUELL",
|
||||
"istAktiv": true,
|
||||
"notizenIntern": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### PUT /api/horses/{id}
|
||||
Update an existing horse.
|
||||
|
||||
**Parameters:**
|
||||
- `id` (path) - UUID of the horse
|
||||
|
||||
**Request Body:** Same as POST
|
||||
|
||||
### DELETE /api/horses/{id}
|
||||
Delete a horse.
|
||||
|
||||
**Parameters:**
|
||||
- `id` (path) - UUID of the horse
|
||||
|
||||
---
|
||||
|
||||
## Data Models
|
||||
|
||||
### Person
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
package at.mocode.config
|
||||
|
||||
import io.ktor.server.application.*
|
||||
|
||||
/**
|
||||
* Application configuration management
|
||||
* Centralizes all configuration settings for better maintainability
|
||||
*/
|
||||
object AppConfig {
|
||||
|
||||
/**
|
||||
* Application information
|
||||
*/
|
||||
data class AppInfo(
|
||||
val name: String,
|
||||
val version: String,
|
||||
val environment: String,
|
||||
val description: String
|
||||
)
|
||||
|
||||
/**
|
||||
* Database configuration
|
||||
*/
|
||||
data class DatabaseConfig(
|
||||
val url: String,
|
||||
val driver: String,
|
||||
val user: String,
|
||||
val password: String,
|
||||
val maxPoolSize: Int = 10,
|
||||
val connectionTimeout: Long = 30000
|
||||
)
|
||||
|
||||
/**
|
||||
* API configuration
|
||||
*/
|
||||
data class ApiConfig(
|
||||
val baseUrl: String,
|
||||
val version: String,
|
||||
val enableCors: Boolean = true,
|
||||
val enableSwagger: Boolean = false,
|
||||
val rateLimitEnabled: Boolean = false
|
||||
)
|
||||
|
||||
/**
|
||||
* Security configuration
|
||||
*/
|
||||
data class SecurityConfig(
|
||||
val jwtSecret: String? = null,
|
||||
val jwtIssuer: String? = null,
|
||||
val jwtAudience: String? = null,
|
||||
val sessionTimeout: Long = 3600000, // 1 hour
|
||||
val enableAuthentication: Boolean = false
|
||||
)
|
||||
|
||||
/**
|
||||
* Load configuration from application environment
|
||||
*/
|
||||
fun loadConfig(application: Application): AppConfiguration {
|
||||
val config = application.environment.config
|
||||
|
||||
val appInfo = AppInfo(
|
||||
name = config.propertyOrNull("application.name")?.getString() ?: "Meldestelle API Server",
|
||||
version = config.propertyOrNull("application.version")?.getString() ?: "1.0.0",
|
||||
environment = config.propertyOrNull("application.environment")?.getString() ?: "development",
|
||||
description = config.propertyOrNull("application.description")?.getString() ?: "Equestrian Event Management API"
|
||||
)
|
||||
|
||||
val databaseConfig = DatabaseConfig(
|
||||
url = config.propertyOrNull("database.url")?.getString() ?: "jdbc:postgresql://localhost:5432/meldestelle",
|
||||
driver = config.propertyOrNull("database.driver")?.getString() ?: "org.postgresql.Driver",
|
||||
user = config.propertyOrNull("database.user")?.getString() ?: "postgres",
|
||||
password = config.propertyOrNull("database.password")?.getString() ?: "password",
|
||||
maxPoolSize = config.propertyOrNull("database.maxPoolSize")?.getString()?.toIntOrNull() ?: 10,
|
||||
connectionTimeout = config.propertyOrNull("database.connectionTimeout")?.getString()?.toLongOrNull() ?: 30000
|
||||
)
|
||||
|
||||
val apiConfig = ApiConfig(
|
||||
baseUrl = config.propertyOrNull("api.baseUrl")?.getString() ?: "http://localhost:8080",
|
||||
version = config.propertyOrNull("api.version")?.getString() ?: "v1",
|
||||
enableCors = config.propertyOrNull("api.enableCors")?.getString()?.toBoolean() ?: true,
|
||||
enableSwagger = config.propertyOrNull("api.enableSwagger")?.getString()?.toBoolean() ?: (appInfo.environment == "development"),
|
||||
rateLimitEnabled = config.propertyOrNull("api.rateLimitEnabled")?.getString()?.toBoolean() ?: false
|
||||
)
|
||||
|
||||
val securityConfig = SecurityConfig(
|
||||
jwtSecret = config.propertyOrNull("security.jwt.secret")?.getString(),
|
||||
jwtIssuer = config.propertyOrNull("security.jwt.issuer")?.getString(),
|
||||
jwtAudience = config.propertyOrNull("security.jwt.audience")?.getString(),
|
||||
sessionTimeout = config.propertyOrNull("security.sessionTimeout")?.getString()?.toLongOrNull() ?: 3600000,
|
||||
enableAuthentication = config.propertyOrNull("security.enableAuthentication")?.getString()?.toBoolean() ?: false
|
||||
)
|
||||
|
||||
return AppConfiguration(appInfo, databaseConfig, apiConfig, securityConfig)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete application configuration
|
||||
*/
|
||||
data class AppConfiguration(
|
||||
val app: AppConfig.AppInfo,
|
||||
val database: AppConfig.DatabaseConfig,
|
||||
val api: AppConfig.ApiConfig,
|
||||
val security: AppConfig.SecurityConfig
|
||||
) {
|
||||
/**
|
||||
* Check if running in development mode
|
||||
*/
|
||||
val isDevelopment: Boolean
|
||||
get() = app.environment.lowercase() == "development"
|
||||
|
||||
/**
|
||||
* Check if running in production mode
|
||||
*/
|
||||
val isProduction: Boolean
|
||||
get() = app.environment.lowercase() == "production"
|
||||
|
||||
/**
|
||||
* Get application info string for API endpoint
|
||||
*/
|
||||
fun getAppInfoString(): String {
|
||||
return "${app.name} v${app.version} - Running in ${app.environment} mode"
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
package at.mocode.model
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
package at.mocode.plugins
|
||||
|
||||
import at.mocode.tables.ArtikelTable
|
||||
import at.mocode.tables.PlaetzeTable
|
||||
import at.mocode.tables.TurniereTable
|
||||
import at.mocode.tables.VeranstaltungenTable
|
||||
import at.mocode.tables.domaene.DomQualifikationTable
|
||||
import at.mocode.tables.stammdaten.LizenzenTable
|
||||
import at.mocode.tables.stammdaten.PersonenTable
|
||||
import at.mocode.tables.stammdaten.PferdeTable
|
||||
import at.mocode.tables.stammdaten.VereineTable
|
||||
import com.zaxxer.hikari.HikariConfig
|
||||
import com.zaxxer.hikari.HikariDataSource
|
||||
import io.ktor.server.application.*
|
||||
@@ -22,7 +31,7 @@ import java.util.concurrent.TimeUnit
|
||||
*/
|
||||
fun Application.configureDatabase() {
|
||||
val log = LoggerFactory.getLogger("DatabaseInitialization")
|
||||
var connectionSuccessful = false
|
||||
var connectionSuccessful: Boolean
|
||||
|
||||
// Environment detection
|
||||
val isTestEnvironment = System.getProperty("isTestEnvironment")?.toBoolean() ?: false
|
||||
@@ -32,7 +41,7 @@ fun Application.configureDatabase() {
|
||||
// Get database configuration from application.yaml if available
|
||||
val dbConfig = try {
|
||||
environment.config.config("database")
|
||||
} catch (e: ApplicationConfigurationException) {
|
||||
} catch (_: ApplicationConfigurationException) {
|
||||
log.warn("No database configuration found in application.yaml, using environment variables")
|
||||
null
|
||||
}
|
||||
@@ -51,7 +60,7 @@ fun Application.configureDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize schema if connection was successful
|
||||
// Initialize schema if the connection was successful
|
||||
if (connectionSuccessful) {
|
||||
initializeSchema(log, isTestEnvironment, isIdeaEnvironment)
|
||||
} else {
|
||||
@@ -174,14 +183,15 @@ private fun initializeSchema(log: Logger, isTestEnvironment: Boolean, isIdeaEnvi
|
||||
try {
|
||||
// Create all tables if they don't exist
|
||||
SchemaUtils.create(
|
||||
_root_ide_package_.at.mocode.tables.VereineTable,
|
||||
_root_ide_package_.at.mocode.tables.PersonenTable,
|
||||
_root_ide_package_.at.mocode.tables.PferdeTable,
|
||||
_root_ide_package_.at.mocode.tables.VeranstaltungenTable,
|
||||
_root_ide_package_.at.mocode.tables.TurniereTable,
|
||||
_root_ide_package_.at.mocode.tables.ArtikelTable,
|
||||
_root_ide_package_.at.mocode.tables.PlaetzeTable,
|
||||
_root_ide_package_.at.mocode.tables.LizenzenTable
|
||||
VereineTable,
|
||||
PersonenTable,
|
||||
PferdeTable,
|
||||
VeranstaltungenTable,
|
||||
TurniereTable,
|
||||
ArtikelTable,
|
||||
PlaetzeTable,
|
||||
LizenzenTable,
|
||||
DomQualifikationTable
|
||||
// Add more tables here if needed
|
||||
)
|
||||
log.info("Database schema initialized successfully.")
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
package at.mocode.plugins
|
||||
|
||||
import at.mocode.routes.artikelRoutes
|
||||
import at.mocode.routes.domLizenzRoutes
|
||||
import at.mocode.routes.personRoutes
|
||||
import at.mocode.routes.vereinRoutes
|
||||
import at.mocode.config.AppConfig
|
||||
import at.mocode.routes.RouteConfiguration.configureApiRoutes
|
||||
import io.ktor.server.application.Application
|
||||
import io.ktor.server.http.content.staticResources
|
||||
import io.ktor.server.response.respondText
|
||||
import io.ktor.server.routing.application
|
||||
import io.ktor.server.routing.get
|
||||
import io.ktor.server.routing.routing
|
||||
|
||||
/**
|
||||
* Configures all routes for the application
|
||||
* Configures all routes for the application using the centralized route configuration
|
||||
*/
|
||||
fun Application.configureRouting() {
|
||||
// Load application configuration
|
||||
val appConfig = AppConfig.loadConfig(this)
|
||||
|
||||
routing {
|
||||
// Health check endpoint
|
||||
get("/health") {
|
||||
@@ -26,18 +26,10 @@ fun Application.configureRouting() {
|
||||
|
||||
// Root endpoint with basic information (API info endpoint)
|
||||
get("/api") {
|
||||
// Read application info from config if available
|
||||
val appName = application.environment.config.propertyOrNull("application.name")?.getString() ?: "Meldestelle API Server"
|
||||
val appVersion = application.environment.config.propertyOrNull("application.version")?.getString() ?: "1.0.0"
|
||||
val appEnv = application.environment.config.propertyOrNull("application.environment")?.getString() ?: "development"
|
||||
|
||||
call.respondText("$appName v$appVersion - Running in $appEnv mode")
|
||||
call.respondText(appConfig.getAppInfoString())
|
||||
}
|
||||
|
||||
// API routes
|
||||
personRoutes()
|
||||
vereinRoutes()
|
||||
artikelRoutes()
|
||||
domLizenzRoutes()
|
||||
// Configure all API routes using the centralized configuration
|
||||
configureApiRoutes()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
package at.mocode.plugins
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.Abteilung
|
||||
import com.benasher44.uuid.Uuid
|
||||
|
||||
interface AbteilungRepository {
|
||||
suspend fun findAll(): List<Abteilung>
|
||||
suspend fun findById(id: Uuid): Abteilung?
|
||||
suspend fun findByBewerbId(bewerbId: Uuid): List<Abteilung>
|
||||
suspend fun create(abteilung: Abteilung): Abteilung
|
||||
suspend fun update(id: Uuid, abteilung: Abteilung): Abteilung?
|
||||
suspend fun delete(id: Uuid): Boolean
|
||||
suspend fun search(query: String): List<Abteilung>
|
||||
suspend fun findByAktiv(istAktiv: Boolean): List<Abteilung>
|
||||
}
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.Artikel
|
||||
import com.benasher44.uuid.Uuid
|
||||
|
||||
interface ArtikelRepository {
|
||||
@@ -0,0 +1,18 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.Bewerb
|
||||
import com.benasher44.uuid.Uuid
|
||||
|
||||
interface BewerbRepository {
|
||||
suspend fun findAll(): List<Bewerb>
|
||||
suspend fun findById(id: Uuid): Bewerb?
|
||||
suspend fun findByTurnierId(turnierId: Uuid): List<Bewerb>
|
||||
suspend fun findBySparte(sparte: String): List<Bewerb>
|
||||
suspend fun findByKlasse(klasse: String): List<Bewerb>
|
||||
suspend fun create(bewerb: Bewerb): Bewerb
|
||||
suspend fun update(id: Uuid, bewerb: Bewerb): Bewerb?
|
||||
suspend fun delete(id: Uuid): Boolean
|
||||
suspend fun search(query: String): List<Bewerb>
|
||||
suspend fun findByStartlisteFinal(istFinal: Boolean): List<Bewerb>
|
||||
suspend fun findByErgebnislisteFinal(istFinal: Boolean): List<Bewerb>
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.domaene.DomLizenz
|
||||
import com.benasher44.uuid.Uuid
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.domaene.DomPferd
|
||||
import com.benasher44.uuid.Uuid
|
||||
@@ -0,0 +1,18 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.domaene.DomQualifikation
|
||||
import com.benasher44.uuid.Uuid
|
||||
import kotlinx.datetime.LocalDate
|
||||
|
||||
interface DomQualifikationRepository {
|
||||
suspend fun findAll(): List<DomQualifikation>
|
||||
suspend fun findById(id: Uuid): DomQualifikation?
|
||||
suspend fun findByPersonId(personId: Uuid): List<DomQualifikation>
|
||||
suspend fun findByQualTypId(qualTypId: Uuid): List<DomQualifikation>
|
||||
suspend fun findActiveByPersonId(personId: Uuid): List<DomQualifikation>
|
||||
suspend fun findByValidityPeriod(fromDate: LocalDate?, toDate: LocalDate?): List<DomQualifikation>
|
||||
suspend fun create(domQualifikation: DomQualifikation): DomQualifikation
|
||||
suspend fun update(id: Uuid, domQualifikation: DomQualifikation): DomQualifikation?
|
||||
suspend fun delete(id: Uuid): Boolean
|
||||
suspend fun search(query: String): List<DomQualifikation>
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
interface EventRepository {
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.stammdaten.Person
|
||||
import com.benasher44.uuid.Uuid
|
||||
@@ -0,0 +1,156 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.enums.BeginnzeitTypE
|
||||
import at.mocode.model.Abteilung
|
||||
import at.mocode.tables.AbteilungTable
|
||||
import com.benasher44.uuid.Uuid
|
||||
import com.ionspin.kotlin.bignum.decimal.BigDecimal
|
||||
import kotlinx.datetime.Clock
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import java.math.BigDecimal as JavaBigDecimal
|
||||
|
||||
class PostgresAbteilungRepository : AbteilungRepository {
|
||||
|
||||
override suspend fun findAll(): List<Abteilung> = transaction {
|
||||
AbteilungTable.selectAll().map { rowToAbteilung(it) }
|
||||
}
|
||||
|
||||
override suspend fun findById(id: Uuid): Abteilung? = transaction {
|
||||
AbteilungTable.selectAll().where { AbteilungTable.id eq id }
|
||||
.map { rowToAbteilung(it) }
|
||||
.singleOrNull()
|
||||
}
|
||||
|
||||
override suspend fun findByBewerbId(bewerbId: Uuid): List<Abteilung> = transaction {
|
||||
AbteilungTable.selectAll().where { AbteilungTable.bewerbId eq bewerbId }
|
||||
.map { rowToAbteilung(it) }
|
||||
}
|
||||
|
||||
override suspend fun create(abteilung: Abteilung): Abteilung = transaction {
|
||||
val now = Clock.System.now()
|
||||
AbteilungTable.insert {
|
||||
it[id] = abteilung.id
|
||||
it[bewerbId] = abteilung.bewerbId
|
||||
it[abteilungsKennzeichen] = abteilung.abteilungsKennzeichen
|
||||
it[bezeichnungIntern] = abteilung.bezeichnungIntern
|
||||
it[bezeichnungAufStartliste] = abteilung.bezeichnungAufStartliste
|
||||
it[teilungsKriteriumLizenz] = abteilung.teilungsKriteriumLizenz
|
||||
it[teilungsKriteriumPferdealter] = abteilung.teilungsKriteriumPferdealter
|
||||
it[teilungsKriteriumAltersklasseReiter] = abteilung.teilungsKriteriumAltersklasseReiter
|
||||
it[teilungsKriteriumAnzahlMin] = abteilung.teilungsKriteriumAnzahlMin
|
||||
it[teilungsKriteriumAnzahlMax] = abteilung.teilungsKriteriumAnzahlMax
|
||||
it[teilungsKriteriumFreiText] = abteilung.teilungsKriteriumFreiText
|
||||
it[startgeld] = abteilung.startgeld?.let { bg -> JavaBigDecimal(bg.toStringExpanded()) }
|
||||
it[platzId] = abteilung.platzId
|
||||
it[datum] = abteilung.datum
|
||||
it[beginnzeitTypE] = abteilung.beginnzeitTypE.name
|
||||
it[beginnzeitFix] = abteilung.beginnzeitFix
|
||||
it[beginnNachAbteilungId] = abteilung.beginnNachAbteilungId
|
||||
it[beginnzeitCa] = abteilung.beginnzeitCa
|
||||
it[dauerProStartGeschaetztSek] = abteilung.dauerProStartGeschaetztSek
|
||||
it[umbauzeitNachAbteilungMin] = abteilung.umbauzeitNachAbteilungMin
|
||||
it[besichtigungszeitVorAbteilungMin] = abteilung.besichtigungszeitVorAbteilungMin
|
||||
it[stechzeitZusaetzlichMin] = abteilung.stechzeitZusaetzlichMin
|
||||
it[anzahlStarter] = abteilung.anzahlStarter
|
||||
it[istAktiv] = abteilung.istAktiv
|
||||
it[createdAt] = now
|
||||
it[updatedAt] = now
|
||||
}
|
||||
abteilung.copy(createdAt = now, updatedAt = now)
|
||||
}
|
||||
|
||||
override suspend fun update(id: Uuid, abteilung: Abteilung): Abteilung? = transaction {
|
||||
val updateCount = AbteilungTable.update({ AbteilungTable.id eq id }) {
|
||||
it[bewerbId] = abteilung.bewerbId
|
||||
it[abteilungsKennzeichen] = abteilung.abteilungsKennzeichen
|
||||
it[bezeichnungIntern] = abteilung.bezeichnungIntern
|
||||
it[bezeichnungAufStartliste] = abteilung.bezeichnungAufStartliste
|
||||
it[teilungsKriteriumLizenz] = abteilung.teilungsKriteriumLizenz
|
||||
it[teilungsKriteriumPferdealter] = abteilung.teilungsKriteriumPferdealter
|
||||
it[teilungsKriteriumAltersklasseReiter] = abteilung.teilungsKriteriumAltersklasseReiter
|
||||
it[teilungsKriteriumAnzahlMin] = abteilung.teilungsKriteriumAnzahlMin
|
||||
it[teilungsKriteriumAnzahlMax] = abteilung.teilungsKriteriumAnzahlMax
|
||||
it[teilungsKriteriumFreiText] = abteilung.teilungsKriteriumFreiText
|
||||
it[startgeld] = abteilung.startgeld?.let { bg -> JavaBigDecimal(bg.toStringExpanded()) }
|
||||
it[platzId] = abteilung.platzId
|
||||
it[datum] = abteilung.datum
|
||||
it[beginnzeitTypE] = abteilung.beginnzeitTypE.name
|
||||
it[beginnzeitFix] = abteilung.beginnzeitFix
|
||||
it[beginnNachAbteilungId] = abteilung.beginnNachAbteilungId
|
||||
it[beginnzeitCa] = abteilung.beginnzeitCa
|
||||
it[dauerProStartGeschaetztSek] = abteilung.dauerProStartGeschaetztSek
|
||||
it[umbauzeitNachAbteilungMin] = abteilung.umbauzeitNachAbteilungMin
|
||||
it[besichtigungszeitVorAbteilungMin] = abteilung.besichtigungszeitVorAbteilungMin
|
||||
it[stechzeitZusaetzlichMin] = abteilung.stechzeitZusaetzlichMin
|
||||
it[anzahlStarter] = abteilung.anzahlStarter
|
||||
it[istAktiv] = abteilung.istAktiv
|
||||
it[updatedAt] = Clock.System.now()
|
||||
}
|
||||
if (updateCount > 0) {
|
||||
AbteilungTable.selectAll().where { AbteilungTable.id eq id }
|
||||
.map { rowToAbteilung(it) }
|
||||
.singleOrNull()
|
||||
} else null
|
||||
}
|
||||
|
||||
override suspend fun delete(id: Uuid): Boolean = transaction {
|
||||
AbteilungTable.deleteWhere { AbteilungTable.id eq id } > 0
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<Abteilung> = transaction {
|
||||
AbteilungTable.selectAll().where {
|
||||
(AbteilungTable.abteilungsKennzeichen.lowerCase() like "%${query.lowercase()}%") or
|
||||
(AbteilungTable.bezeichnungIntern?.lowerCase()?.like("%${query.lowercase()}%") ?: Op.FALSE) or
|
||||
(AbteilungTable.bezeichnungAufStartliste?.lowerCase()?.like("%${query.lowercase()}%") ?: Op.FALSE)
|
||||
}.map { rowToAbteilung(it) }
|
||||
}
|
||||
|
||||
override suspend fun findByAktiv(istAktiv: Boolean): List<Abteilung> = transaction {
|
||||
AbteilungTable.selectAll().where { AbteilungTable.istAktiv eq istAktiv }
|
||||
.map { rowToAbteilung(it) }
|
||||
}
|
||||
|
||||
private fun rowToAbteilung(row: ResultRow): Abteilung {
|
||||
return Abteilung(
|
||||
id = row[AbteilungTable.id],
|
||||
bewerbId = row[AbteilungTable.bewerbId],
|
||||
abteilungsKennzeichen = row[AbteilungTable.abteilungsKennzeichen],
|
||||
bezeichnungIntern = row[AbteilungTable.bezeichnungIntern],
|
||||
bezeichnungAufStartliste = row[AbteilungTable.bezeichnungAufStartliste],
|
||||
teilungsKriteriumLizenz = row[AbteilungTable.teilungsKriteriumLizenz],
|
||||
teilungsKriteriumPferdealter = row[AbteilungTable.teilungsKriteriumPferdealter],
|
||||
teilungsKriteriumAltersklasseReiter = row[AbteilungTable.teilungsKriteriumAltersklasseReiter],
|
||||
teilungsKriteriumAnzahlMin = row[AbteilungTable.teilungsKriteriumAnzahlMin],
|
||||
teilungsKriteriumAnzahlMax = row[AbteilungTable.teilungsKriteriumAnzahlMax],
|
||||
teilungsKriteriumFreiText = row[AbteilungTable.teilungsKriteriumFreiText],
|
||||
startgeld = row[AbteilungTable.startgeld]?.let {
|
||||
try {
|
||||
BigDecimal.parseString(it.toString())
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
},
|
||||
dotierungen = emptyList(), // TODO: Load from related table when implemented
|
||||
platzId = row[AbteilungTable.platzId],
|
||||
datum = row[AbteilungTable.datum],
|
||||
beginnzeitTypE = try {
|
||||
BeginnzeitTypE.valueOf(row[AbteilungTable.beginnzeitTypE])
|
||||
} catch (_: Exception) {
|
||||
BeginnzeitTypE.ANSCHLIESSEND
|
||||
},
|
||||
beginnzeitFix = row[AbteilungTable.beginnzeitFix],
|
||||
beginnNachAbteilungId = row[AbteilungTable.beginnNachAbteilungId],
|
||||
beginnzeitCa = row[AbteilungTable.beginnzeitCa],
|
||||
dauerProStartGeschaetztSek = row[AbteilungTable.dauerProStartGeschaetztSek],
|
||||
umbauzeitNachAbteilungMin = row[AbteilungTable.umbauzeitNachAbteilungMin],
|
||||
besichtigungszeitVorAbteilungMin = row[AbteilungTable.besichtigungszeitVorAbteilungMin],
|
||||
stechzeitZusaetzlichMin = row[AbteilungTable.stechzeitZusaetzlichMin],
|
||||
anzahlStarter = row[AbteilungTable.anzahlStarter],
|
||||
istAktiv = row[AbteilungTable.istAktiv],
|
||||
createdAt = row[AbteilungTable.createdAt],
|
||||
updatedAt = row[AbteilungTable.updatedAt]
|
||||
)
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.Artikel
|
||||
import at.mocode.tables.ArtikelTable
|
||||
import com.benasher44.uuid.Uuid
|
||||
import com.ionspin.kotlin.bignum.decimal.BigDecimal
|
||||
@@ -0,0 +1,61 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.Bewerb
|
||||
import com.benasher44.uuid.Uuid
|
||||
|
||||
class PostgresBewerbRepository : BewerbRepository {
|
||||
override suspend fun findAll(): List<Bewerb> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun findById(id: Uuid): Bewerb? {
|
||||
// TODO: Implement database operations
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun findByTurnierId(turnierId: Uuid): List<Bewerb> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun findBySparte(sparte: String): List<Bewerb> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun findByKlasse(klasse: String): List<Bewerb> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun create(bewerb: Bewerb): Bewerb {
|
||||
// TODO: Implement database operations
|
||||
return bewerb
|
||||
}
|
||||
|
||||
override suspend fun update(id: Uuid, bewerb: Bewerb): Bewerb? {
|
||||
// TODO: Implement database operations
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun delete(id: Uuid): Boolean {
|
||||
// TODO: Implement database operations
|
||||
return false
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<Bewerb> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun findByStartlisteFinal(istFinal: Boolean): List<Bewerb> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun findByErgebnislisteFinal(istFinal: Boolean): List<Bewerb> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -1,9 +1,8 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.domaene.DomLizenz
|
||||
import at.mocode.tables.DomLizenzTable
|
||||
import at.mocode.tables.domaene.DomLizenzTable
|
||||
import com.benasher44.uuid.Uuid
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import kotlinx.datetime.Clock
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
+2
-3
@@ -1,12 +1,11 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.domaene.DomPferd
|
||||
import at.mocode.tables.DomPferdTable
|
||||
import at.mocode.tables.domaene.DomPferdTable
|
||||
import com.benasher44.uuid.Uuid
|
||||
import kotlinx.datetime.Clock
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.like
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
class PostgresDomPferdRepository : DomPferdRepository {
|
||||
@@ -0,0 +1,115 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.domaene.DomQualifikation
|
||||
import at.mocode.tables.domaene.DomQualifikationTable
|
||||
import com.benasher44.uuid.Uuid
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.LocalDate
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
class PostgresDomQualifikationRepository : DomQualifikationRepository {
|
||||
|
||||
override suspend fun findAll(): List<DomQualifikation> = transaction {
|
||||
DomQualifikationTable.selectAll().map { rowToDomQualifikation(it) }
|
||||
}
|
||||
|
||||
override suspend fun findById(id: Uuid): DomQualifikation? = transaction {
|
||||
DomQualifikationTable.select { DomQualifikationTable.qualifikationId eq id }
|
||||
.map { rowToDomQualifikation(it) }
|
||||
.singleOrNull()
|
||||
}
|
||||
|
||||
override suspend fun findByPersonId(personId: Uuid): List<DomQualifikation> = transaction {
|
||||
DomQualifikationTable.select { DomQualifikationTable.personId eq personId }
|
||||
.map { rowToDomQualifikation(it) }
|
||||
}
|
||||
|
||||
override suspend fun findByQualTypId(qualTypId: Uuid): List<DomQualifikation> = transaction {
|
||||
DomQualifikationTable.select { DomQualifikationTable.qualTypId eq qualTypId }
|
||||
.map { rowToDomQualifikation(it) }
|
||||
}
|
||||
|
||||
override suspend fun findActiveByPersonId(personId: Uuid): List<DomQualifikation> = transaction {
|
||||
DomQualifikationTable.select {
|
||||
(DomQualifikationTable.personId eq personId) and (DomQualifikationTable.istAktiv eq true)
|
||||
}.map { rowToDomQualifikation(it) }
|
||||
}
|
||||
|
||||
override suspend fun findByValidityPeriod(fromDate: LocalDate?, toDate: LocalDate?): List<DomQualifikation> = transaction {
|
||||
var query = DomQualifikationTable.selectAll()
|
||||
|
||||
if (fromDate != null) {
|
||||
query = query.andWhere {
|
||||
DomQualifikationTable.gueltigVon.isNull() or (DomQualifikationTable.gueltigVon greaterEq fromDate)
|
||||
}
|
||||
}
|
||||
|
||||
if (toDate != null) {
|
||||
query = query.andWhere {
|
||||
DomQualifikationTable.gueltigBis.isNull() or (DomQualifikationTable.gueltigBis lessEq toDate)
|
||||
}
|
||||
}
|
||||
|
||||
query.map { rowToDomQualifikation(it) }
|
||||
}
|
||||
|
||||
override suspend fun create(domQualifikation: DomQualifikation): DomQualifikation = transaction {
|
||||
val now = Clock.System.now()
|
||||
DomQualifikationTable.insert {
|
||||
it[qualifikationId] = domQualifikation.qualifikationId
|
||||
it[personId] = domQualifikation.personId
|
||||
it[qualTypId] = domQualifikation.qualTypId
|
||||
it[bemerkung] = domQualifikation.bemerkung
|
||||
it[gueltigVon] = domQualifikation.gueltigVon
|
||||
it[gueltigBis] = domQualifikation.gueltigBis
|
||||
it[istAktiv] = domQualifikation.istAktiv
|
||||
it[createdAt] = domQualifikation.createdAt
|
||||
it[updatedAt] = now
|
||||
}
|
||||
domQualifikation.copy(updatedAt = now)
|
||||
}
|
||||
|
||||
override suspend fun update(id: Uuid, domQualifikation: DomQualifikation): DomQualifikation? = transaction {
|
||||
val now = Clock.System.now()
|
||||
val updateCount = DomQualifikationTable.update({ DomQualifikationTable.qualifikationId eq id }) {
|
||||
it[personId] = domQualifikation.personId
|
||||
it[qualTypId] = domQualifikation.qualTypId
|
||||
it[bemerkung] = domQualifikation.bemerkung
|
||||
it[gueltigVon] = domQualifikation.gueltigVon
|
||||
it[gueltigBis] = domQualifikation.gueltigBis
|
||||
it[istAktiv] = domQualifikation.istAktiv
|
||||
it[updatedAt] = now
|
||||
}
|
||||
if (updateCount > 0) {
|
||||
domQualifikation.copy(qualifikationId = id, updatedAt = now)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun delete(id: Uuid): Boolean = transaction {
|
||||
DomQualifikationTable.deleteWhere { qualifikationId eq id } > 0
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<DomQualifikation> = transaction {
|
||||
DomQualifikationTable.select {
|
||||
DomQualifikationTable.bemerkung like "%$query%"
|
||||
}.map { rowToDomQualifikation(it) }
|
||||
}
|
||||
|
||||
private fun rowToDomQualifikation(row: ResultRow): DomQualifikation {
|
||||
return DomQualifikation(
|
||||
qualifikationId = row[DomQualifikationTable.qualifikationId],
|
||||
personId = row[DomQualifikationTable.personId],
|
||||
qualTypId = row[DomQualifikationTable.qualTypId],
|
||||
bemerkung = row[DomQualifikationTable.bemerkung],
|
||||
gueltigVon = row[DomQualifikationTable.gueltigVon],
|
||||
gueltigBis = row[DomQualifikationTable.gueltigBis],
|
||||
istAktiv = row[DomQualifikationTable.istAktiv],
|
||||
createdAt = row[DomQualifikationTable.createdAt],
|
||||
updatedAt = row[DomQualifikationTable.updatedAt]
|
||||
)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
class PostgresEventRepository {
|
||||
}
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.enums.FunktionaerRolle
|
||||
import at.mocode.stammdaten.Person
|
||||
import at.mocode.tables.PersonenTable
|
||||
import at.mocode.tables.stammdaten.PersonenTable
|
||||
import com.benasher44.uuid.Uuid
|
||||
import kotlinx.datetime.Clock
|
||||
import org.jetbrains.exposed.sql.*
|
||||
@@ -0,0 +1,46 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.Turnier
|
||||
import com.benasher44.uuid.Uuid
|
||||
|
||||
class PostgresTurnierRepository : TurnierRepository {
|
||||
override suspend fun findAll(): List<Turnier> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun findById(id: Uuid): Turnier? {
|
||||
// TODO: Implement database operations
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun findByVeranstaltungId(veranstaltungId: Uuid): List<Turnier> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun findByOepsTurnierNr(oepsTurnierNr: String): Turnier? {
|
||||
// TODO: Implement database operations
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun create(turnier: Turnier): Turnier {
|
||||
// TODO: Implement database operations
|
||||
return turnier
|
||||
}
|
||||
|
||||
override suspend fun update(id: Uuid, turnier: Turnier): Turnier? {
|
||||
// TODO: Implement database operations
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun delete(id: Uuid): Boolean {
|
||||
// TODO: Implement database operations
|
||||
return false
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<Turnier> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.Veranstaltung
|
||||
import com.benasher44.uuid.Uuid
|
||||
|
||||
class PostgresVeranstaltungRepository : VeranstaltungRepository {
|
||||
override suspend fun findAll(): List<Veranstaltung> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun findById(id: Uuid): Veranstaltung? {
|
||||
// TODO: Implement database operations
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun findByName(name: String): List<Veranstaltung> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun findByVeranstalterOepsNummer(oepsNummer: String): List<Veranstaltung> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun create(veranstaltung: Veranstaltung): Veranstaltung {
|
||||
// TODO: Implement database operations
|
||||
return veranstaltung
|
||||
}
|
||||
|
||||
override suspend fun update(id: Uuid, veranstaltung: Veranstaltung): Veranstaltung? {
|
||||
// TODO: Implement database operations
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun delete(id: Uuid): Boolean {
|
||||
// TODO: Implement database operations
|
||||
return false
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<Veranstaltung> {
|
||||
// TODO: Implement database operations
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.stammdaten.Verein
|
||||
import at.mocode.tables.VereineTable
|
||||
import at.mocode.tables.stammdaten.VereineTable
|
||||
import com.benasher44.uuid.Uuid
|
||||
import kotlinx.datetime.Clock
|
||||
import org.jetbrains.exposed.sql.*
|
||||
@@ -0,0 +1,15 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.Turnier
|
||||
import com.benasher44.uuid.Uuid
|
||||
|
||||
interface TurnierRepository {
|
||||
suspend fun findAll(): List<Turnier>
|
||||
suspend fun findById(id: Uuid): Turnier?
|
||||
suspend fun findByVeranstaltungId(veranstaltungId: Uuid): List<Turnier>
|
||||
suspend fun findByOepsTurnierNr(oepsTurnierNr: String): Turnier?
|
||||
suspend fun create(turnier: Turnier): Turnier
|
||||
suspend fun update(id: Uuid, turnier: Turnier): Turnier?
|
||||
suspend fun delete(id: Uuid): Boolean
|
||||
suspend fun search(query: String): List<Turnier>
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.model.Veranstaltung
|
||||
import com.benasher44.uuid.Uuid
|
||||
|
||||
interface VeranstaltungRepository {
|
||||
suspend fun findAll(): List<Veranstaltung>
|
||||
suspend fun findById(id: Uuid): Veranstaltung?
|
||||
suspend fun findByName(name: String): List<Veranstaltung>
|
||||
suspend fun findByVeranstalterOepsNummer(oepsNummer: String): List<Veranstaltung>
|
||||
suspend fun create(veranstaltung: Veranstaltung): Veranstaltung
|
||||
suspend fun update(id: Uuid, veranstaltung: Veranstaltung): Veranstaltung?
|
||||
suspend fun delete(id: Uuid): Boolean
|
||||
suspend fun search(query: String): List<Veranstaltung>
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package at.mocode.model
|
||||
package at.mocode.repositories
|
||||
|
||||
import at.mocode.stammdaten.Verein
|
||||
import com.benasher44.uuid.Uuid
|
||||
@@ -0,0 +1,146 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import at.mocode.model.Abteilung
|
||||
import at.mocode.repositories.AbteilungRepository
|
||||
import at.mocode.repositories.PostgresAbteilungRepository
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Route.abteilungRoutes() {
|
||||
val abteilungRepository: AbteilungRepository = PostgresAbteilungRepository()
|
||||
|
||||
route("/api/abteilungen") {
|
||||
// GET /api/abteilungen - Get all abteilungen
|
||||
get {
|
||||
try {
|
||||
val abteilungen = abteilungRepository.findAll()
|
||||
call.respond(HttpStatusCode.OK, abteilungen)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/abteilungen/{id} - Get abteilung by ID
|
||||
get("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing abteilung ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val abteilung = abteilungRepository.findById(uuid)
|
||||
if (abteilung != null) {
|
||||
call.respond(HttpStatusCode.OK, abteilung)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Abteilung not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/abteilungen/search?q={query} - Search abteilungen
|
||||
get("/search") {
|
||||
try {
|
||||
val query = call.request.queryParameters["q"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing search query parameter 'q'")
|
||||
)
|
||||
val abteilungen = abteilungRepository.search(query)
|
||||
call.respond(HttpStatusCode.OK, abteilungen)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/abteilungen/bewerb/{bewerbId} - Get abteilungen by bewerb ID
|
||||
get("/bewerb/{bewerbId}") {
|
||||
try {
|
||||
val bewerbId = call.parameters["bewerbId"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing bewerb ID")
|
||||
)
|
||||
val uuid = uuidFrom(bewerbId)
|
||||
val abteilungen = abteilungRepository.findByBewerbId(uuid)
|
||||
call.respond(HttpStatusCode.OK, abteilungen)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/abteilungen/aktiv/{istAktiv} - Get abteilungen by active status
|
||||
get("/aktiv/{istAktiv}") {
|
||||
try {
|
||||
val istAktiv = call.parameters["istAktiv"]?.toBoolean() ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing or invalid aktiv parameter")
|
||||
)
|
||||
val abteilungen = abteilungRepository.findByAktiv(istAktiv)
|
||||
call.respond(HttpStatusCode.OK, abteilungen)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/abteilungen - Create new abteilung
|
||||
post {
|
||||
try {
|
||||
val abteilung = call.receive<Abteilung>()
|
||||
val createdAbteilung = abteilungRepository.create(abteilung)
|
||||
call.respond(HttpStatusCode.Created, createdAbteilung)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// PUT /api/abteilungen/{id} - Update abteilung
|
||||
put("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@put call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing abteilung ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val abteilung = call.receive<Abteilung>()
|
||||
val updatedAbteilung = abteilungRepository.update(uuid, abteilung)
|
||||
if (updatedAbteilung != null) {
|
||||
call.respond(HttpStatusCode.OK, updatedAbteilung)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Abteilung not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE /api/abteilungen/{id} - Delete abteilung
|
||||
delete("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@delete call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing abteilung ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val deleted = abteilungRepository.delete(uuid)
|
||||
if (deleted) {
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Abteilung not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import at.mocode.model.Artikel
|
||||
import at.mocode.model.ArtikelRepository
|
||||
import at.mocode.model.PostgresArtikelRepository
|
||||
import at.mocode.repositories.ArtikelRepository
|
||||
import at.mocode.services.ServiceLocator
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.request.*
|
||||
@@ -11,9 +11,9 @@ import io.ktor.server.routing.*
|
||||
import kotlin.collections.mapOf
|
||||
|
||||
fun Route.artikelRoutes() {
|
||||
val artikelRepository: ArtikelRepository = PostgresArtikelRepository()
|
||||
val artikelRepository: ArtikelRepository = ServiceLocator.artikelRepository
|
||||
|
||||
route("/api/artikel") {
|
||||
route("/artikel") {
|
||||
// GET /api/artikel - Get all articles
|
||||
get {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import at.mocode.model.Bewerb
|
||||
import at.mocode.repositories.BewerbRepository
|
||||
import at.mocode.repositories.PostgresBewerbRepository
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Route.bewerbRoutes() {
|
||||
val bewerbRepository: BewerbRepository = PostgresBewerbRepository()
|
||||
|
||||
route("/api/bewerbe") {
|
||||
// GET /api/bewerbe - Get all bewerbe
|
||||
get {
|
||||
try {
|
||||
val bewerbe = bewerbRepository.findAll()
|
||||
call.respond(HttpStatusCode.OK, bewerbe)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/bewerbe/{id} - Get bewerb by ID
|
||||
get("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing bewerb ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val bewerb = bewerbRepository.findById(uuid)
|
||||
if (bewerb != null) {
|
||||
call.respond(HttpStatusCode.OK, bewerb)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Bewerb not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/bewerbe/search?q={query} - Search bewerbe
|
||||
get("/search") {
|
||||
try {
|
||||
val query = call.request.queryParameters["q"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing search query parameter 'q'")
|
||||
)
|
||||
val bewerbe = bewerbRepository.search(query)
|
||||
call.respond(HttpStatusCode.OK, bewerbe)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/bewerbe/turnier/{turnierId} - Get bewerbe by turnier ID
|
||||
get("/turnier/{turnierId}") {
|
||||
try {
|
||||
val turnierId = call.parameters["turnierId"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing turnier ID")
|
||||
)
|
||||
val uuid = uuidFrom(turnierId)
|
||||
val bewerbe = bewerbRepository.findByTurnierId(uuid)
|
||||
call.respond(HttpStatusCode.OK, bewerbe)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/bewerbe/sparte/{sparte} - Get bewerbe by sparte
|
||||
get("/sparte/{sparte}") {
|
||||
try {
|
||||
val sparte = call.parameters["sparte"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing sparte parameter")
|
||||
)
|
||||
val bewerbe = bewerbRepository.findBySparte(sparte)
|
||||
call.respond(HttpStatusCode.OK, bewerbe)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/bewerbe/klasse/{klasse} - Get bewerbe by klasse
|
||||
get("/klasse/{klasse}") {
|
||||
try {
|
||||
val klasse = call.parameters["klasse"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing klasse parameter")
|
||||
)
|
||||
val bewerbe = bewerbRepository.findByKlasse(klasse)
|
||||
call.respond(HttpStatusCode.OK, bewerbe)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/bewerbe - Create new bewerb
|
||||
post {
|
||||
try {
|
||||
val bewerb = call.receive<Bewerb>()
|
||||
val createdBewerb = bewerbRepository.create(bewerb)
|
||||
call.respond(HttpStatusCode.Created, createdBewerb)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// PUT /api/bewerbe/{id} - Update bewerb
|
||||
put("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@put call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing bewerb ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val bewerb = call.receive<Bewerb>()
|
||||
val updatedBewerb = bewerbRepository.update(uuid, bewerb)
|
||||
if (updatedBewerb != null) {
|
||||
call.respond(HttpStatusCode.OK, updatedBewerb)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Bewerb not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE /api/bewerbe/{id} - Delete bewerb
|
||||
delete("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@delete call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing bewerb ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val deleted = bewerbRepository.delete(uuid)
|
||||
if (deleted) {
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Bewerb not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import at.mocode.model.DomLizenzRepository
|
||||
import at.mocode.model.PostgresDomLizenzRepository
|
||||
import at.mocode.repositories.DomLizenzRepository
|
||||
import at.mocode.repositories.PostgresDomLizenzRepository
|
||||
import at.mocode.model.domaene.DomLizenz
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.http.*
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import at.mocode.repositories.DomPferdRepository
|
||||
import at.mocode.repositories.PostgresDomPferdRepository
|
||||
import at.mocode.model.domaene.DomPferd
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Route.domPferdRoutes() {
|
||||
val domPferdRepository: DomPferdRepository = PostgresDomPferdRepository()
|
||||
|
||||
route("/api/horses") {
|
||||
// GET /api/horses - Get all horses
|
||||
get {
|
||||
try {
|
||||
val horses = domPferdRepository.findAll()
|
||||
call.respond(HttpStatusCode.OK, horses)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/{id} - Get horse by ID
|
||||
get("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing horse ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val horse = domPferdRepository.findById(uuid)
|
||||
if (horse != null) {
|
||||
call.respond(HttpStatusCode.OK, horse)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Horse not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/oeps/{oepsSatzNr} - Get horse by OEPS number
|
||||
get("/oeps/{oepsSatzNr}") {
|
||||
try {
|
||||
val oepsSatzNr = call.parameters["oepsSatzNr"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing OEPS Satz number")
|
||||
)
|
||||
val horse = domPferdRepository.findByOepsSatzNr(oepsSatzNr)
|
||||
if (horse != null) {
|
||||
call.respond(HttpStatusCode.OK, horse)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Horse not found"))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/lebensnummer/{lebensnummer} - Get horse by life number
|
||||
get("/lebensnummer/{lebensnummer}") {
|
||||
try {
|
||||
val lebensnummer = call.parameters["lebensnummer"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing Lebensnummer")
|
||||
)
|
||||
val horse = domPferdRepository.findByLebensnummer(lebensnummer)
|
||||
if (horse != null) {
|
||||
call.respond(HttpStatusCode.OK, horse)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Horse not found"))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/search?q={query} - Search horses
|
||||
get("/search") {
|
||||
try {
|
||||
val query = call.request.queryParameters["q"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing search query parameter 'q'")
|
||||
)
|
||||
val horses = domPferdRepository.search(query)
|
||||
call.respond(HttpStatusCode.OK, horses)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/name/{name} - Get horses by name
|
||||
get("/name/{name}") {
|
||||
try {
|
||||
val name = call.parameters["name"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing horse name")
|
||||
)
|
||||
val horses = domPferdRepository.findByName(name)
|
||||
call.respond(HttpStatusCode.OK, horses)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/owner/{ownerId} - Get horses by owner ID
|
||||
get("/owner/{ownerId}") {
|
||||
try {
|
||||
val ownerId = call.parameters["ownerId"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing owner ID")
|
||||
)
|
||||
val uuid = uuidFrom(ownerId)
|
||||
val horses = domPferdRepository.findByBesitzerId(uuid)
|
||||
call.respond(HttpStatusCode.OK, horses)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/responsible/{personId} - Get horses by responsible person ID
|
||||
get("/responsible/{personId}") {
|
||||
try {
|
||||
val personId = call.parameters["personId"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing person ID")
|
||||
)
|
||||
val uuid = uuidFrom(personId)
|
||||
val horses = domPferdRepository.findByVerantwortlichePersonId(uuid)
|
||||
call.respond(HttpStatusCode.OK, horses)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/club/{clubId} - Get horses by home club ID
|
||||
get("/club/{clubId}") {
|
||||
try {
|
||||
val clubId = call.parameters["clubId"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing club ID")
|
||||
)
|
||||
val uuid = uuidFrom(clubId)
|
||||
val horses = domPferdRepository.findByHeimatVereinId(uuid)
|
||||
call.respond(HttpStatusCode.OK, horses)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/breed/{breed} - Get horses by breed
|
||||
get("/breed/{breed}") {
|
||||
try {
|
||||
val breed = call.parameters["breed"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing breed")
|
||||
)
|
||||
val horses = domPferdRepository.findByRasse(breed)
|
||||
call.respond(HttpStatusCode.OK, horses)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/birth-year/{year} - Get horses by birth year
|
||||
get("/birth-year/{year}") {
|
||||
try {
|
||||
val yearStr = call.parameters["year"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing birth year")
|
||||
)
|
||||
val year = yearStr.toIntOrNull() ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Invalid birth year format")
|
||||
)
|
||||
val horses = domPferdRepository.findByGeburtsjahr(year)
|
||||
call.respond(HttpStatusCode.OK, horses)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/horses/active - Get active horses only
|
||||
get("/active") {
|
||||
try {
|
||||
val horses = domPferdRepository.findActiveHorses()
|
||||
call.respond(HttpStatusCode.OK, horses)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/horses - Create a new horse
|
||||
post {
|
||||
try {
|
||||
val horse = call.receive<DomPferd>()
|
||||
val createdHorse = domPferdRepository.create(horse)
|
||||
call.respond(HttpStatusCode.Created, createdHorse)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// PUT /api/horses/{id} - Update horse
|
||||
put("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@put call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing horse ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val horse = call.receive<DomPferd>()
|
||||
val updatedHorse = domPferdRepository.update(uuid, horse)
|
||||
if (updatedHorse != null) {
|
||||
call.respond(HttpStatusCode.OK, updatedHorse)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Horse not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE /api/horses/{id} - Delete horse
|
||||
delete("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@delete call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing horse ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val deleted = domPferdRepository.delete(uuid)
|
||||
if (deleted) {
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Horse not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import at.mocode.repositories.DomQualifikationRepository
|
||||
import at.mocode.repositories.PostgresDomQualifikationRepository
|
||||
import at.mocode.model.domaene.DomQualifikation
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import kotlinx.datetime.LocalDate
|
||||
|
||||
fun Route.domQualifikationRoutes() {
|
||||
val domQualifikationRepository: DomQualifikationRepository = PostgresDomQualifikationRepository()
|
||||
|
||||
route("/api/dom-qualifikationen") {
|
||||
// GET /api/dom-qualifikationen - Get all qualifications
|
||||
get {
|
||||
try {
|
||||
val qualifikationen = domQualifikationRepository.findAll()
|
||||
call.respond(HttpStatusCode.OK, qualifikationen)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/dom-qualifikationen/{id} - Get qualification by ID
|
||||
get("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing qualification ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val qualifikation = domQualifikationRepository.findById(uuid)
|
||||
if (qualifikation != null) {
|
||||
call.respond(HttpStatusCode.OK, qualifikation)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Qualification not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/dom-qualifikationen/person/{personId} - Get qualifications by person ID
|
||||
get("/person/{personId}") {
|
||||
try {
|
||||
val personId = call.parameters["personId"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing person ID")
|
||||
)
|
||||
val uuid = uuidFrom(personId)
|
||||
val qualifikationen = domQualifikationRepository.findByPersonId(uuid)
|
||||
call.respond(HttpStatusCode.OK, qualifikationen)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/dom-qualifikationen/person/{personId}/active - Get active qualifications by person ID
|
||||
get("/person/{personId}/active") {
|
||||
try {
|
||||
val personId = call.parameters["personId"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing person ID")
|
||||
)
|
||||
val uuid = uuidFrom(personId)
|
||||
val qualifikationen = domQualifikationRepository.findActiveByPersonId(uuid)
|
||||
call.respond(HttpStatusCode.OK, qualifikationen)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/dom-qualifikationen/qual-typ/{qualTypId} - Get qualifications by qualification type
|
||||
get("/qual-typ/{qualTypId}") {
|
||||
try {
|
||||
val qualTypId = call.parameters["qualTypId"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing qualification type ID")
|
||||
)
|
||||
val uuid = uuidFrom(qualTypId)
|
||||
val qualifikationen = domQualifikationRepository.findByQualTypId(uuid)
|
||||
call.respond(HttpStatusCode.OK, qualifikationen)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/dom-qualifikationen/validity-period?from={fromDate}&to={toDate} - Get qualifications by validity period
|
||||
get("/validity-period") {
|
||||
try {
|
||||
val fromDateStr = call.request.queryParameters["from"]
|
||||
val toDateStr = call.request.queryParameters["to"]
|
||||
|
||||
val fromDate = fromDateStr?.let { LocalDate.parse(it) }
|
||||
val toDate = toDateStr?.let { LocalDate.parse(it) }
|
||||
|
||||
val qualifikationen = domQualifikationRepository.findByValidityPeriod(fromDate, toDate)
|
||||
call.respond(HttpStatusCode.OK, qualifikationen)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid date format. Use YYYY-MM-DD"))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/dom-qualifikationen/search?q={query} - Search qualifications
|
||||
get("/search") {
|
||||
try {
|
||||
val query = call.request.queryParameters["q"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing search query parameter 'q'")
|
||||
)
|
||||
val qualifikationen = domQualifikationRepository.search(query)
|
||||
call.respond(HttpStatusCode.OK, qualifikationen)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/dom-qualifikationen - Create new qualification
|
||||
post {
|
||||
try {
|
||||
val qualifikation = call.receive<DomQualifikation>()
|
||||
val createdQualifikation = domQualifikationRepository.create(qualifikation)
|
||||
call.respond(HttpStatusCode.Created, createdQualifikation)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// PUT /api/dom-qualifikationen/{id} - Update qualification
|
||||
put("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@put call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing qualification ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val qualifikation = call.receive<DomQualifikation>()
|
||||
val updatedQualifikation = domQualifikationRepository.update(uuid, qualifikation)
|
||||
if (updatedQualifikation != null) {
|
||||
call.respond(HttpStatusCode.OK, updatedQualifikation)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Qualification not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE /api/dom-qualifikationen/{id} - Delete qualification
|
||||
delete("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@delete call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing qualification ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val deleted = domQualifikationRepository.delete(uuid)
|
||||
if (deleted) {
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Qualification not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import at.mocode.model.PersonRepository
|
||||
import at.mocode.model.PostgresPersonRepository
|
||||
import at.mocode.repositories.PersonRepository
|
||||
import at.mocode.repositories.PostgresPersonRepository
|
||||
import at.mocode.stammdaten.Person
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.http.*
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
/**
|
||||
* Centralized route configuration that organizes all API routes
|
||||
* by domain and functionality for better maintainability
|
||||
*/
|
||||
object RouteConfiguration {
|
||||
|
||||
/**
|
||||
* Configure all API routes in a structured manner
|
||||
*/
|
||||
fun Route.configureApiRoutes() {
|
||||
route("/api") {
|
||||
// Core domain routes
|
||||
configureCoreRoutes()
|
||||
|
||||
// Domain-specific routes
|
||||
configureDomainRoutes()
|
||||
|
||||
// Event/Tournament management routes
|
||||
configureEventRoutes()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure core domain routes (Person, Verein, etc.)
|
||||
*/
|
||||
private fun Route.configureCoreRoutes() {
|
||||
// Person and organization management
|
||||
personRoutes()
|
||||
vereinRoutes()
|
||||
|
||||
// Articles and products
|
||||
artikelRoutes()
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure domain-specific routes (licenses, horses, qualifications)
|
||||
*/
|
||||
private fun Route.configureDomainRoutes() {
|
||||
route("/domain") {
|
||||
domLizenzRoutes()
|
||||
domPferdRoutes()
|
||||
domQualifikationRoutes()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure event and tournament management routes
|
||||
*/
|
||||
private fun Route.configureEventRoutes() {
|
||||
route("/events") {
|
||||
// Event hierarchy: Veranstaltung -> Turnier -> Bewerb -> Abteilung
|
||||
veranstaltungRoutes()
|
||||
turnierRoutes()
|
||||
bewerbRoutes()
|
||||
abteilungRoutes()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure administrative and utility routes
|
||||
*/
|
||||
private fun Route.configureAdminRoutes() {
|
||||
route("/admin") {
|
||||
// Future: Admin-specific endpoints
|
||||
// userManagementRoutes()
|
||||
// systemConfigRoutes()
|
||||
// auditLogRoutes()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure public/external API routes
|
||||
*/
|
||||
private fun Route.configurePublicRoutes() {
|
||||
route("/public") {
|
||||
// Future: Public endpoints that don't require authentication
|
||||
// publicEventListRoutes()
|
||||
// publicResultsRoutes()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import at.mocode.model.Turnier
|
||||
import at.mocode.repositories.TurnierRepository
|
||||
import at.mocode.repositories.PostgresTurnierRepository
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Route.turnierRoutes() {
|
||||
val turnierRepository: TurnierRepository = PostgresTurnierRepository()
|
||||
|
||||
route("/api/turniere") {
|
||||
// GET /api/turniere - Get all turniere
|
||||
get {
|
||||
try {
|
||||
val turniere = turnierRepository.findAll()
|
||||
call.respond(HttpStatusCode.OK, turniere)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/turniere/{id} - Get turnier by ID
|
||||
get("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing turnier ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val turnier = turnierRepository.findById(uuid)
|
||||
if (turnier != null) {
|
||||
call.respond(HttpStatusCode.OK, turnier)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Turnier not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/turniere/search?q={query} - Search turniere
|
||||
get("/search") {
|
||||
try {
|
||||
val query = call.request.queryParameters["q"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing search query parameter 'q'")
|
||||
)
|
||||
val turniere = turnierRepository.search(query)
|
||||
call.respond(HttpStatusCode.OK, turniere)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/turniere/veranstaltung/{veranstaltungId} - Get turniere by veranstaltung ID
|
||||
get("/veranstaltung/{veranstaltungId}") {
|
||||
try {
|
||||
val veranstaltungId = call.parameters["veranstaltungId"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing veranstaltung ID")
|
||||
)
|
||||
val uuid = uuidFrom(veranstaltungId)
|
||||
val turniere = turnierRepository.findByVeranstaltungId(uuid)
|
||||
call.respond(HttpStatusCode.OK, turniere)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/turniere - Create new turnier
|
||||
post {
|
||||
try {
|
||||
val turnier = call.receive<Turnier>()
|
||||
val createdTurnier = turnierRepository.create(turnier)
|
||||
call.respond(HttpStatusCode.Created, createdTurnier)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// PUT /api/turniere/{id} - Update turnier
|
||||
put("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@put call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing turnier ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val turnier = call.receive<Turnier>()
|
||||
val updatedTurnier = turnierRepository.update(uuid, turnier)
|
||||
if (updatedTurnier != null) {
|
||||
call.respond(HttpStatusCode.OK, updatedTurnier)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Turnier not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE /api/turniere/{id} - Delete turnier
|
||||
delete("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@delete call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing turnier ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val deleted = turnierRepository.delete(uuid)
|
||||
if (deleted) {
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Turnier not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import at.mocode.model.Veranstaltung
|
||||
import at.mocode.repositories.VeranstaltungRepository
|
||||
import at.mocode.services.ServiceLocator
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Route.veranstaltungRoutes() {
|
||||
val veranstaltungRepository: VeranstaltungRepository = ServiceLocator.veranstaltungRepository
|
||||
|
||||
route("/veranstaltungen") {
|
||||
// GET /api/veranstaltungen - Get all veranstaltungen
|
||||
get {
|
||||
try {
|
||||
val veranstaltungen = veranstaltungRepository.findAll()
|
||||
call.respond(HttpStatusCode.OK, veranstaltungen)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/veranstaltungen/{id} - Get veranstaltung by ID
|
||||
get("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing veranstaltung ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val veranstaltung = veranstaltungRepository.findById(uuid)
|
||||
if (veranstaltung != null) {
|
||||
call.respond(HttpStatusCode.OK, veranstaltung)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Veranstaltung not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// GET /api/veranstaltungen/search?q={query} - Search veranstaltungen
|
||||
get("/search") {
|
||||
try {
|
||||
val query = call.request.queryParameters["q"] ?: return@get call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing search query parameter 'q'")
|
||||
)
|
||||
val veranstaltungen = veranstaltungRepository.search(query)
|
||||
call.respond(HttpStatusCode.OK, veranstaltungen)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/veranstaltungen - Create new veranstaltung
|
||||
post {
|
||||
try {
|
||||
val veranstaltung = call.receive<Veranstaltung>()
|
||||
val createdVeranstaltung = veranstaltungRepository.create(veranstaltung)
|
||||
call.respond(HttpStatusCode.Created, createdVeranstaltung)
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// PUT /api/veranstaltungen/{id} - Update veranstaltung
|
||||
put("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@put call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing veranstaltung ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val veranstaltung = call.receive<Veranstaltung>()
|
||||
val updatedVeranstaltung = veranstaltungRepository.update(uuid, veranstaltung)
|
||||
if (updatedVeranstaltung != null) {
|
||||
call.respond(HttpStatusCode.OK, updatedVeranstaltung)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Veranstaltung not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE /api/veranstaltungen/{id} - Delete veranstaltung
|
||||
delete("/{id}") {
|
||||
try {
|
||||
val id = call.parameters["id"] ?: return@delete call.respond(
|
||||
HttpStatusCode.BadRequest,
|
||||
mapOf("error" to "Missing veranstaltung ID")
|
||||
)
|
||||
val uuid = uuidFrom(id)
|
||||
val deleted = veranstaltungRepository.delete(uuid)
|
||||
if (deleted) {
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.NotFound, mapOf("error" to "Veranstaltung not found"))
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
call.respond(HttpStatusCode.BadRequest, mapOf("error" to "Invalid UUID format"))
|
||||
} catch (e: Exception) {
|
||||
call.respond(HttpStatusCode.InternalServerError, mapOf("error" to e.message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package at.mocode.routes
|
||||
|
||||
import at.mocode.model.PostgresVereinRepository
|
||||
import at.mocode.model.VereinRepository
|
||||
import at.mocode.repositories.PostgresVereinRepository
|
||||
import at.mocode.repositories.VereinRepository
|
||||
import at.mocode.stammdaten.Verein
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.http.*
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package at.mocode.services
|
||||
|
||||
import at.mocode.repositories.*
|
||||
|
||||
/**
|
||||
* Service locator pattern for managing repository instances.
|
||||
* This provides a centralized way to access repository implementations
|
||||
* and makes it easier to switch implementations or add caching/decorators.
|
||||
*/
|
||||
object ServiceLocator {
|
||||
|
||||
// Repository instances - lazy initialization
|
||||
val artikelRepository: ArtikelRepository by lazy { PostgresArtikelRepository() }
|
||||
val vereinRepository: VereinRepository by lazy { PostgresVereinRepository() }
|
||||
val personRepository: PersonRepository by lazy { PostgresPersonRepository() }
|
||||
val domLizenzRepository: DomLizenzRepository by lazy { PostgresDomLizenzRepository() }
|
||||
val domPferdRepository: DomPferdRepository by lazy { PostgresDomPferdRepository() }
|
||||
val domQualifikationRepository: DomQualifikationRepository by lazy { PostgresDomQualifikationRepository() }
|
||||
val abteilungRepository: AbteilungRepository by lazy { PostgresAbteilungRepository() }
|
||||
val bewerbRepository: BewerbRepository by lazy { PostgresBewerbRepository() }
|
||||
val turnierRepository: TurnierRepository by lazy { PostgresTurnierRepository() }
|
||||
val veranstaltungRepository: VeranstaltungRepository by lazy { PostgresVeranstaltungRepository() }
|
||||
|
||||
/**
|
||||
* Initialize all repositories - useful for eager loading or validation
|
||||
*/
|
||||
fun initializeAll() {
|
||||
artikelRepository
|
||||
vereinRepository
|
||||
personRepository
|
||||
domLizenzRepository
|
||||
domPferdRepository
|
||||
domQualifikationRepository
|
||||
abteilungRepository
|
||||
bewerbRepository
|
||||
turnierRepository
|
||||
veranstaltungRepository
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ object BewerbTable : Table("bewerbe") {
|
||||
val geldpreisVorlageId = uuid("geldpreis_vorlage_id").nullable()
|
||||
|
||||
// Ort/Zeit (Default-Werte)
|
||||
val standardPlatzId = uuid("standard_platz_id").nullable().references(PlaetzeTable.id)
|
||||
val standardPlatzId = uuid("standard_platz_id").references(PlaetzeTable.id)
|
||||
val standardDatum = date("standard_datum").nullable()
|
||||
val standardBeginnzeitTypE = varchar("standard_beginnzeit_typ", 50).default("ANSCHLIESSEND")
|
||||
val standardBeginnzeitFix = time("standard_beginnzeit_fix").nullable()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package at.mocode.tables
|
||||
|
||||
import at.mocode.tables.stammdaten.PersonenTable
|
||||
import org.jetbrains.exposed.sql.Table
|
||||
import org.jetbrains.exposed.sql.kotlin.datetime.date // Für kotlinx-datetime LocalDate
|
||||
import org.jetbrains.exposed.sql.kotlin.datetime.datetime // Für kotlinx-datetime LocalDateTime
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package at.mocode.tables.domaene
|
||||
|
||||
import at.mocode.tables.PersonenTable
|
||||
import at.mocode.tables.stammdaten.PersonenTable
|
||||
import org.jetbrains.exposed.sql.Table
|
||||
import org.jetbrains.exposed.sql.kotlin.datetime.date
|
||||
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
||||
|
||||
@@ -2,8 +2,8 @@ package at.mocode.tables.domaene
|
||||
|
||||
import at.mocode.enums.DatenQuelleE
|
||||
import at.mocode.enums.PferdeGeschlechtE
|
||||
import at.mocode.tables.PersonenTable
|
||||
import at.mocode.tables.VereineTable
|
||||
import at.mocode.tables.stammdaten.PersonenTable
|
||||
import at.mocode.tables.stammdaten.VereineTable
|
||||
import org.jetbrains.exposed.sql.Table
|
||||
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import at.mocode.tables.TurniereTable
|
||||
import at.mocode.tables.VeranstaltungenTable
|
||||
import org.jetbrains.exposed.sql.Table
|
||||
import org.jetbrains.exposed.sql.kotlin.datetime.date
|
||||
import org.jetbrains.exposed.sql.kotlin.datetime.time
|
||||
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
||||
|
||||
// Event models tables
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
package at.mocode.utils
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Standardized API response wrapper for a consistent response format
|
||||
*/
|
||||
@Serializable
|
||||
data class ApiResponse<T>(
|
||||
val success: Boolean,
|
||||
val data: T? = null,
|
||||
val error: String? = null,
|
||||
val message: String? = null
|
||||
)
|
||||
|
||||
/**
|
||||
* Error response data class
|
||||
*/
|
||||
@Serializable
|
||||
data class ErrorResponse(
|
||||
val code: String,
|
||||
val message: String,
|
||||
val details: String? = null
|
||||
)
|
||||
|
||||
/**
|
||||
* Utility object for common HTTP responses
|
||||
*/
|
||||
object ResponseUtils {
|
||||
|
||||
/**
|
||||
* Respond with success and data
|
||||
*/
|
||||
suspend inline fun <reified T> RoutingCall.respondSuccess(
|
||||
data: T,
|
||||
status: HttpStatusCode = HttpStatusCode.OK,
|
||||
message: String? = null
|
||||
) {
|
||||
respond(status, ApiResponse(success = true, data = data, message = message))
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond with error
|
||||
*/
|
||||
suspend fun RoutingCall.respondError(
|
||||
error: String,
|
||||
status: HttpStatusCode = HttpStatusCode.InternalServerError,
|
||||
details: String? = null
|
||||
) {
|
||||
respond(status, ApiResponse<Nothing>(
|
||||
success = false,
|
||||
error = error,
|
||||
message = details
|
||||
))
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond with validation error
|
||||
*/
|
||||
suspend fun RoutingCall.respondValidationError(
|
||||
message: String,
|
||||
details: String? = null
|
||||
) {
|
||||
respondError(
|
||||
error = "VALIDATION_ERROR",
|
||||
status = HttpStatusCode.BadRequest,
|
||||
details = "$message${details?.let { " - $it" } ?: ""}"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond with not found error
|
||||
*/
|
||||
suspend fun RoutingCall.respondNotFound(
|
||||
resource: String = "Resource"
|
||||
) {
|
||||
respondError(
|
||||
error = "NOT_FOUND",
|
||||
status = HttpStatusCode.NotFound,
|
||||
details = "$resource not found"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond with a created resource
|
||||
*/
|
||||
suspend inline fun <reified T> RoutingCall.respondCreated(
|
||||
data: T,
|
||||
message: String? = null
|
||||
) {
|
||||
respondSuccess(data, HttpStatusCode.Created, message)
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond with no content (for successful deletions)
|
||||
*/
|
||||
suspend fun RoutingCall.respondNoContent() {
|
||||
respond(HttpStatusCode.NoContent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle common exceptions and respond appropriately
|
||||
*/
|
||||
suspend fun RoutingCall.handleException(
|
||||
exception: Exception,
|
||||
operation: String = "operation"
|
||||
) {
|
||||
when (exception) {
|
||||
is IllegalArgumentException -> respondValidationError(
|
||||
"Invalid input for $operation",
|
||||
exception.message
|
||||
)
|
||||
is NoSuchElementException -> respondNotFound()
|
||||
else -> respondError(
|
||||
"Internal server error during $operation",
|
||||
HttpStatusCode.InternalServerError,
|
||||
exception.message
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package at.mocode.utils
|
||||
|
||||
import com.benasher44.uuid.Uuid
|
||||
import com.benasher44.uuid.uuidFrom
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.routing.*
|
||||
import at.mocode.utils.ResponseUtils.respondValidationError
|
||||
|
||||
/**
|
||||
* Utility functions for common route operations
|
||||
*/
|
||||
object RouteUtils {
|
||||
|
||||
/**
|
||||
* Extract and validate UUID parameter from route
|
||||
*/
|
||||
suspend fun RoutingCall.getUuidParameter(
|
||||
paramName: String,
|
||||
resourceName: String = paramName
|
||||
): Uuid? {
|
||||
val paramValue = parameters[paramName]
|
||||
if (paramValue == null) {
|
||||
respondValidationError("Missing $resourceName ID")
|
||||
return null
|
||||
}
|
||||
|
||||
return try {
|
||||
uuidFrom(paramValue)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
respondValidationError("Invalid UUID format for $resourceName ID")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract and validate required string parameter from route
|
||||
*/
|
||||
suspend fun RoutingCall.getStringParameter(
|
||||
paramName: String,
|
||||
resourceName: String = paramName
|
||||
): String? {
|
||||
val paramValue = parameters[paramName]
|
||||
if (paramValue.isNullOrBlank()) {
|
||||
respondValidationError("Missing or empty $resourceName parameter")
|
||||
return null
|
||||
}
|
||||
return paramValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract and validate boolean parameter from route
|
||||
*/
|
||||
suspend fun RoutingCall.getBooleanParameter(
|
||||
paramName: String,
|
||||
resourceName: String = paramName
|
||||
): Boolean? {
|
||||
val paramValue = parameters[paramName]
|
||||
if (paramValue == null) {
|
||||
respondValidationError("Missing $resourceName parameter")
|
||||
return null
|
||||
}
|
||||
|
||||
return try {
|
||||
paramValue.toBoolean()
|
||||
} catch (e: Exception) {
|
||||
respondValidationError("Invalid boolean format for $resourceName parameter")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract and validate required query parameter
|
||||
*/
|
||||
suspend fun RoutingCall.getQueryParameter(
|
||||
paramName: String,
|
||||
resourceName: String = paramName
|
||||
): String? {
|
||||
val paramValue = request.queryParameters[paramName]
|
||||
if (paramValue.isNullOrBlank()) {
|
||||
respondValidationError("Missing search query parameter '$paramName'")
|
||||
return null
|
||||
}
|
||||
return paramValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Safe receive with error handling
|
||||
*/
|
||||
suspend inline fun <reified T : Any> RoutingCall.safeReceive(
|
||||
resourceName: String = "request body"
|
||||
): T? {
|
||||
return try {
|
||||
receive<T>()
|
||||
} catch (e: Exception) {
|
||||
respondValidationError("Invalid $resourceName format", e.message)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute repository operation with standardized error handling
|
||||
*/
|
||||
suspend inline fun <T> RoutingCall.executeRepositoryOperation(
|
||||
operation: String,
|
||||
block: () -> T
|
||||
): T? {
|
||||
return try {
|
||||
block()
|
||||
} catch (e: Exception) {
|
||||
ResponseUtils.run { handleException(e, operation) }
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package at.mocode
|
||||
|
||||
import at.mocode.model.domaene.DomQualifikation
|
||||
import com.benasher44.uuid.uuid4
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlin.test.*
|
||||
|
||||
class DomQualifikationTest {
|
||||
|
||||
@Test
|
||||
fun testDomQualifikationCreation() {
|
||||
val personId = uuid4()
|
||||
val qualTypId = uuid4()
|
||||
|
||||
val qualification = DomQualifikation(
|
||||
personId = personId,
|
||||
qualTypId = qualTypId,
|
||||
bemerkung = "Test qualification",
|
||||
gueltigVon = LocalDate(2024, 1, 1),
|
||||
gueltigBis = LocalDate(2024, 12, 31),
|
||||
istAktiv = true
|
||||
)
|
||||
|
||||
assertEquals(personId, qualification.personId)
|
||||
assertEquals(qualTypId, qualification.qualTypId)
|
||||
assertEquals("Test qualification", qualification.bemerkung)
|
||||
assertEquals(LocalDate(2024, 1, 1), qualification.gueltigVon)
|
||||
assertEquals(LocalDate(2024, 12, 31), qualification.gueltigBis)
|
||||
assertTrue(qualification.istAktiv)
|
||||
assertNotNull(qualification.qualifikationId)
|
||||
assertNotNull(qualification.createdAt)
|
||||
assertNotNull(qualification.updatedAt)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDomQualifikationDefaults() {
|
||||
val personId = uuid4()
|
||||
val qualTypId = uuid4()
|
||||
|
||||
val qualification = DomQualifikation(
|
||||
personId = personId,
|
||||
qualTypId = qualTypId
|
||||
)
|
||||
|
||||
assertEquals(personId, qualification.personId)
|
||||
assertEquals(qualTypId, qualification.qualTypId)
|
||||
assertNull(qualification.bemerkung)
|
||||
assertNull(qualification.gueltigVon)
|
||||
assertNull(qualification.gueltigBis)
|
||||
assertTrue(qualification.istAktiv) // Default should be true
|
||||
assertNotNull(qualification.qualifikationId)
|
||||
assertNotNull(qualification.createdAt)
|
||||
assertNotNull(qualification.updatedAt)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
package at.mocode.model.domaene
|
||||
|
||||
import at.mocode.serializers.KotlinInstantSerializer
|
||||
import at.mocode.serializers.KotlinLocalDateSerializer
|
||||
import at.mocode.serializers.UuidSerializer
|
||||
|
||||
Reference in New Issue
Block a user