Files
TrisolarisServer/src/main/kotlin/com/android/trisolarisserver/controller/GuestRatings.kt
androidlover5842 9b64b34ab9
All checks were successful
build-and-deploy / build-deploy (push) Successful in 33s
Deduplicate logic across controllers, auth, and schema fixes
2026-01-28 23:03:48 +05:30

112 lines
4.5 KiB
Kotlin

package com.android.trisolarisserver.controller
import com.android.trisolarisserver.component.PropertyAccess
import com.android.trisolarisserver.controller.dto.GuestRatingCreateRequest
import com.android.trisolarisserver.controller.dto.GuestRatingResponse
import com.android.trisolarisserver.db.repo.BookingRepo
import com.android.trisolarisserver.db.repo.GuestRatingRepo
import com.android.trisolarisserver.db.repo.GuestRepo
import com.android.trisolarisserver.repo.AppUserRepo
import com.android.trisolarisserver.repo.PropertyRepo
import com.android.trisolarisserver.models.booking.GuestRating
import com.android.trisolarisserver.models.booking.GuestRatingScore
import com.android.trisolarisserver.security.MyPrincipal
import org.springframework.http.HttpStatus
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ResponseStatusException
import java.util.UUID
@RestController
@RequestMapping("/properties/{propertyId}/guests/{guestId}/ratings")
class GuestRatings(
private val propertyAccess: PropertyAccess,
private val propertyRepo: PropertyRepo,
private val guestRepo: GuestRepo,
private val bookingRepo: BookingRepo,
private val guestRatingRepo: GuestRatingRepo,
private val appUserRepo: AppUserRepo
) {
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun create(
@PathVariable propertyId: UUID,
@PathVariable guestId: UUID,
@AuthenticationPrincipal principal: MyPrincipal?,
@RequestBody request: GuestRatingCreateRequest
): GuestRatingResponse {
val resolved = requireMember(propertyAccess, propertyId, principal)
val (property, guest) = requirePropertyGuest(propertyRepo, guestRepo, propertyId, guestId)
val booking = bookingRepo.findById(request.bookingId).orElseThrow {
ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found")
}
if (booking.property.id != property.id) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Booking not in property")
}
if (booking.primaryGuest?.id != guest.id) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Booking not linked to guest")
}
if (guestRatingRepo.existsByGuestIdAndBookingId(guest.id!!, booking.id!!)) {
throw ResponseStatusException(HttpStatus.CONFLICT, "Rating already exists for booking")
}
val score = parseScore(request.score)
val rating = GuestRating(
property = property,
guest = guest,
booking = booking,
score = score,
notes = request.notes?.trim(),
createdBy = appUserRepo.findById(resolved.userId).orElse(null)
)
guestRatingRepo.save(rating)
return rating.toResponse()
}
@GetMapping
fun list(
@PathVariable propertyId: UUID,
@PathVariable guestId: UUID,
@AuthenticationPrincipal principal: MyPrincipal?
): List<GuestRatingResponse> {
requireMember(propertyAccess, propertyId, principal)
val (_, guest) = requirePropertyGuest(propertyRepo, guestRepo, propertyId, guestId)
return guestRatingRepo.findByGuestIdOrderByCreatedAtDesc(guestId).map { it.toResponse() }
}
private fun parseScore(raw: String): GuestRatingScore {
val normalized = raw.trim().uppercase()
return when (normalized) {
"1", "GOOD" -> GuestRatingScore.GOOD
"2", "OK" -> GuestRatingScore.OK
"3", "TROUBLE", "TROUBLEMAKER", "TROUBLE-MAKER" -> GuestRatingScore.TROUBLE
else -> throw ResponseStatusException(HttpStatus.BAD_REQUEST, "score must be GOOD/OK/TROUBLE or 1/2/3")
}
}
private fun GuestRating.toResponse(): GuestRatingResponse {
return GuestRatingResponse(
id = id!!,
propertyId = property.id!!,
guestId = guest.id!!,
bookingId = booking.id!!,
score = score.name,
notes = notes,
createdAt = createdAt.toString(),
createdByUserId = createdBy?.id
)
}
}