Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Chat] 서버 전체 채팅 조회 API 구현 GET api/v1/chat #145

Merged
merged 21 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
83c87d3
Merge pull request #141 from kSideProject/dev
yudonggeun May 30, 2024
a824d5f
chore: serverClient base url값 추가
minisundev Jun 2, 2024
7b0d1ba
feat: core의 AuthConfig를 가져와서 사용하게 함
minisundev Jun 2, 2024
9ebca75
feat: Controller Layer에 getChats method 구현
minisundev Jun 2, 2024
4c245e4
feat: Service Layer에 getChats method 구현
minisundev Jun 2, 2024
e1e949e
refac: Chat을 RoomChat으로 변경
minisundev Jun 2, 2024
2eb2d98
feat: ServerChat model 생성
minisundev Jun 2, 2024
848052a
feat: ServerChatRepository 생성
minisundev Jun 2, 2024
99ec231
feat: ServerClient 생성
minisundev Jun 2, 2024
fa7e126
feat: ServerClientConfig 생성
minisundev Jun 2, 2024
a0def5e
feat: core의 ServerConfig import해서 사용
minisundev Jun 2, 2024
88be642
feat: ErrorCode 변경
minisundev Jun 2, 2024
cb614a1
refac: Chat을 RoomChat으로 변경
minisundev Jun 2, 2024
8e255cf
refac: sentAt을 LocalDateTime에서 String으로 변경
minisundev Jun 2, 2024
81ecf3c
refac: 메서드명, 에러코드명 변경
minisundev Jun 2, 2024
b5fdf77
refac: Chat을 RoomChat으로 변경
minisundev Jun 2, 2024
cebb203
feat: ChatControllerTest에 getChats test code 작성
minisundev Jun 2, 2024
68f158a
feat: ChatServiceTest에 getChats test code 작성
minisundev Jun 2, 2024
3967416
refac: ChatType에 의한 케이스 분리 if 대신 when 사용
minisundev Jun 2, 2024
9127519
style: 가독성을 위한 코드 줄 바꿈
minisundev Jun 2, 2024
dba4c47
refac: Service에서만 사용하는 메서드 private 처리
minisundev Jun 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions chat/src/main/kotlin/kpring/chat/chat/api/v1/ChatController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package kpring.chat.chat.api.v1
import kpring.chat.chat.service.ChatService
import kpring.core.auth.client.AuthClient
import kpring.core.chat.chat.dto.request.CreateChatRequest
import kpring.core.chat.chat.dto.response.ChatResponse
import kpring.core.global.dto.response.ApiResponse
import kpring.core.server.client.ServerClient
import kpring.core.server.dto.request.GetServerCondition
import org.springframework.http.ResponseEntity
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
Expand All @@ -12,6 +16,7 @@ import org.springframework.web.bind.annotation.*
class ChatController(
private val chatService: ChatService,
val authClient: AuthClient,
val serverClient: ServerClient,
) {
@PostMapping("/chat")
fun createChat(
Expand All @@ -23,14 +28,23 @@ class ChatController(
return ResponseEntity.ok().body(result)
}

@GetMapping("/chat/{chatRoomId}/{page}")
fun getChatsByChatRoom(
@PathVariable("chatRoomId") chatRoomId: String,
@PathVariable("page") page: Int,
@GetMapping("/chat")
fun getChats(
@RequestParam("type") type: String,
@RequestParam("id") id: String,
@RequestParam("page") page: Int,
@RequestHeader("Authorization") token: String,
): ResponseEntity<*> {
val userId = authClient.getTokenInfo(token).data!!.userId
val result = chatService.getChatsByChatRoom(chatRoomId, userId, page)
return ResponseEntity.ok().body(result)
var result: List<ChatResponse>? = null

if (type.equals("Room")) {
result = chatService.getRoomChats(id, userId, page)
} else if (type.equals("Server")) {
val serverList = serverClient.getServerList(token, GetServerCondition()).body!!.data!!
result = chatService.getServerChats(id, userId, page, serverList)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기는 chattype이 없네요?

Copy link
Member Author

@minisundev minisundev Jun 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 ChatType을 받을까 하다가 requestParam 방식으로 받게 되어서 저렇게 했는데 ChatType.ROOM.toString()이라도 쓰는게 나아보이긴 하네요~! 다시 보니 createServerChat할때 만든 ChatType이 merge되지 않아서 쓸 수 없었어요..!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

val result = when(type) {
  "Server" -> return chatService.getRoomChats(id, userId, page)
  "Room" -> return chatService.getServerList(token, ..)
}

when을 이용하면 var을 안써도 괜찮을 것 같아요.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋네요~!


return ResponseEntity.ok().body(ApiResponse(data = result, status = 200))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.springframework.data.mongodb.core.mapping.Document

@NoArg
@Document(collection = "chats")
class Chat(
class RoomChat(
val userId: String,
val roomId: String,
val content: String,
Expand Down
21 changes: 21 additions & 0 deletions chat/src/main/kotlin/kpring/chat/chat/model/ServerChat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package kpring.chat.chat.model

import kpring.chat.NoArg
import kpring.chat.global.model.BaseTime
import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.mapping.Document

@NoArg
@Document(collection = "server_chats")
class ServerChat(
val userId: String,
val serverId: String,
val content: String,
) : BaseTime() {
@Id
var id: String? = null

fun isEdited(): Boolean {
return !createdAt.equals(updatedAt)
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package kpring.chat.chat.repository

import kpring.chat.chat.model.Chat
import kpring.chat.chat.model.RoomChat
import org.springframework.data.domain.Pageable
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.querydsl.QuerydslPredicateExecutor
import org.springframework.stereotype.Repository

@Repository
interface ChatRepository : MongoRepository<Chat, String>, QuerydslPredicateExecutor<Chat> {
interface RoomChatRepository : MongoRepository<RoomChat, String>, QuerydslPredicateExecutor<RoomChat> {
fun findAllByRoomId(
roomId: String,
pageable: Pageable,
): List<Chat>
): List<RoomChat>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package kpring.chat.chat.repository

import kpring.chat.chat.model.ServerChat
import org.springframework.data.domain.Pageable
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.querydsl.QuerydslPredicateExecutor
import org.springframework.stereotype.Repository

@Repository
interface ServerChatRepository : MongoRepository<ServerChat, String>, QuerydslPredicateExecutor<ServerChat> {
fun findAllByServerId(
serverId: String,
pageable: Pageable,
): List<ServerChat>
}
75 changes: 54 additions & 21 deletions chat/src/main/kotlin/kpring/chat/chat/service/ChatService.kt
Original file line number Diff line number Diff line change
@@ -1,69 +1,102 @@
package kpring.chat.chat.service

import kpring.chat.chat.model.Chat
import kpring.chat.chat.repository.ChatRepository
import kpring.chat.chat.model.RoomChat
import kpring.chat.chat.model.ServerChat
import kpring.chat.chat.repository.RoomChatRepository
import kpring.chat.chat.repository.ServerChatRepository
import kpring.chat.chatroom.repository.ChatRoomRepository
import kpring.chat.global.exception.ErrorCode
import kpring.chat.global.exception.GlobalException
import kpring.core.chat.chat.dto.request.CreateChatRequest
import kpring.core.chat.chat.dto.response.ChatResponse
import kpring.core.server.dto.ServerSimpleInfo
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service

@Service
class ChatService(
private val chatRepository: ChatRepository,
private val roomChatRepository: RoomChatRepository,
private val serverChatRepository: ServerChatRepository,
private val chatRoomRepository: ChatRoomRepository,
@Value("\${page.size}") val pageSize: Int = 100,
) {
/*
business logic
*/
fun createChat(
request: CreateChatRequest,
userId: String,
) {
val chat =
chatRepository.save(
Chat(
val roomChat =
roomChatRepository.save(
RoomChat(
userId = userId,
roomId = request.room,
content = request.content,
),
)
}

fun getChatsByChatRoom(
fun getRoomChats(
chatRoomId: String,
userId: String,
page: Int,
): List<ChatResponse> {
checkIfAuthorized(chatRoomId, userId)
verifyChatRoomAccess(chatRoomId, userId)

// find chats by chatRoomId and convert them into DTOs
val pageable: Pageable = PageRequest.of(page, pageSize)
val chats: List<Chat> = chatRepository.findAllByRoomId(chatRoomId, pageable)
val roomChats: List<RoomChat> = roomChatRepository.findAllByRoomId(chatRoomId, pageable)

return convertChatsToResponses(chats)
return convertRoomChatsToResponses(roomChats)
}

fun checkIfAuthorized(
fun getServerChats(
serverId: String,
userId: String,
page: Int,
servers: List<ServerSimpleInfo>,
): List<ChatResponse> {
verifyServerAccess(servers, serverId)

val pageable: Pageable = PageRequest.of(page, pageSize)
val chats: List<ServerChat> = serverChatRepository.findAllByServerId(serverId, pageable)

return convertServerChatsToResponses(chats)
}

fun verifyServerAccess(
servers: List<ServerSimpleInfo>,
serverId: String,
) {
servers.forEach { info ->
if (info.id.equals(serverId)) {
return
}
}
throw GlobalException(ErrorCode.FORBIDDEN_SERVER)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ServiceException을 사용하지 않고 GlobalException을 사용하신 이유가 있을까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

에러 핸들러를 추가할 필요가 없다고 생각해서 공용으로 쓰고 있었습니다~

}

fun verifyChatRoomAccess(
chatRoomId: String,
userId: String,
) {
// check if there is a chatroom with the chatRoomId and the user is one of the members
if (!chatRoomRepository.existsByIdAndMembersContaining(chatRoomId, userId)) {
throw GlobalException(ErrorCode.UNAUTHORIZED_CHATROOM)
throw GlobalException(ErrorCode.FORBIDDEN_CHATROOM)
}
}

fun convertChatsToResponses(chats: List<Chat>): List<ChatResponse> {
val chatResponses =
fun convertRoomChatsToResponses(roomChats: List<RoomChat>): List<ChatResponse> {
val chatResponse =
roomChats.map { chat ->
ChatResponse(chat.id!!, chat.isEdited(), chat.createdAt.toString(), chat.content)
}
return chatResponse
}

fun convertServerChatsToResponses(chats: List<ServerChat>): List<ChatResponse> {
val chatResponse =
chats.map { chat ->
ChatResponse(chat.roomId, chat.isEdited(), chat.createdAt, chat.content)
ChatResponse(chat.id!!, chat.isEdited(), chat.createdAt.toString(), chat.content)
}
return chatResponses
return chatResponse
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확장된 기능이 아니라면 private하는 것은 어떨까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은 지적이네요~!

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,18 @@ class ChatRoomService(
chatRoomId: String,
userId: String,
) {
verifyAuthorizationForChatRoom(chatRoomId, userId)
verifyChatRoomAccess(chatRoomId, userId)
val chatRoom: ChatRoom = getChatRoom(chatRoomId)
chatRoom.removeUser(userId)
chatRoomRepository.save(chatRoom)
}

fun verifyAuthorizationForChatRoom(
fun verifyChatRoomAccess(
chatRoomId: String,
userId: String,
) {
// check if there is a chatroom with the chatRoomId and the user is one of the members
if (!chatRoomRepository.existsByIdAndMembersContaining(chatRoomId, userId)) {
throw GlobalException(ErrorCode.UNAUTHORIZED_CHATROOM)
throw GlobalException(ErrorCode.FORBIDDEN_CHATROOM)
}
}

Expand Down
9 changes: 9 additions & 0 deletions chat/src/main/kotlin/kpring/chat/global/config/AuthConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kpring.chat.global.config

import kpring.core.auth.config.AuthClientConfig
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import

@Import(AuthClientConfig::class)
@Configuration
class AuthConfig
26 changes: 0 additions & 26 deletions chat/src/main/kotlin/kpring/chat/global/config/ClientConfig.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kpring.chat.global.config

import kpring.core.server.config.ServerClientConfig
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import

@Import(ServerClientConfig::class)
@Configuration
class ServerConfig
10 changes: 3 additions & 7 deletions chat/src/main/kotlin/kpring/chat/global/exception/ErrorCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@ package kpring.chat.global.exception
import org.springframework.http.HttpStatus

enum class ErrorCode(val httpStatus: Int, val message: String) {
// 400
INVALID_TOKEN(HttpStatus.BAD_REQUEST.value(), "토큰이 유효하지 않습니다"),

// 401
UNAUTHORIZED_CHATROOM(HttpStatus.UNAUTHORIZED.value(), "접근이 제한된 채팅방 입니다"),
// 403
FORBIDDEN_CHATROOM(HttpStatus.FORBIDDEN.value(), "접근이 제한된 채팅방 입니다"),
FORBIDDEN_SERVER(HttpStatus.FORBIDDEN.value(), "접근이 제한된 서버 입니다"),

// 404
INVALID_TOKEN_BODY(HttpStatus.NOT_FOUND.value(), "토큰의 body가 유효하지 않습니다"),
USERID_NOT_EXIST(HttpStatus.NOT_FOUND.value(), "토큰의 userId가 존재하지 않습니다"),
CHATROOM_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "해당 id로 chatroom을 찾을 수 없습니다"),
}
4 changes: 3 additions & 1 deletion chat/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ server:
port: 8081

auth:
url: "http://localhost:8080/"
url: "http://localhost:30000/"
url:
server: "http://localhost:8080/"
page:
size: 100
Loading