feat(chat-room): 채팅방 입장 시 선택적 캐릭터 이미지 서명 URL 반환 및 파라미터 추가
enter API에 characterImageId 선택 파라미터 추가 동일 캐릭터/활성 여부/보유 여부 검증 후 5분 만료의 CloudFront 서명 URL 생성 ChatRoomEnterResponse에 bgImageUrl 필드 추가해 응답 포함 서명 URL 생성 실패 시 warn 로그만 남기고 null 반환하여 사용자 흐름 유지 기존 호출은 그대로 동작하며, 파라미터와 응답 필드 추가는 하위 호환됨
This commit is contained in:
parent
0347d767f0
commit
258943535c
|
@ -91,12 +91,13 @@ class ChatRoomController(
|
||||||
@GetMapping("/{chatRoomId}/enter")
|
@GetMapping("/{chatRoomId}/enter")
|
||||||
fun enterChatRoom(
|
fun enterChatRoom(
|
||||||
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
|
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
|
||||||
@PathVariable chatRoomId: Long
|
@PathVariable chatRoomId: Long,
|
||||||
|
@RequestParam(required = false) characterImageId: Long?
|
||||||
) = run {
|
) = run {
|
||||||
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
|
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
|
||||||
if (member.auth == null) throw SodaException("본인인증을 하셔야 합니다.")
|
if (member.auth == null) throw SodaException("본인인증을 하셔야 합니다.")
|
||||||
|
|
||||||
val response = chatRoomService.enterChatRoom(member, chatRoomId)
|
val response = chatRoomService.enterChatRoom(member, chatRoomId, characterImageId)
|
||||||
ApiResponse.ok(response)
|
ApiResponse.ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,8 @@ data class ChatRoomEnterResponse(
|
||||||
val messages: List<ChatMessageItemDto>,
|
val messages: List<ChatMessageItemDto>,
|
||||||
val hasMoreMessages: Boolean,
|
val hasMoreMessages: Boolean,
|
||||||
val totalRemaining: Int,
|
val totalRemaining: Int,
|
||||||
val nextRechargeAtEpoch: Long?
|
val nextRechargeAtEpoch: Long?,
|
||||||
|
val bgImageUrl: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -298,7 +298,7 @@ class ChatRoomService(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
fun enterChatRoom(member: Member, chatRoomId: Long): ChatRoomEnterResponse {
|
fun enterChatRoom(member: Member, chatRoomId: Long, characterImageId: Long? = null): ChatRoomEnterResponse {
|
||||||
val room = chatRoomRepository.findById(chatRoomId).orElseThrow {
|
val room = chatRoomRepository.findById(chatRoomId).orElseThrow {
|
||||||
SodaException("채팅방을 찾을 수 없습니다.")
|
SodaException("채팅방을 찾을 수 없습니다.")
|
||||||
}
|
}
|
||||||
|
@ -340,13 +340,45 @@ class ChatRoomService(
|
||||||
// 입장 시 Lazy refill 적용 후 상태 반환
|
// 입장 시 Lazy refill 적용 후 상태 반환
|
||||||
val quotaStatus = chatQuotaService.applyRefillOnEnterAndGetStatus(member.id!!)
|
val quotaStatus = chatQuotaService.applyRefillOnEnterAndGetStatus(member.id!!)
|
||||||
|
|
||||||
|
// 선택적 캐릭터 이미지 서명 URL 생성 처리
|
||||||
|
val signedUrl: String? = try {
|
||||||
|
if (characterImageId != null) {
|
||||||
|
val img = characterImageService.getById(characterImageId)
|
||||||
|
// 동일 캐릭터 소속 및 활성 검증
|
||||||
|
if (img.chatCharacter.id == character.id && img.isActive) {
|
||||||
|
val owned =
|
||||||
|
(img.imagePriceCan == 0L) || characterImageService.isOwnedImageByMember(img.id!!, member.id!!)
|
||||||
|
if (owned) {
|
||||||
|
val expiration = 5L * 60L * 1000L // 5분
|
||||||
|
imageCloudFront.generateSignedURL(img.imagePath, expiration)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// 문제가 있어도 입장 자체는 가능해야 하므로 로그만 남기고 null 반환
|
||||||
|
log.warn(
|
||||||
|
"[chat] enter: signed url generation failed. roomId={}, imageId={}, reason={}",
|
||||||
|
room.id,
|
||||||
|
characterImageId,
|
||||||
|
e.message
|
||||||
|
)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
return ChatRoomEnterResponse(
|
return ChatRoomEnterResponse(
|
||||||
roomId = room.id!!,
|
roomId = room.id!!,
|
||||||
character = characterDto,
|
character = characterDto,
|
||||||
messages = items,
|
messages = items,
|
||||||
hasMoreMessages = hasMore,
|
hasMoreMessages = hasMore,
|
||||||
totalRemaining = quotaStatus.totalRemaining,
|
totalRemaining = quotaStatus.totalRemaining,
|
||||||
nextRechargeAtEpoch = quotaStatus.nextRechargeAtEpochMillis
|
nextRechargeAtEpoch = quotaStatus.nextRechargeAtEpochMillis,
|
||||||
|
bgImageUrl = signedUrl
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue