2026-09-02 20:48:17 +00:00
|
|
|
package com.oliver.kidio.backend.plugins
|
2026-09-02 14:12:52 +00:00
|
|
|
|
2026-09-02 20:48:17 +00:00
|
|
|
import com.oliver.kidio.backend.*
|
|
|
|
|
import com.oliver.kidio.backend.domain.repository.KidioRepository
|
2026-09-04 10:54:10 +00:00
|
|
|
import com.oliver.kidio.backend.security.JwtService
|
2026-09-07 10:37:00 +00:00
|
|
|
import io.ktor.http.HttpStatusCode
|
2026-09-02 14:12:52 +00:00
|
|
|
import io.ktor.server.application.*
|
2026-09-04 10:54:10 +00:00
|
|
|
import io.ktor.server.auth.authenticate
|
2026-09-07 10:37:00 +00:00
|
|
|
import io.ktor.server.auth.jwt.JWTPrincipal
|
|
|
|
|
import io.ktor.server.auth.principal
|
2026-09-02 14:12:52 +00:00
|
|
|
import io.ktor.server.request.*
|
|
|
|
|
import io.ktor.server.response.*
|
|
|
|
|
import io.ktor.server.routing.*
|
2026-09-07 10:37:00 +00:00
|
|
|
import org.mindrot.jbcrypt.BCrypt
|
|
|
|
|
import java.util.UUID
|
2026-09-02 14:12:52 +00:00
|
|
|
|
2026-09-04 10:54:10 +00:00
|
|
|
fun Application.configureRouting(repository: KidioRepository, jwtService : JwtService) {
|
2026-09-02 14:12:52 +00:00
|
|
|
routing {
|
2026-09-07 10:37:00 +00:00
|
|
|
post("/api/v1/auth/register") {
|
|
|
|
|
val registerRequest = call.receive<RegisterRequest>()
|
|
|
|
|
if (registerRequest.email.isBlank() || registerRequest.passwordPlain.isBlank()) {
|
|
|
|
|
call.respond(HttpStatusCode.BadRequest, "Bitte füllen Sie alle Felder aus")
|
|
|
|
|
return@post
|
|
|
|
|
}
|
|
|
|
|
if (registerRequest.parentPin.length != 4) {
|
|
|
|
|
call.respond(HttpStatusCode.BadRequest, "Die Eltern-PIN muss genau 4 Ziffern lang sein")
|
|
|
|
|
return@post
|
|
|
|
|
}
|
|
|
|
|
val existingUser = repository.findByEmail(registerRequest.email)
|
|
|
|
|
if (existingUser != null) {
|
|
|
|
|
call.respond(HttpStatusCode.Conflict, "Ein Benutzer mit dieser E-Mail-Adresse existiert bereits")
|
|
|
|
|
return@post
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Backend generiert die eindeutige User-ID
|
|
|
|
|
val userId = UUID.randomUUID().toString()
|
|
|
|
|
val passwordHash = BCrypt.hashpw(registerRequest.passwordPlain, BCrypt.gensalt())
|
|
|
|
|
|
|
|
|
|
//datenbank insert hinzufügen
|
|
|
|
|
repository.registerUser(User(userId, registerRequest.email, passwordHash, registerRequest.familyName, registerRequest.childAge, registerRequest.parentPin))
|
2026-09-02 14:12:52 +00:00
|
|
|
|
2026-09-07 10:37:00 +00:00
|
|
|
val token = jwtService.generateToken(userId)
|
|
|
|
|
|
|
|
|
|
call.respond(
|
|
|
|
|
HttpStatusCode.Created,
|
|
|
|
|
mapOf(
|
|
|
|
|
"token" to token,
|
|
|
|
|
"userId" to userId,
|
|
|
|
|
"message" to "Registrierung erfolgreich"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
}
|
2026-09-02 14:12:52 +00:00
|
|
|
// Health-Check
|
|
|
|
|
get("/api/v1/health") {
|
|
|
|
|
call.respond(mapOf("status" to "OK", "message" to "Kidio Backend läuft!"))
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-04 10:54:10 +00:00
|
|
|
post ("/api/v1/auth/login" ) {
|
|
|
|
|
val loginRequest = call.receive<LoginRequest>()
|
|
|
|
|
|
|
|
|
|
val token = jwtService.generateToken(userId = loginRequest.userId)
|
|
|
|
|
call.respond(mapOf("token" to token))
|
2026-09-02 14:12:52 +00:00
|
|
|
}
|
|
|
|
|
|
2026-09-04 10:54:10 +00:00
|
|
|
authenticate("auth-jwt") {
|
|
|
|
|
|
|
|
|
|
// 1. Alle verfügbaren Aufgaben abrufen
|
|
|
|
|
get("/api/v1/tasks") {
|
|
|
|
|
val tasks = repository.getAllTasks()
|
|
|
|
|
call.respond(tasks)
|
|
|
|
|
}
|
2026-09-02 14:12:52 +00:00
|
|
|
|
2026-09-04 10:54:10 +00:00
|
|
|
// 2. Antwort auf eine Aufgabe überprüfen
|
2026-09-07 10:37:00 +00:00
|
|
|
post("/api/v1/tasks/verify") {
|
|
|
|
|
val request = call.receive<TaskVerifyRequest>()
|
|
|
|
|
val principal = call.principal<JWTPrincipal>()
|
|
|
|
|
val userId = principal?.payload?.getClaim("userId")?.asString()
|
2026-09-02 20:48:17 +00:00
|
|
|
|
2026-09-07 10:37:00 +00:00
|
|
|
if (userId == null){
|
|
|
|
|
call.respond(HttpStatusCode.Unauthorized, mapOf("error" to "Ungültiges oder abgelaufenes Token"))
|
2026-09-04 10:54:10 +00:00
|
|
|
return@post
|
2026-09-07 10:37:00 +00:00
|
|
|
}
|
|
|
|
|
val taskInfo = repository.getTaskAnswerAndReward(request.taskId)
|
|
|
|
|
if (taskInfo == null) {
|
|
|
|
|
call.respond(
|
|
|
|
|
TaskVerifyResponse(
|
|
|
|
|
isCorrect = false,
|
|
|
|
|
earnedMinutes = 0,
|
|
|
|
|
message = "Aufgabe nicht gefunden!"
|
|
|
|
|
)
|
2026-09-04 10:54:10 +00:00
|
|
|
)
|
2026-09-07 10:37:00 +00:00
|
|
|
return@post
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val (correctAnswer, reward) = taskInfo
|
|
|
|
|
val isCorrect = request.selectedAnswer.trim() == correctAnswer.trim()
|
|
|
|
|
|
|
|
|
|
if (isCorrect) {
|
|
|
|
|
val currentScreentime = repository.getScreentime(userId)
|
|
|
|
|
val newSeconds = currentScreentime + (reward * 60)
|
|
|
|
|
repository.updateScreentime(userId, newSeconds)
|
|
|
|
|
|
|
|
|
|
call.respond(
|
|
|
|
|
TaskVerifyResponse(
|
|
|
|
|
isCorrect = true,
|
|
|
|
|
earnedMinutes = reward,
|
|
|
|
|
message = "Super gemacht! Du hast $reward Minuten gewonnen."
|
|
|
|
|
)
|
2026-09-04 10:54:10 +00:00
|
|
|
)
|
2026-09-07 10:37:00 +00:00
|
|
|
} else {
|
|
|
|
|
call.respond(
|
|
|
|
|
TaskVerifyResponse(
|
|
|
|
|
isCorrect = false,
|
|
|
|
|
earnedMinutes = 0,
|
|
|
|
|
message = "Schade, das war leider falsch. Versuche es nochmal!"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
}
|
2026-09-04 10:54:10 +00:00
|
|
|
}
|
2026-09-02 14:12:52 +00:00
|
|
|
|
2026-09-04 10:54:10 +00:00
|
|
|
// 3. Bildschirmzeit synchronisieren
|
|
|
|
|
post("/api/v1/screentime/sync") {
|
|
|
|
|
val request = call.receive<SyncRequest>()
|
2026-09-02 14:12:52 +00:00
|
|
|
|
2026-09-04 10:54:10 +00:00
|
|
|
val currentSeconds = repository.getScreentime(request.userId)
|
|
|
|
|
var newSeconds = currentSeconds - request.usedSecondsSinceLastSync
|
|
|
|
|
if (newSeconds < 0) newSeconds = 0
|
2026-09-02 20:48:17 +00:00
|
|
|
|
2026-09-04 10:54:10 +00:00
|
|
|
repository.updateScreentime(request.userId, newSeconds)
|
2026-09-02 14:12:52 +00:00
|
|
|
|
2026-09-04 10:54:10 +00:00
|
|
|
call.respond(
|
|
|
|
|
SyncResponse(
|
|
|
|
|
remainingSeconds = newSeconds,
|
|
|
|
|
isBlocked = newSeconds <= 0
|
|
|
|
|
)
|
2026-09-02 14:12:52 +00:00
|
|
|
)
|
2026-09-04 10:54:10 +00:00
|
|
|
}
|
2026-09-02 14:12:52 +00:00
|
|
|
}
|
|
|
|
|
}
|
2026-09-02 20:48:17 +00:00
|
|
|
}
|
2026-09-04 10:54:10 +00:00
|
|
|
|