Revoke cards by cardIndex and drop cardId uniqueness
All checks were successful
build-and-deploy / build-deploy (push) Successful in 1m33s

This commit is contained in:
androidlover5842
2026-01-28 18:24:40 +05:30
parent 914d824e51
commit 385a66d5c5
3 changed files with 7 additions and 39 deletions

View File

@@ -46,27 +46,9 @@ class IssuedCardSchemaFix(
Int::class.java Int::class.java
) ?: 0 ) ?: 0
if (uniqueIndexExists == 0) { if (uniqueIndexExists > 0) {
logger.info("Removing duplicate issued_card rows by property_id + card_id") logger.info("Dropping unique index on issued_card(property_id, lower(card_id))")
jdbcTemplate.execute( jdbcTemplate.execute("drop index if exists idx_issued_card_property_card_id_unique")
"""
with ranked as (
select id,
row_number() over (
partition by property_id, lower(card_id)
order by issued_at desc, id desc
) as rn
from issued_card
where card_id is not null
)
delete from issued_card
where id in (select id from ranked where rn > 1)
""".trimIndent()
)
logger.info("Creating unique index on issued_card(property_id, lower(card_id))")
jdbcTemplate.execute(
"create unique index if not exists idx_issued_card_property_card_id_unique on issued_card (property_id, lower(card_id))"
)
} }
} }
} }

View File

@@ -150,14 +150,14 @@ class IssuedCards(
.map { it.toResponse() } .map { it.toResponse() }
} }
@PostMapping("/cards/{cardId}/revoke") @PostMapping("/cards/{cardIndex}/revoke")
fun revoke( fun revoke(
@PathVariable propertyId: UUID, @PathVariable propertyId: UUID,
@PathVariable cardId: String, @PathVariable cardIndex: Int,
@AuthenticationPrincipal principal: MyPrincipal? @AuthenticationPrincipal principal: MyPrincipal?
): CardRevokeResponse { ): CardRevokeResponse {
requireRevokeActor(propertyId, principal) requireRevokeActor(propertyId, principal)
val card = findCardForRevoke(cardId, propertyId) val card = issuedCardRepo.findByPropertyIdAndCardIndex(propertyId, cardIndex)
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Card not found") ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Card not found")
if (card.revokedAt == null) { if (card.revokedAt == null) {
val now = nowForProperty(card.property.timezone) val now = nowForProperty(card.property.timezone)
@@ -238,21 +238,6 @@ class IssuedCards(
propertyAccess.requireAnyRole(propertyId, principal.userId, Role.ADMIN) propertyAccess.requireAnyRole(propertyId, principal.userId, Role.ADMIN)
} }
private fun findCardForRevoke(cardId: String, propertyId: UUID): IssuedCard? {
val trimmed = cardId.trim()
if (trimmed.isBlank()) return null
val uuid = try {
java.util.UUID.fromString(trimmed)
} catch (_: Exception) {
null
}
return if (uuid != null) {
issuedCardRepo.findByIdAndPropertyId(uuid, propertyId)
} else {
issuedCardRepo.findAllByCardIdIgnoreCaseAndPropertyId(trimmed, propertyId)
.maxByOrNull { it.issuedAt }
}
}
private fun nextCardIndex(propertyId: UUID): Int { private fun nextCardIndex(propertyId: UUID): Int {
var counter = counterRepo.findByPropertyIdForUpdate(propertyId) var counter = counterRepo.findByPropertyIdForUpdate(propertyId)

View File

@@ -9,6 +9,7 @@ interface IssuedCardRepo : JpaRepository<IssuedCard, UUID> {
fun findByIdAndPropertyId(id: UUID, propertyId: UUID): IssuedCard? fun findByIdAndPropertyId(id: UUID, propertyId: UUID): IssuedCard?
fun findByCardIdIgnoreCaseAndPropertyId(cardId: String, propertyId: UUID): IssuedCard? fun findByCardIdIgnoreCaseAndPropertyId(cardId: String, propertyId: UUID): IssuedCard?
fun findAllByCardIdIgnoreCaseAndPropertyId(cardId: String, propertyId: UUID): List<IssuedCard> fun findAllByCardIdIgnoreCaseAndPropertyId(cardId: String, propertyId: UUID): List<IssuedCard>
fun findByPropertyIdAndCardIndex(propertyId: UUID, cardIndex: Int): IssuedCard?
@org.springframework.data.jpa.repository.Query(""" @org.springframework.data.jpa.repository.Query("""
select case when count(c) > 0 then true else false end select case when count(c) > 0 then true else false end