메시지 API

This commit is contained in:
Klaus 2023-08-02 14:04:31 +09:00
parent c25b105d4d
commit b3d72ead1f
12 changed files with 685 additions and 2 deletions

View File

@ -5,6 +5,7 @@ import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.live.room.cancel.CancelLiveRequest
import kr.co.vividnext.sodalive.live.room.donation.DeleteLiveRoomDonationMessage
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRequest
import kr.co.vividnext.sodalive.live.room.visit.LiveRoomVisitService
import kr.co.vividnext.sodalive.member.Member
import org.springframework.data.domain.Pageable
import org.springframework.security.core.annotation.AuthenticationPrincipal
@ -22,7 +23,10 @@ import org.springframework.web.multipart.MultipartFile
@RestController
@RequestMapping("/live/room")
class LiveRoomController(private val service: LiveRoomService) {
class LiveRoomController(
private val service: LiveRoomService,
private val visitService: LiveRoomVisitService
) {
@GetMapping
fun getRoomList(
@ -229,4 +233,13 @@ class LiveRoomController(private val service: LiveRoomService) {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.quitRoom(roomId, member))
}
@GetMapping("/recent_visit_room/users")
fun recentVisitRoomUsers(
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(visitService.getRecentVisitRoomUsers(member.id!!))
}
}

View File

@ -3,6 +3,8 @@ package kr.co.vividnext.sodalive.live.room.visit
import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom
import kr.co.vividnext.sodalive.live.room.visit.QLiveRoomVisit.liveRoomVisit
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.MemberRole
import kr.co.vividnext.sodalive.member.QMember.member
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@ -13,6 +15,7 @@ interface LiveRoomVisitRepository : JpaRepository<LiveRoomVisit, Long>, LiveRoom
interface LiveRoomVisitQueryRepository {
fun findByRoomIdAndMemberId(roomId: Long, memberId: Long): LiveRoomVisit?
fun findFirstByMemberIdOrderByUpdatedAtDesc(memberId: Long): LiveRoomVisit?
fun getRecentVisitRoomUsers(roomId: Long, memberId: Long): List<Member>
}
@Repository
@ -38,4 +41,17 @@ class LiveRoomVisitQueryRepositoryImpl(private val queryFactory: JPAQueryFactory
.orderBy(liveRoomVisit.updatedAt.desc())
.fetchFirst()
}
override fun getRecentVisitRoomUsers(roomId: Long, memberId: Long): List<Member> {
return queryFactory
.selectFrom(member)
.where(
liveRoomVisit.room.id.eq(roomId)
.and(liveRoomVisit.member.isActive.isTrue)
.and(liveRoomVisit.member.id.ne(memberId))
.and(liveRoomVisit.member.role.ne(MemberRole.ADMIN))
.and(liveRoomVisit.member.role.ne(MemberRole.AGENT))
)
.fetch()
}
}

View File

@ -1,14 +1,21 @@
package kr.co.vividnext.sodalive.live.room.visit
import kr.co.vividnext.sodalive.live.room.LiveRoom
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser
import kr.co.vividnext.sodalive.member.Member
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime
@Service
@Transactional(readOnly = true)
class LiveRoomVisitService(private val repository: LiveRoomVisitRepository) {
class LiveRoomVisitService(
private val repository: LiveRoomVisitRepository,
@Value("\${cloud.aws.cloud-front.host}")
private val cloudFrontHost: String
) {
@Transactional
fun roomVisit(room: LiveRoom, member: Member) {
var roomVisit = repository.findByRoomIdAndMemberId(room.id!!, member.id!!)
@ -22,4 +29,14 @@ class LiveRoomVisitService(private val repository: LiveRoomVisitRepository) {
repository.save(roomVisit)
}
fun getRecentVisitRoomUsers(memberId: Long): List<GetRoomDetailUser> {
val roomVisit = repository.findFirstByMemberIdOrderByUpdatedAtDesc(memberId)
?: return emptyList()
return repository.getRecentVisitRoomUsers(roomVisit.room!!.id!!, memberId)
.asSequence()
.map { GetRoomDetailUser(it, cloudFrontHost) }
.toList()
}
}

View File

@ -114,4 +114,14 @@ class MemberController(private val service: MemberService) {
ApiResponse.ok(service.memberUnBlock(request = request, memberId = member.id!!))
}
@GetMapping("/search")
fun searchMember(
@RequestParam nickname: String,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.searchMember(nickname = nickname, memberId = member.id!!))
}
}

