modes of transport

This commit is contained in:
androidlover5842
2026-01-24 22:39:45 +05:30
parent 6b6d84e40a
commit 72d9f5bb12
11 changed files with 309 additions and 10 deletions

View File

@@ -0,0 +1,113 @@
package com.android.trisolarisserver.controller
import com.android.trisolarisserver.component.PropertyAccess
import com.android.trisolarisserver.controller.dto.GuestResponse
import com.android.trisolarisserver.controller.dto.GuestVehicleRequest
import com.android.trisolarisserver.models.booking.Guest
import com.android.trisolarisserver.models.booking.GuestVehicle
import com.android.trisolarisserver.repo.GuestRepo
import com.android.trisolarisserver.repo.GuestVehicleRepo
import com.android.trisolarisserver.repo.PropertyRepo
import com.android.trisolarisserver.security.MyPrincipal
import org.springframework.http.HttpStatus
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.*
import org.springframework.web.server.ResponseStatusException
import java.util.UUID
@RestController
@RequestMapping("/properties/{propertyId}/guests")
class Guests(
private val propertyAccess: PropertyAccess,
private val propertyRepo: PropertyRepo,
private val guestRepo: GuestRepo,
private val guestVehicleRepo: GuestVehicleRepo
) {
@GetMapping("/search")
fun search(
@PathVariable propertyId: UUID,
@AuthenticationPrincipal principal: MyPrincipal?,
@RequestParam(required = false) phone: String?,
@RequestParam(required = false) vehicleNumber: String?
): List<GuestResponse> {
requirePrincipal(principal)
propertyAccess.requireMember(propertyId, principal!!.userId)
if (phone.isNullOrBlank() && vehicleNumber.isNullOrBlank()) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "phone or vehicleNumber required")
}
val property = propertyRepo.findById(propertyId).orElseThrow {
ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found")
}
val orgId = property.org.id ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Org missing")
val guests = mutableSetOf<Guest>()
if (!phone.isNullOrBlank()) {
val guest = guestRepo.findByOrgIdAndPhoneE164(orgId, phone)
if (guest != null) guests.add(guest)
}
if (!vehicleNumber.isNullOrBlank()) {
val vehicle = guestVehicleRepo.findByOrgIdAndVehicleNumberIgnoreCase(orgId, vehicleNumber)
if (vehicle != null) guests.add(vehicle.guest)
}
return guests.toResponse(guestVehicleRepo)
}
@PostMapping("/{guestId}/vehicles")
@ResponseStatus(HttpStatus.CREATED)
fun addVehicle(
@PathVariable propertyId: UUID,
@PathVariable guestId: UUID,
@AuthenticationPrincipal principal: MyPrincipal?,
@RequestBody request: GuestVehicleRequest
): GuestResponse {
requirePrincipal(principal)
propertyAccess.requireMember(propertyId, principal!!.userId)
val property = propertyRepo.findById(propertyId).orElseThrow {
ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found")
}
val guest = guestRepo.findById(guestId).orElseThrow {
ResponseStatusException(HttpStatus.NOT_FOUND, "Guest not found")
}
if (guest.org.id != property.org.id) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Guest not in property org")
}
if (guestVehicleRepo.existsByOrgIdAndVehicleNumberIgnoreCase(property.org.id!!, request.vehicleNumber)) {
throw ResponseStatusException(HttpStatus.CONFLICT, "Vehicle number already exists")
}
val vehicle = GuestVehicle(
org = property.org,
guest = guest,
vehicleNumber = request.vehicleNumber.trim()
)
guestVehicleRepo.save(vehicle)
return listOf(guest).toResponse(guestVehicleRepo).first()
}
private fun requirePrincipal(principal: MyPrincipal?) {
if (principal == null) {
throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Missing principal")
}
}
}
private fun Set<Guest>.toResponse(guestVehicleRepo: GuestVehicleRepo): List<GuestResponse> {
val ids = this.mapNotNull { it.id }
val vehicles = if (ids.isEmpty()) emptyList() else guestVehicleRepo.findByGuestIdIn(ids)
val vehiclesByGuest = vehicles.groupBy { it.guest.id }
return this.map { guest ->
GuestResponse(
id = guest.id!!,
orgId = guest.org.id!!,
name = guest.name,
phoneE164 = guest.phoneE164,
nationality = guest.nationality,
addressText = guest.addressText,
vehicleNumbers = vehiclesByGuest[guest.id]?.map { it.vehicleNumber }?.toSet() ?: emptySet()
)
}
}