From df351204edc61885096f2c02385802700a8bbfc1 Mon Sep 17 00:00:00 2001 From: androidlover5842 Date: Tue, 27 Jan 2026 23:34:37 +0530 Subject: [PATCH] Add room type images list endpoint --- .../controller/RoomTypeImages.kt | 83 +++++++++++++++++++ .../trisolarisserver/repo/RoomImageRepo.kt | 14 ++++ .../security/FirebaseAuthFilter.kt | 1 + .../security/SecurityConfig.kt | 1 + 4 files changed, 99 insertions(+) create mode 100644 src/main/kotlin/com/android/trisolarisserver/controller/RoomTypeImages.kt diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/RoomTypeImages.kt b/src/main/kotlin/com/android/trisolarisserver/controller/RoomTypeImages.kt new file mode 100644 index 0000000..72eeb63 --- /dev/null +++ b/src/main/kotlin/com/android/trisolarisserver/controller/RoomTypeImages.kt @@ -0,0 +1,83 @@ +package com.android.trisolarisserver.controller + +import com.android.trisolarisserver.controller.dto.RoomImageResponse +import com.android.trisolarisserver.models.room.RoomImage +import com.android.trisolarisserver.models.room.RoomImageTag +import com.android.trisolarisserver.repo.RoomImageRepo +import com.android.trisolarisserver.repo.RoomTypeRepo +import org.springframework.http.HttpStatus +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.server.ResponseStatusException +import java.nio.file.Files +import java.nio.file.Paths +import java.util.UUID + +@RestController +@RequestMapping("/properties/{propertyId}/room-types/{roomTypeCode}/images") +class RoomTypeImages( + private val roomTypeRepo: RoomTypeRepo, + private val roomImageRepo: RoomImageRepo, + @org.springframework.beans.factory.annotation.Value("\${storage.rooms.publicBaseUrl}") + private val publicBaseUrl: String +) { + + @GetMapping + fun listByRoomType( + @PathVariable propertyId: UUID, + @PathVariable roomTypeCode: String + ): List { + val roomType = roomTypeRepo.findByPropertyIdAndCodeIgnoreCase(propertyId, roomTypeCode) + ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Room type not found") + + val images = roomImageRepo.findByPropertyIdAndRoomTypeCodeOrdered(propertyId, roomType.code).toMutableList() + if (images.isEmpty()) return emptyList() + + val missing = mutableListOf() + val present = mutableListOf() + for (img in images) { + val originalExists = Files.exists(Paths.get(img.originalPath)) + if (!originalExists) { + missing.add(img) + try { + Files.deleteIfExists(Paths.get(img.thumbnailPath)) + } catch (_: Exception) { + } + } else { + present.add(img) + } + } + if (missing.isNotEmpty()) { + roomImageRepo.deleteAll(missing) + } + return present.map { it.toResponse(publicBaseUrl) } + } +} + +private fun RoomImage.toResponse(baseUrl: String): RoomImageResponse { + val id = id ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Image id missing") + return RoomImageResponse( + id = id, + propertyId = property.id!!, + roomId = room.id!!, + roomTypeCode = roomTypeCode, + url = "$baseUrl/properties/${property.id}/rooms/${room.id}/images/$id/file", + thumbnailUrl = "$baseUrl/properties/${property.id}/rooms/${room.id}/images/$id/file?size=thumb", + contentType = contentType, + sizeBytes = sizeBytes, + tags = tags.map { it.toResponse() }.toSet(), + roomSortOrder = roomSortOrder, + roomTypeSortOrder = roomTypeSortOrder, + createdAt = createdAt.toString() + ) +} + +private fun RoomImageTag.toResponse(): com.android.trisolarisserver.controller.dto.RoomImageTagResponse { + val id = id ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Tag id missing") + return com.android.trisolarisserver.controller.dto.RoomImageTagResponse( + id = id, + name = name + ) +} diff --git a/src/main/kotlin/com/android/trisolarisserver/repo/RoomImageRepo.kt b/src/main/kotlin/com/android/trisolarisserver/repo/RoomImageRepo.kt index 95a3be2..2081802 100644 --- a/src/main/kotlin/com/android/trisolarisserver/repo/RoomImageRepo.kt +++ b/src/main/kotlin/com/android/trisolarisserver/repo/RoomImageRepo.kt @@ -37,6 +37,20 @@ interface RoomImageRepo : JpaRepository { """ ) fun findByRoomTypeCodeForReorder(@Param("roomTypeCode") roomTypeCode: String): List + + @org.springframework.data.jpa.repository.EntityGraph(attributePaths = ["tags"]) + @Query( + """ + select ri + from RoomImage ri + where ri.property.id = :propertyId and ri.roomTypeCode = :roomTypeCode + order by case when ri.roomTypeSortOrder is null then 1 else 0 end, ri.roomTypeSortOrder asc, ri.createdAt desc + """ + ) + fun findByPropertyIdAndRoomTypeCodeOrdered( + @Param("propertyId") propertyId: UUID, + @Param("roomTypeCode") roomTypeCode: String + ): List fun findByIdAndRoomIdAndPropertyId(id: UUID, roomId: UUID, propertyId: UUID): RoomImage? fun findByIdIn(ids: Collection): List fun existsByRoomIdAndContentHash(roomId: UUID, contentHash: String): Boolean diff --git a/src/main/kotlin/com/android/trisolarisserver/security/FirebaseAuthFilter.kt b/src/main/kotlin/com/android/trisolarisserver/security/FirebaseAuthFilter.kt index 6f99398..6e73eb7 100644 --- a/src/main/kotlin/com/android/trisolarisserver/security/FirebaseAuthFilter.kt +++ b/src/main/kotlin/com/android/trisolarisserver/security/FirebaseAuthFilter.kt @@ -28,6 +28,7 @@ class FirebaseAuthFilter( return path.matches(Regex("^/properties/[^/]+/rooms/[^/]+/images/[^/]+/file$")) || path.matches(Regex("^/properties/[^/]+/rooms/[^/]+/images$")) || path.matches(Regex("^/properties/[^/]+/room-types$")) + || path.matches(Regex("^/properties/[^/]+/room-types/[^/]+/images$")) || (path == "/image-tags" && request.method.equals("GET", true)) || path == "/icons/png" || path.matches(Regex("^/icons/png/[^/]+$")) diff --git a/src/main/kotlin/com/android/trisolarisserver/security/SecurityConfig.kt b/src/main/kotlin/com/android/trisolarisserver/security/SecurityConfig.kt index c350c15..f1ccc21 100644 --- a/src/main/kotlin/com/android/trisolarisserver/security/SecurityConfig.kt +++ b/src/main/kotlin/com/android/trisolarisserver/security/SecurityConfig.kt @@ -29,6 +29,7 @@ class SecurityConfig( it.requestMatchers("/properties/*/rooms/*/images/*/file").permitAll() it.requestMatchers("/properties/*/rooms/*/images").permitAll() it.requestMatchers("/properties/*/room-types").permitAll() + it.requestMatchers("/properties/*/room-types/*/images").permitAll() it.requestMatchers(org.springframework.http.HttpMethod.GET, "/image-tags").permitAll() it.requestMatchers("/icons/png").permitAll() it.requestMatchers("/icons/png/*").permitAll()