View File

@ -13,6 +13,7 @@ interface MemberRepository : JpaRepository<Member, Long>, MemberQueryRepository
interface MemberQueryRepository {
fun findByPushToken(pushToken: String): List<Member>
fun findByNicknameAndOtherCondition(nickname: String, memberId: Long): List<Member>
}
@Repository
@ -23,4 +24,16 @@ class MemberQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : Mem
.where(member.pushToken.eq(pushToken))
.fetch()
}
override fun findByNicknameAndOtherCondition(nickname: String, memberId: Long): List<Member> {
return queryFactory
.selectFrom(member)
.where(
member.nickname.containsIgnoreCase(nickname)
.and(member.id.ne(memberId))
.and(member.role.ne(MemberRole.ADMIN))
.and(member.role.ne(MemberRole.AGENT))
)
.fetch()
}
}

View File

@ -6,6 +6,7 @@ import kr.co.vividnext.sodalive.aws.s3.S3Uploader
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.jwt.TokenProvider
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser
import kr.co.vividnext.sodalive.member.block.BlockMember
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
import kr.co.vividnext.sodalive.member.block.MemberBlockRequest
@ -334,4 +335,18 @@ class MemberService(
}
fun isBlocked(blockedMemberId: Long, memberId: Long) = blockMemberRepository.isBlocked(blockedMemberId, memberId)
fun searchMember(nickname: String, memberId: Long): List<GetRoomDetailUser> {
if (nickname.length < 2) {
throw SodaException("두 글자 이상 입력 하셔야 합니다.")
}
return repository.findByNicknameAndOtherCondition(nickname, memberId)
.asSequence()
.filter { blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = it.id!!) }
.map {
GetRoomDetailUser(it, cloudFrontHost)
}
.toList()
}
}

View File

@ -0,0 +1,35 @@
package kr.co.vividnext.sodalive.message
data class GetVoiceMessageResponse(
val totalCount: Int,
val items: List<VoiceMessageItem>
) {
data class VoiceMessageItem(
val messageId: Long,
val senderId: Long,
val senderNickname: String,
val senderProfileImageUrl: String,
val recipientNickname: String,
val recipientProfileImageUrl: String,
val voiceMessageUrl: String,
val date: String,
val isKept: Boolean
)
}
data class GetTextMessageResponse(
val totalCount: Int,
val items: List<TextMessageItem>
) {
data class TextMessageItem(
val messageId: Long,
val senderId: Long,
val senderNickname: String,
val senderProfileImageUrl: String,
val recipientNickname: String,
val recipientProfileImageUrl: String,
val textMessage: String,
val date: String,
val isKept: Boolean
)
}

View File

@ -0,0 +1,37 @@
package kr.co.vividnext.sodalive.message
import kr.co.vividnext.sodalive.common.BaseEntity
import kr.co.vividnext.sodalive.member.Member
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.EnumType
import javax.persistence.Enumerated
import javax.persistence.FetchType
import javax.persistence.JoinColumn
import javax.persistence.ManyToOne
@Entity
data class Message(
@Column(columnDefinition = "TEXT")
val textMessage: String? = null,
var voiceMessage: String? = null,
@Enumerated(EnumType.STRING)
val messageType: MessageType = MessageType.TEXT,
var isRecipientKeep: Boolean = false,
var isSenderDelete: Boolean = false,
var isRecipientDelete: Boolean = false
) : BaseEntity() {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "sender_id", nullable = false)
var sender: Member? = null
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "recipient_id", nullable = false)
var recipient: Member? = null
}
enum class MessageType {
TEXT, VOICE
}

View File

