diff --git a/src/main/kotlin/com/android/trisolarisserver/controller/Auth.kt b/src/main/kotlin/com/android/trisolarisserver/controller/Auth.kt index 1ade4db..f82be33 100644 --- a/src/main/kotlin/com/android/trisolarisserver/controller/Auth.kt +++ b/src/main/kotlin/com/android/trisolarisserver/controller/Auth.kt @@ -3,8 +3,6 @@ package com.android.trisolarisserver.controller import com.android.trisolarisserver.controller.dto.PropertyUserResponse import com.android.trisolarisserver.controller.dto.UserResponse import com.android.trisolarisserver.repo.AppUserRepo -import com.android.trisolarisserver.repo.OrganizationRepo -import com.android.trisolarisserver.repo.PendingUserRepo import com.android.trisolarisserver.repo.PropertyUserRepo import com.android.trisolarisserver.security.MyPrincipal import com.google.firebase.auth.FirebaseAuth @@ -13,7 +11,9 @@ import org.slf4j.LoggerFactory import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RestController import org.springframework.web.server.ResponseStatusException import org.springframework.http.HttpStatus @@ -24,9 +24,7 @@ import java.util.UUID @RequestMapping("/auth") class Auth( private val appUserRepo: AppUserRepo, - private val propertyUserRepo: PropertyUserRepo, - private val organizationRepo: OrganizationRepo, - private val pendingUserRepo: PendingUserRepo + private val propertyUserRepo: PropertyUserRepo ) { private val logger = LoggerFactory.getLogger(Auth::class.java) @@ -36,7 +34,7 @@ class Auth( request: HttpServletRequest ): ResponseEntity { logger.info("Auth verify hit, principalPresent={}", principal != null) - val resolved = principal?.let { ResolveResult(it, null) } ?: resolvePrincipalFromHeader(request) + val resolved = principal?.let { ResolveResult(it) } ?: resolvePrincipalFromHeader(request) return resolved.toResponseEntity() } @@ -45,10 +43,31 @@ class Auth( @AuthenticationPrincipal principal: MyPrincipal?, request: HttpServletRequest ): ResponseEntity { - val resolved = principal?.let { ResolveResult(it, null) } ?: resolvePrincipalFromHeader(request) + val resolved = principal?.let { ResolveResult(it) } ?: resolvePrincipalFromHeader(request) return resolved.toResponseEntity() } + @PutMapping("/me") + fun updateMe( + @AuthenticationPrincipal principal: MyPrincipal?, + request: HttpServletRequest, + @RequestBody body: UpdateMeRequest + ): ResponseEntity { + val resolved = principal?.let { ResolveResult(it) } ?: resolvePrincipalFromHeader(request) + if (resolved.principal == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body(AuthResponse(status = "UNAUTHORIZED")) + } + val user = appUserRepo.findById(resolved.principal.userId).orElseThrow { + ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found") + } + if (!body.name.isNullOrBlank()) { + user.name = body.name.trim() + } + appUserRepo.save(user) + return ResponseEntity.ok(buildAuthResponse(resolved.principal)) + } + private fun buildAuthResponse(principal: MyPrincipal): AuthResponse { val user = appUserRepo.findById(principal.userId).orElseThrow { ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found") @@ -60,15 +79,20 @@ class Auth( roles = it.roles.map { role -> role.name }.toSet() ) } + val status = when { + user.superAdmin -> "SUPER_ADMIN" + memberships.isEmpty() -> "NO_PROPERTIES" + else -> "OK" + } return AuthResponse( - status = "OK", + status = status, user = UserResponse( id = user.id!!, - orgId = user.org.id!!, firebaseUid = user.firebaseUid, phoneE164 = user.phoneE164, name = user.name, - disabled = user.disabled + disabled = user.disabled, + superAdmin = user.superAdmin ), properties = memberships ) @@ -90,62 +114,34 @@ class Auth( logger.warn("Auth verify failed: {}", ex.message) throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid token") } - val user = appUserRepo.findByFirebaseUid(decoded.uid) - if (user == null) { - val orgs = organizationRepo.findAll() - if (orgs.isEmpty()) { - logger.warn("Auth verify user not found for uid={}, orgCount=0", decoded.uid) - val phone = decoded.claims["phone_number"] as? String - val name = decoded.claims["name"] as? String - val existing = pendingUserRepo.findByFirebaseUid(decoded.uid) - val pending = existing ?: pendingUserRepo.save( - com.android.trisolarisserver.models.property.PendingUser( - firebaseUid = decoded.uid, - phoneE164 = phone, - name = name - ) + val user = appUserRepo.findByFirebaseUid(decoded.uid) ?: run { + val phone = decoded.claims["phone_number"] as? String + val name = decoded.claims["name"] as? String + val makeSuperAdmin = appUserRepo.count() == 0L + val created = appUserRepo.save( + com.android.trisolarisserver.models.property.AppUser( + firebaseUid = decoded.uid, + phoneE164 = phone, + name = name, + superAdmin = makeSuperAdmin ) - return ResolveResult(null, pending.id) - } - if (orgs.size == 1) { - val org = orgs.first() - val phone = decoded.claims["phone_number"] as? String - val name = decoded.claims["name"] as? String - val created = appUserRepo.save( - com.android.trisolarisserver.models.property.AppUser( - org = org, - firebaseUid = decoded.uid, - phoneE164 = phone, - name = name - ) - ) - logger.warn("Auth verify auto-created user uid={}, userId={}, orgId={}", decoded.uid, created.id, org.id) - return ResolveResult( - MyPrincipal( - userId = created.id - ?: throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "User id missing"), - firebaseUid = decoded.uid - ), - null - ) - } - logger.warn("Auth verify user not found for uid={}, orgCount={}", decoded.uid, orgs.size) - throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found") + ) + logger.warn("Auth verify auto-created user uid={}, userId={}", decoded.uid, created.id) + created } logger.warn("Auth verify resolved uid={}, userId={}", decoded.uid, user.id) return ResolveResult( MyPrincipal( userId = user.id ?: throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "User id missing"), firebaseUid = decoded.uid - ), - null + ) ) } private fun ResolveResult.toResponseEntity(): ResponseEntity { return if (principal == null) { - ResponseEntity.status(HttpStatus.ACCEPTED) - .body(AuthResponse(status = "NEEDS_ORG", pendingUserId = pendingUserId)) + ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body(AuthResponse(status = "UNAUTHORIZED")) } else { ResponseEntity.ok(buildAuthResponse(principal)) } @@ -155,11 +151,13 @@ class Auth( data class AuthResponse( val status: String, val user: UserResponse? = null, - val properties: List = emptyList(), - val pendingUserId: UUID? = null + val properties: List = emptyList() +) + +data class UpdateMeRequest( + val name: String? = null ) private data class ResolveResult( - val principal: MyPrincipal?, - val pendingUserId: UUID? + val principal: MyPrincipal? )