Allow access code join by property code or id
All checks were successful
build-and-deploy / build-deploy (push) Successful in 34s

This commit is contained in:
androidlover5842
2026-02-01 23:09:47 +05:30
parent 4bcac9cb6a
commit d01b853f5e
3 changed files with 29 additions and 3 deletions

View File

@@ -192,6 +192,10 @@ Notes / constraints
- Super admin can create properties and assign users to properties. - Super admin can create properties and assign users to properties.
- Admin can assign ADMIN/MANAGER/STAFF/AGENT; Manager can assign STAFF/AGENT. - Admin can assign ADMIN/MANAGER/STAFF/AGENT; Manager can assign STAFF/AGENT.
- Agents can only see free rooms. - Agents can only see free rooms.
- Role hierarchy for visibility/management: SUPER_ADMIN > ADMIN > MANAGER > STAFF/HOUSEKEEPING/FINANCE/SUPERVISOR/GUIDE > AGENT. Users cannot see anyone above their rank in property user lists. Access code invites cannot assign ADMIN.
- Property code is auto-generated (7-char random, no fixed prefix). Property create no longer accepts `code` in request. Join-by-code uses property code, not propertyId.
- Property access codes: 6-digit PIN, 1-minute expiry, single-use. Admin generates; staff joins with property code + PIN.
- Property user disable is property-scoped (not global); hierarchy applies for who can disable.
Operational notes Operational notes
- Payment provider migrated: PayU removed; Razorpay now used for settings, QR, payment links, and webhooks. - Payment provider migrated: PayU removed; Razorpay now used for settings, QR, payment links, and webhooks.

View File

@@ -33,6 +33,7 @@ data class PropertyAccessCodeResponse(
) )
data class PropertyAccessCodeJoinRequest( data class PropertyAccessCodeJoinRequest(
val propertyCode: String, val propertyCode: String? = null,
val propertyId: String? = null,
val code: String val code: String
) )

View File

@@ -7,6 +7,7 @@ import com.android.trisolarisserver.controller.dto.property.PropertyAccessCodeJo
import com.android.trisolarisserver.controller.dto.property.PropertyAccessCodeResponse import com.android.trisolarisserver.controller.dto.property.PropertyAccessCodeResponse
import com.android.trisolarisserver.controller.dto.property.PropertyUserResponse import com.android.trisolarisserver.controller.dto.property.PropertyUserResponse
import com.android.trisolarisserver.models.property.PropertyAccessCode import com.android.trisolarisserver.models.property.PropertyAccessCode
import com.android.trisolarisserver.models.property.Property
import com.android.trisolarisserver.models.property.PropertyUser import com.android.trisolarisserver.models.property.PropertyUser
import com.android.trisolarisserver.models.property.PropertyUserId import com.android.trisolarisserver.models.property.PropertyUserId
import com.android.trisolarisserver.models.property.Role import com.android.trisolarisserver.models.property.Role
@@ -97,8 +98,7 @@ class PropertyAccessCodes(
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Invalid code") throw ResponseStatusException(HttpStatus.NOT_FOUND, "Invalid code")
} }
val now = OffsetDateTime.now() val now = OffsetDateTime.now()
val property = propertyRepo.findByCode(request.propertyCode.trim()) val property = resolveProperty(request)
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found")
val accessCode = accessCodeRepo.findActiveByPropertyAndCode(property.id!!, code, now) val accessCode = accessCodeRepo.findActiveByPropertyAndCode(property.id!!, code, now)
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Invalid code") ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Invalid code")
@@ -130,6 +130,27 @@ class PropertyAccessCodes(
) )
} }
private fun resolveProperty(request: PropertyAccessCodeJoinRequest): Property {
val code = request.propertyCode?.trim().orEmpty()
if (code.isNotBlank()) {
return propertyRepo.findByCode(code)
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found")
}
val rawId = request.propertyId?.trim().orEmpty()
if (rawId.isBlank()) {
throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Property code required")
}
val asUuid = runCatching { UUID.fromString(rawId) }.getOrNull()
return if (asUuid != null) {
propertyRepo.findById(asUuid).orElseThrow {
ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found")
}
} else {
propertyRepo.findByCode(rawId)
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Property not found")
}
}
private fun parseRoles(input: Set<String>): Set<Role> { private fun parseRoles(input: Set<String>): Set<Role> {
return try { return try {
input.map { Role.valueOf(it) }.toSet() input.map { Role.valueOf(it) }.toSet()