@ -0,0 +1,136 @@
package kr.co.vividnext.sodalive.message
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.member.Member
import org.springframework.data.domain.Pageable
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile
@RestController
@RequestMapping("/message")
class MessageController(private val service: MessageService) {
@PostMapping("/send/text")
fun sendTextMessage(
@RequestBody request: SendTextMessageRequest,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.sendTextMessage(request, member))
}
@GetMapping("/sent/text")
fun getSentTextMessages(
@RequestParam("timezone") timezone: String,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
pageable: Pageable
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.getSentTextMessages(member, pageable, timezone))
}
@GetMapping("/received/text")
fun getReceivedTextMessages(
@RequestParam("timezone") timezone: String,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
pageable: Pageable
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.getReceivedTextMessages(member, pageable, timezone))
}
@GetMapping("/keep/text")
fun getKeepTextMessages(
@RequestParam("timezone") timezone: String,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
pageable: Pageable
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.getKeepTextMessages(member, pageable, timezone))
}
@PutMapping("/keep/text/{id}")
fun keepTextMessage(
@PathVariable id: Long,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.keepTextMessage(id, member))
}
@PostMapping("/send/voice")
fun sendVoiceMessage(
@RequestPart("voiceMessageFile") voiceMessageFile: MultipartFile,
@RequestPart("request") requestString: String,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.sendVoiceMessage(voiceMessageFile, requestString, member))
}
@GetMapping("/sent/voice")
fun getSentVoiceMessages(
@RequestParam("timezone") timezone: String,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
pageable: Pageable
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.getSentVoiceMessages(member, pageable, timezone))
}
@GetMapping("/received/voice")
fun getReceivedVoiceMessages(
@RequestParam("timezone") timezone: String,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
pageable: Pageable
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.getReceivedVoiceMessages(member, pageable, timezone))
}
@GetMapping("/keep/voice")
fun getKeepVoiceMessages(
@RequestParam("timezone") timezone: String,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
pageable: Pageable
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.getKeepVoiceMessages(member, pageable, timezone))
}
@PutMapping("/keep/voice/{id}")
fun keepVoiceMessage(
@PathVariable id: Long,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.keepVoiceMessage(id, member))
}
@DeleteMapping("/{messageId}")
fun deleteMessage(
@PathVariable messageId: Long,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.deleteMessage(messageId, member))
}
}

View File

