From eb0b99f55ad64fd4645151ce5f411eedaec625d7 Mon Sep 17 00:00:00 2001 From: androidlover5842 Date: Tue, 27 Jan 2026 04:33:51 +0530 Subject: [PATCH] Make amenities global and super-admin managed --- .../controller/RoomAmenities.kt | 59 ++++++++----------- .../trisolarisserver/controller/RoomTypes.kt | 10 ++-- .../controller/dto/RoomTypeDtos.kt | 1 - .../models/room/RoomAmenity.kt | 10 +--- .../trisolarisserver/repo/RoomAmenityRepo.kt | 9 ++- 5 files changed, 34 insertions(+), 55 deletions(-) diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/RoomAmenities.kt b/src/main/kotlin/com/android/trisolarisserver/controller/RoomAmenities.kt index 717325f..bbb63b6 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/RoomAmenities.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/RoomAmenities.kt @@ -1,11 +1,9 @@ package com.android.trisolarisserver.controller -import com.android.trisolarisserver.component.PropertyAccess import com.android.trisolarisserver.controller.dto.AmenityResponse import com.android.trisolarisserver.controller.dto.AmenityUpsertRequest -import com.android.trisolarisserver.models.property.Role import com.android.trisolarisserver.models.room.RoomAmenity -import com.android.trisolarisserver.repo.PropertyRepo +import com.android.trisolarisserver.repo.AppUserRepo import com.android.trisolarisserver.repo.RoomAmenityRepo import com.android.trisolarisserver.security.MyPrincipal import org.springframework.http.HttpStatus @@ -23,43 +21,32 @@ import org.springframework.web.server.ResponseStatusException import java.util.UUID @RestController -@RequestMapping("/properties/{propertyId}/amenities") +@RequestMapping("/amenities") class RoomAmenities( - private val propertyAccess: PropertyAccess, private val roomAmenityRepo: RoomAmenityRepo, - private val propertyRepo: PropertyRepo + private val appUserRepo: AppUserRepo ) { @GetMapping fun listAmenities( - @PathVariable propertyId: UUID, @AuthenticationPrincipal principal: MyPrincipal? ): List { requirePrincipal(principal) - propertyAccess.requireMember(propertyId, principal!!.userId) - return roomAmenityRepo.findByPropertyIdOrderByName(propertyId).map { it.toResponse() } + return roomAmenityRepo.findAllByOrderByName().map { it.toResponse() } } @PostMapping @ResponseStatus(HttpStatus.CREATED) fun createAmenity( - @PathVariable propertyId: UUID, @AuthenticationPrincipal principal: MyPrincipal?, @RequestBody request: AmenityUpsertRequest ): AmenityResponse { - requirePrincipal(principal) - propertyAccess.requireMember(propertyId, principal!!.userId) - propertyAccess.requireAnyRole(propertyId, principal.userId, Role.ADMIN, Role.MANAGER) + requireSuperAdmin(principal) - if (roomAmenityRepo.existsByPropertyIdAndName(propertyId, request.name)) { - throw ResponseStatusException(HttpStatus.CONFLICT, "Amenity already exists for property") - } - - val property = propertyRepo.findById(propertyId).orElseThrow { - ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found") + if (roomAmenityRepo.existsByName(request.name)) { + throw ResponseStatusException(HttpStatus.CONFLICT, "Amenity already exists") } val amenity = RoomAmenity( - property = property, name = request.name, category = request.category, iconKey = request.iconKey, @@ -70,20 +57,17 @@ class RoomAmenities( @PutMapping("/{amenityId}") fun updateAmenity( - @PathVariable propertyId: UUID, @PathVariable amenityId: UUID, @AuthenticationPrincipal principal: MyPrincipal?, @RequestBody request: AmenityUpsertRequest ): AmenityResponse { - requirePrincipal(principal) - propertyAccess.requireMember(propertyId, principal!!.userId) - propertyAccess.requireAnyRole(propertyId, principal.userId, Role.ADMIN, Role.MANAGER) + requireSuperAdmin(principal) - val amenity = roomAmenityRepo.findByIdAndPropertyId(amenityId, propertyId) + val amenity = roomAmenityRepo.findById(amenityId).orElse(null) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Amenity not found") - if (roomAmenityRepo.existsByPropertyIdAndNameAndIdNot(propertyId, request.name, amenityId)) { - throw ResponseStatusException(HttpStatus.CONFLICT, "Amenity already exists for property") + if (roomAmenityRepo.existsByNameAndIdNot(request.name, amenityId)) { + throw ResponseStatusException(HttpStatus.CONFLICT, "Amenity already exists") } amenity.name = request.name @@ -96,15 +80,12 @@ class RoomAmenities( @DeleteMapping("/{amenityId}") @ResponseStatus(HttpStatus.NO_CONTENT) fun deleteAmenity( - @PathVariable propertyId: UUID, @PathVariable amenityId: UUID, @AuthenticationPrincipal principal: MyPrincipal? ) { - requirePrincipal(principal) - propertyAccess.requireMember(propertyId, principal!!.userId) - propertyAccess.requireAnyRole(propertyId, principal.userId, Role.ADMIN, Role.MANAGER) + requireSuperAdmin(principal) - val amenity = roomAmenityRepo.findByIdAndPropertyId(amenityId, propertyId) + val amenity = roomAmenityRepo.findById(amenityId).orElse(null) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Amenity not found") roomAmenityRepo.delete(amenity) @@ -115,14 +96,24 @@ class RoomAmenities( throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Missing principal") } } + + private fun requireSuperAdmin(principal: MyPrincipal?) { + if (principal == null) { + throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Missing principal") + } + val user = appUserRepo.findById(principal.userId).orElseThrow { + ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found") + } + if (!user.superAdmin) { + throw ResponseStatusException(HttpStatus.FORBIDDEN, "Super admin only") + } + } } private fun RoomAmenity.toResponse(): AmenityResponse { val id = id ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Amenity id missing") - val propertyId = property.id ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Property id missing") return AmenityResponse( id = id, - propertyId = propertyId, name = name, category = category, iconKey = iconKey, diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/RoomTypes.kt b/src/main/kotlin/com/android/trisolarisserver/controller/RoomTypes.kt index 148cd83..ea8c17f 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/RoomTypes.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/RoomTypes.kt @@ -74,16 +74,16 @@ class RoomTypes( otaAliases = request.otaAliases?.toMutableSet() ?: mutableSetOf() ) if (request.amenityIds != null) { - roomType.amenities = resolveAmenities(propertyId, request.amenityIds) + roomType.amenities = resolveAmenities(request.amenityIds) } return roomTypeRepo.save(roomType).toResponse() } - private fun resolveAmenities(propertyId: UUID, ids: Set): MutableSet { + private fun resolveAmenities(ids: Set): MutableSet { if (ids.isEmpty()) { return mutableSetOf() } - val amenities = roomAmenityRepo.findByPropertyIdAndIdIn(propertyId, ids) + val amenities = roomAmenityRepo.findByIdIn(ids) if (amenities.size != ids.size) { throw ResponseStatusException(HttpStatus.NOT_FOUND, "Amenity not found") } @@ -118,7 +118,7 @@ class RoomTypes( roomType.otaAliases = request.otaAliases.toMutableSet() } if (request.amenityIds != null) { - roomType.amenities = resolveAmenities(propertyId, request.amenityIds) + roomType.amenities = resolveAmenities(request.amenityIds) } return roomTypeRepo.save(roomType).toResponse() } @@ -169,10 +169,8 @@ private fun RoomType.toResponse(): RoomTypeResponse { private fun RoomAmenity.toResponse(): com.android.trisolarisserver.controller.dto.AmenityResponse { val id = id ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Amenity id missing") - val propertyId = property.id ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Property id missing") return com.android.trisolarisserver.controller.dto.AmenityResponse( id = id, - propertyId = propertyId, name = name, category = category, iconKey = iconKey, diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/dto/RoomTypeDtos.kt b/src/main/kotlin/com/android/trisolarisserver/controller/dto/RoomTypeDtos.kt index 101236c..261f4a7 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/dto/RoomTypeDtos.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/dto/RoomTypeDtos.kt @@ -35,7 +35,6 @@ data class AmenityUpsertRequest( data class AmenityResponse( val id: UUID, - val propertyId: UUID, val name: String, val category: String?, val iconKey: String?, diff --git a/src/main/kotlin/com/android/trisolarisserver/models/room/RoomAmenity.kt b/src/main/kotlin/com/android/trisolarisserver/models/room/RoomAmenity.kt index 9d38229..d418f21 100644 --- a/src/main/kotlin/com/android/trisolarisserver/models/room/RoomAmenity.kt +++ b/src/main/kotlin/com/android/trisolarisserver/models/room/RoomAmenity.kt @@ -1,13 +1,9 @@ package com.android.trisolarisserver.models.room -import com.android.trisolarisserver.models.property.Property import jakarta.persistence.Column import jakarta.persistence.Entity -import jakarta.persistence.FetchType import jakarta.persistence.GeneratedValue import jakarta.persistence.Id -import jakarta.persistence.JoinColumn -import jakarta.persistence.ManyToOne import jakarta.persistence.Table import jakarta.persistence.UniqueConstraint import java.time.OffsetDateTime @@ -16,7 +12,7 @@ import java.util.UUID @Entity @Table( name = "room_amenity", - uniqueConstraints = [UniqueConstraint(columnNames = ["property_id", "name"])] + uniqueConstraints = [UniqueConstraint(columnNames = ["name"])] ) class RoomAmenity( @Id @@ -24,10 +20,6 @@ class RoomAmenity( @Column(columnDefinition = "uuid") val id: UUID? = null, - @ManyToOne(fetch = FetchType.LAZY, optional = false) - @JoinColumn(name = "property_id", nullable = false) - var property: Property, - @Column(nullable = false) var name: String, diff --git a/src/main/kotlin/com/android/trisolarisserver/repo/RoomAmenityRepo.kt b/src/main/kotlin/com/android/trisolarisserver/repo/RoomAmenityRepo.kt index 4dd5fc8..31a4a15 100644 --- a/src/main/kotlin/com/android/trisolarisserver/repo/RoomAmenityRepo.kt +++ b/src/main/kotlin/com/android/trisolarisserver/repo/RoomAmenityRepo.kt @@ -5,9 +5,8 @@ import org.springframework.data.jpa.repository.JpaRepository import java.util.UUID interface RoomAmenityRepo : JpaRepository { - fun findByIdAndPropertyId(id: UUID, propertyId: UUID): RoomAmenity? - fun findByPropertyIdOrderByName(propertyId: UUID): List - fun findByPropertyIdAndIdIn(propertyId: UUID, ids: Set): List - fun existsByPropertyIdAndName(propertyId: UUID, name: String): Boolean - fun existsByPropertyIdAndNameAndIdNot(propertyId: UUID, name: String, id: UUID): Boolean + fun findAllByOrderByName(): List + fun findByIdIn(ids: Set): List + fun existsByName(name: String): Boolean + fun existsByNameAndIdNot(name: String, id: UUID): Boolean }