@ -0,0 +1,146 @@
package kr.co.vividnext.sodalive.message
import com.querydsl.core.types.dsl.BooleanExpression
import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.message.QMessage.message
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface MessageRepository : JpaRepository<Message, Long>, MessageQueryRepository
interface MessageQueryRepository {
fun getSentTextMessageCount(memberId: Long): Int
fun getSentTextMessageList(pageable: Pageable, memberId: Long): List<Message>
fun getReceivedTextMessageCount(memberId: Long): Int
fun getReceivedTextMessageList(pageable: Pageable, memberId: Long): List<Message>
fun getKeepTextMessageCount(memberId: Long): Int
fun getKeepTextMessageList(pageable: Pageable, memberId: Long): List<Message>
fun getSentVoiceMessageCount(memberId: Long): Int
fun getSentVoiceMessageList(pageable: Pageable, memberId: Long): List<Message>
fun getReceivedVoiceMessageCount(memberId: Long): Int
fun getReceivedVoiceMessageList(pageable: Pageable, memberId: Long): List<Message>
fun getKeepVoiceMessageCount(memberId: Long): Int
fun getKeepVoiceMessageList(pageable: Pageable, memberId: Long): List<Message>
}
@Repository
class MessageQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : MessageQueryRepository {
override fun getSentTextMessageCount(memberId: Long): Int {
val where = message.messageType.eq(MessageType.TEXT)
.and(message.isSenderDelete.isFalse)
.and(message.sender.id.eq(memberId))
return totalCount(where)
}
override fun getSentTextMessageList(pageable: Pageable, memberId: Long): List<Message> {
val where = message.messageType.eq(MessageType.TEXT)
.and(message.isSenderDelete.isFalse)
.and(message.sender.id.eq(memberId))
return messageList(pageable, where)
}
override fun getReceivedTextMessageCount(memberId: Long): Int {
val where = message.messageType.eq(MessageType.TEXT)
.and(message.isRecipientDelete.isFalse)
.and(message.recipient.id.eq(memberId))
return totalCount(where)
}
override fun getReceivedTextMessageList(pageable: Pageable, memberId: Long): List<Message> {
val where = message.messageType.eq(MessageType.TEXT)
.and(message.isRecipientDelete.isFalse)
.and(message.recipient.id.eq(memberId))
return messageList(pageable, where)
}
override fun getKeepTextMessageCount(memberId: Long): Int {
val where = message.messageType.eq(MessageType.TEXT)
.and(message.isRecipientDelete.isFalse)
.and(message.isRecipientKeep.isTrue)
.and(message.recipient.id.eq(memberId))
return totalCount(where)
}
override fun getKeepTextMessageList(pageable: Pageable, memberId: Long): List<Message> {
val where = message.messageType.eq(MessageType.TEXT)
.and(message.isRecipientDelete.isFalse)
.and(message.isRecipientKeep.isTrue)
.and(message.recipient.id.eq(memberId))
return messageList(pageable, where)
}
override fun getSentVoiceMessageCount(memberId: Long): Int {
val where = message.messageType.eq(MessageType.VOICE)
.and(message.isSenderDelete.isFalse)
.and(message.sender.id.eq(memberId))
return totalCount(where)
}
override fun getSentVoiceMessageList(pageable: Pageable, memberId: Long): List<Message> {
val where = message.messageType.eq(MessageType.VOICE)
.and(message.isSenderDelete.isFalse)
.and(message.sender.id.eq(memberId))
return messageList(pageable, where)
}
override fun getReceivedVoiceMessageCount(memberId: Long): Int {
val where = message.messageType.eq(MessageType.VOICE)
.and(message.isRecipientDelete.isFalse)
.and(message.recipient.id.eq(memberId))
return totalCount(where)
}
override fun getReceivedVoiceMessageList(pageable: Pageable, memberId: Long): List<Message> {
val where = message.messageType.eq(MessageType.VOICE)
.and(message.isRecipientDelete.isFalse)
.and(message.recipient.id.eq(memberId))
return messageList(pageable, where)
}
override fun getKeepVoiceMessageCount(memberId: Long): Int {
val where = message.messageType.eq(MessageType.VOICE)
.and(message.isRecipientDelete.isFalse)
.and(message.isRecipientKeep.isTrue)
.and(message.recipient.id.eq(memberId))
return totalCount(where)
}
override fun getKeepVoiceMessageList(pageable: Pageable, memberId: Long): List<Message> {
val where = message.messageType.eq(MessageType.VOICE)
.and(message.isRecipientDelete.isFalse)
.and(message.isRecipientKeep.isTrue)
.and(message.recipient.id.eq(memberId))
return messageList(pageable, where)
}
private fun messageList(pageable: Pageable, where: BooleanExpression): List<Message> {
return queryFactory.selectFrom(message)
.offset(pageable.offset)
.limit(pageable.pageSize.toLong())
.where(where)
.orderBy(message.id.desc())
.fetch()
}
private fun totalCount(where: BooleanExpression): Int {
return queryFactory.select(message.id)
.from(message)
.where(where)
.fetch()
.size
}
}

View File

@ -0,0 +1,240 @@
package kr.co.vividnext.sodalive.message
import com.amazonaws.services.s3.model.ObjectMetadata
import com.fasterxml.jackson.databind.ObjectMapper
import kr.co.vividnext.sodalive.aws.s3.S3Uploader
import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.MemberRepository
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
import kr.co.vividnext.sodalive.utils.generateFileName
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.domain.Pageable
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.multipart.MultipartFile
import java.time.ZoneId
import java.time.format.DateTimeFormatter
@Service
@Transactional(readOnly = true)
class MessageService(
private val repository: MessageRepository,
private val memberRepository: MemberRepository,
private val blockMemberRepository: BlockMemberRepository,
private val objectMapper: ObjectMapper,
private val s3Uploader: S3Uploader,
@Value("\${cloud.aws.s3.bucket}")
private val bucket: String,
@Value("\${cloud.aws.cloud-front.host}")
private val cloudFrontHost: String
) {
@Transactional
fun sendTextMessage(request: SendTextMessageRequest, member: Member) {
val recipient = memberRepository.findByIdOrNull(request.recipientId)
?: throw SodaException("받는 사람이 없습니다.")
if (!recipient.isActive) {
throw SodaException("탈퇴한 유저에게는 메시지를 보내실 수 없습니다.")
}
val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = request.recipientId)
if (isBlocked) throw SodaException("${recipient.nickname}님의 요청으로 메시지를 보낼 수 없습니다.")
val sender = memberRepository.findByIdOrNull(member.id!!)
?: throw SodaException("로그인 정보를 확인해주세요.")
val message = Message(
textMessage = request.textMessage,
messageType = MessageType.TEXT
)
message.sender = sender
message.recipient = recipient
repository.save(message)
}
fun getSentTextMessages(member: Member, pageable: Pageable, timezone: String): GetTextMessageResponse {
val totalCount = repository.getSentTextMessageCount(memberId = member.id!!)
val messageList = repository.getSentTextMessageList(pageable, memberId = member.id!!)
return getTextMessageResponse(totalCount, messageList, timezone)
}
fun getReceivedTextMessages(member: Member, pageable: Pageable, timezone: String): GetTextMessageResponse {
val totalCount = repository.getReceivedTextMessageCount(memberId = member.id!!)
val messageList = repository.getReceivedTextMessageList(pageable, memberId = member.id!!)
return getTextMessageResponse(totalCount, messageList, timezone)
}
fun getKeepTextMessages(member: Member, pageable: Pageable, timezone: String): GetTextMessageResponse {
val totalCount = repository.getKeepTextMessageCount(memberId = member.id!!)
val messageList = repository.getKeepTextMessageList(pageable, memberId = member.id!!)
return getTextMessageResponse(totalCount, messageList, timezone)
}
@Transactional
fun keepTextMessage(messageId: Long, member: Member) {
keepMessage(messageId, member)
}
@Transactional
fun sendVoiceMessage(voiceMessageFile: MultipartFile, requestString: String, member: Member) {
val request = objectMapper.readValue(requestString, SendVoiceMessageRequest::class.java)
val recipient = memberRepository.findByIdOrNull(request.recipientId)
?: throw SodaException("받는 사람이 없습니다.")
if (!recipient.isActive) {
throw SodaException("탈퇴한 유저에게는 메시지를 보내실 수 없습니다.")
}
val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = request.recipientId)
if (isBlocked) throw SodaException("${recipient.nickname}님의 요청으로 메시지를 보낼 수 없습니다.")
val sender = memberRepository.findByIdOrNull(member.id!!)
?: throw SodaException("로그인 정보를 확인해주세요.")
val message = Message(messageType = MessageType.VOICE)
message.sender = sender
message.recipient = recipient
repository.save(message)
val metadata = ObjectMetadata()
metadata.contentLength = voiceMessageFile.size
val messagePath = s3Uploader.upload(
inputStream = voiceMessageFile.inputStream,
bucket = bucket,
filePath = "voice_message/${message.id}/${generateFileName(prefix = "${message.id}-message-")}",
metadata = metadata
)
message.voiceMessage = messagePath
}
fun getSentVoiceMessages(member: Member, pageable: Pageable, timezone: String): GetVoiceMessageResponse {
val totalCount = repository.getSentVoiceMessageCount(memberId = member.id!!)
val messageList = repository.getSentVoiceMessageList(pageable, memberId = member.id!!)
return getVoiceMessageResponse(totalCount, messageList, timezone)
}
fun getReceivedVoiceMessages(member: Member, pageable: Pageable, timezone: String): GetTextMessageResponse {
val totalCount = repository.getReceivedVoiceMessageCount(memberId = member.id!!)
val messageList = repository.getReceivedVoiceMessageList(pageable, memberId = member.id!!)
return getTextMessageResponse(totalCount, messageList, timezone)
}
fun getKeepVoiceMessages(member: Member, pageable: Pageable, timezone: String): GetTextMessageResponse {
val totalCount = repository.getKeepVoiceMessageCount(memberId = member.id!!)
val messageList = repository.getKeepVoiceMessageList(pageable, memberId = member.id!!)
return getTextMessageResponse(totalCount, messageList, timezone)
}
@Transactional
fun keepVoiceMessage(messageId: Long, member: Member) {
keepMessage(messageId, member)
}
@Transactional
fun deleteMessage(messageId: Long, member: Member) {
val message = repository.findByIdOrNull(messageId)
?: throw SodaException("해당하는 메시지가 없습니다.\n다시 확인해 주시기 바랍니다.")
if (message.sender!!.id!! == member.id!!) {
message.isSenderDelete = true
} else if (message.recipient!!.id!! == member.id!!) {
message.isRecipientDelete = true
}
}
private fun getTextMessageResponse(
totalCount: Int,
messageList: List<Message>,
timezone: String
) = GetTextMessageResponse(
totalCount = totalCount,
items = messageList.asSequence()
.map {
val createdAt = it.createdAt!!
.atZone(ZoneId.of("UTC"))
.withZoneSameInstant(ZoneId.of(timezone))
GetTextMessageResponse.TextMessageItem(
messageId = it.id!!,
senderId = it.sender!!.id!!,
senderNickname = it.sender!!.nickname,
senderProfileImageUrl = if (it.sender!!.profileImage != null) {
"$cloudFrontHost/${it.sender!!.profileImage}"
} else {
"$cloudFrontHost/profile/default-profile.png"
},
recipientNickname = it.recipient!!.nickname,
recipientProfileImageUrl = if (it.recipient!!.profileImage != null) {
"$cloudFrontHost/${it.recipient!!.profileImage}"
} else {
"$cloudFrontHost/profile/default-profile.png"
},
textMessage = it.textMessage!!,
date = createdAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
isKept = false
)
}
.toList()
)
private fun getVoiceMessageResponse(
totalCount: Int,
messageList: List<Message>,
timezone: String
) = GetVoiceMessageResponse(
totalCount = totalCount,
items = messageList.asSequence()
.map {
val createdAt = it.createdAt!!
.atZone(ZoneId.of("UTC"))
.withZoneSameInstant(ZoneId.of(timezone))
GetVoiceMessageResponse.VoiceMessageItem(
messageId = it.id!!,
senderId = it.sender!!.id!!,
senderNickname = it.sender!!.nickname,
senderProfileImageUrl = if (it.sender!!.profileImage != null) {
"$cloudFrontHost/${it.sender!!.profileImage}"
} else {
"$cloudFrontHost/profile/default-profile.png"
},
recipientNickname = it.recipient!!.nickname,
recipientProfileImageUrl = if (it.recipient!!.profileImage != null) {
"$cloudFrontHost/${it.recipient!!.profileImage}"
} else {
"$cloudFrontHost/profile/default-profile.png"
},
voiceMessageUrl = "$cloudFrontHost/${it.voiceMessage!!}",
date = createdAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
isKept = it.isRecipientKeep
)
}
.toList()
)
private fun keepMessage(messageId: Long, member: Member) {
val message = repository.findByIdOrNull(messageId)
?: throw SodaException("잘못된 요청입니다.")
if (message.recipient != member) {
throw SodaException("잘못된 요청입니다.")
}
if (message.isRecipientKeep) {
throw SodaException("이미 보관된 메시지 입니다.")
}
message.isRecipientKeep = true
}
}

View File

@ -0,0 +1,5 @@
package kr.co.vividnext.sodalive.message
data class SendVoiceMessageRequest(val recipientId: Long, val container: String)
data class SendTextMessageRequest(val recipientId: Long, val textMessage: String, val container: String)