Skip to content

Commit

Permalink
Merge pull request #302 from jihyun-j/main
Browse files Browse the repository at this point in the history
dev브랜치 코드 main브랜치로 병합
  • Loading branch information
minisundev authored Nov 24, 2024
2 parents 84cc4c7 + 2e7be6b commit 48a4b02
Show file tree
Hide file tree
Showing 226 changed files with 113,638 additions and 8,154 deletions.
Binary file added .DS_Store
Binary file not shown.
22 changes: 22 additions & 0 deletions .github/ISSUE_TEMPLATE/스토리-기능-명세.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: 스토리 기능 명세
about: 요구사항 명세
title: ''
labels: ''
assignees: ''

---

## 🤔 어떤 요구사항을 구현하나요?

> 구현하고자 하는 요구사항을 적어주세요. 개발자가 아니더라도 이해할 수 있도록 직관적으로 작성해주는 것을 권장해요.
## ✅ 하위 기능 명세

> 추상화된 해당 요구사항을 구현하기 위한 구체적인 Task 목록을 작성해주세요.
- [ ] TODO
- [ ] TODO

## 📚 참고할만한 자료(선택)
> 개발을 하면서 참고한 자료나 배경 지식을 공유하고 싶다면 링크나 설명을 추가해주세요.
> 해당 기능과 관련된 다른 이슈 링크가 있다면 작성해주세요.
9 changes: 6 additions & 3 deletions .github/ISSUE_TEMPLATE/추가-기능-구현.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ assignees: ''

---

## 어떤 기능인가요?
## 🤔 어떤 기능인가요?

> 추가하려는 기능에 대해 간결하게 설명해주세요
## 작업 상세 내용
## 작업 상세 내용

> 개발하는 기능에 대해서 구체적으로 어떤 것을 고려해야하는지를 작성해주세요.
> API 스펙이나 비지니스 관련된 제약 등 누군가 문서를 보고 작업을 이어서 할 수 있도록 자세히 해주면 좋아요!
- [ ] TODO
- [ ] TODO
- [ ] TODO

## 참고할만한 자료(선택)
## 📚 참고할만한 자료(선택)
> 개발을 하면서 참고한 자료나 배경 지식을 공유하고 싶다면 링크나 설명을 추가해주세요.
5 changes: 4 additions & 1 deletion .github/workflows/pr-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ jobs:

# Gradle test를 실행한다
- name: Test with Gradle
run: ./gradlew --info test
run: |
./gradlew --info :user:test -Dspring.profiles.active=dev && \
./gradlew --info :server:test -Dspring.profiles.active=dev && \
./gradlew --info test -x :user:test -x :server:test
16 changes: 16 additions & 0 deletions chat/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ dependencies {
// core module
api(project(":core"))

compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")

// mongodb
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
implementation("com.querydsl:querydsl-mongodb:$queryDslVersion") {
Expand Down Expand Up @@ -67,6 +70,19 @@ dependencies {
// default test
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation(project(":test"))

// websocket
implementation("org.springframework.boot:spring-boot-starter-websocket")
implementation("com.fasterxml.jackson.core:jackson-databind")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")

// websocket security
implementation("org.springframework.security:spring-security-messaging")

// Web Security
implementation("org.springframework.boot:spring-boot-starter-security")
}

kapt {
Expand Down
38 changes: 21 additions & 17 deletions chat/src/main/kotlin/kpring/chat/chat/api/v1/ChatController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import kpring.chat.chat.service.ChatService
import kpring.chat.global.exception.ErrorCode
import kpring.chat.global.exception.GlobalException
import kpring.core.auth.client.AuthClient
import kpring.core.chat.chat.dto.request.ChatType
import kpring.core.chat.chat.dto.request.CreateChatRequest
import kpring.core.chat.chat.dto.request.UpdateChatRequest
import kpring.core.chat.model.ChatType
import kpring.core.global.dto.response.ApiResponse
import kpring.core.server.client.ServerClient
import kpring.core.server.dto.request.GetServerCondition
Expand All @@ -22,6 +22,7 @@ class ChatController(
private val authClient: AuthClient,
private val serverClient: ServerClient,
) {
@Deprecated("WebSocketChatController를 대신 사용")
@PostMapping("/chat")
fun createChat(
@Validated @RequestBody request: CreateChatRequest,
Expand All @@ -30,62 +31,65 @@ class ChatController(
val userId = authClient.getTokenInfo(token).data!!.userId

when (request.type) {
ChatType.Room -> chatService.createRoomChat(request, userId)
ChatType.Server -> chatService.createServerChat(request, userId)
ChatType.ROOM -> chatService.createRoomChat(request, userId)
ChatType.SERVER ->
chatService.createServerChat(
request,
userId,
serverClient.getServerList(token, GetServerCondition()).body!!.data!!,
)
else -> throw GlobalException(ErrorCode.INVALID_CHAT_TYPE)
}

return ResponseEntity(ApiResponse<Nothing>(status = 201), HttpStatus.CREATED)
}

@Deprecated("WebSocketChatController를 대신 사용")
@GetMapping("/chat")
fun getChats(
@RequestParam("type") type: ChatType,
@RequestParam("id") id: String,
@RequestParam("page") page: Int,
@RequestParam("size") size: Int,
@RequestHeader("Authorization") token: String,
): ResponseEntity<*> {
val userId = authClient.getTokenInfo(token).data!!.userId
val result =
when (type) {
ChatType.Room -> chatService.getRoomChats(id, userId, page)
ChatType.Server ->
ChatType.ROOM -> chatService.getRoomChats(id, userId, page, size)
ChatType.SERVER ->
chatService.getServerChats(
id,
userId,
page,
size,
serverClient.getServerList(token, GetServerCondition()).body!!.data!!,
)
)else -> {
throw GlobalException(ErrorCode.INVALID_CHAT_TYPE)
}
}
return ResponseEntity.ok().body(ApiResponse(data = result, status = 200))
}

@Deprecated("WebSocketChatController를 대신 사용")
@PatchMapping("/chat")
fun updateChat(
@Validated @RequestBody request: UpdateChatRequest,
@RequestHeader("Authorization") token: String,
): ResponseEntity<*> {
val userId = authClient.getTokenInfo(token).data!!.userId
val result =
when (request.type) {
ChatType.Room -> chatService.updateRoomChat(request, userId)
ChatType.Server -> chatService.updateServerChat(request, userId)
}
val result = chatService.updateChat(request, userId)
return ResponseEntity.ok().body(ApiResponse<Nothing>(status = 200))
}

@Deprecated("WebSocketChatController를 대신 사용")
@DeleteMapping("/chat/{chatId}")
fun deleteChat(
@RequestParam("type") type: ChatType,
@PathVariable("chatId") chatId: String,
@RequestHeader("Authorization") token: String,
): ResponseEntity<*> {
val userId = authClient.getTokenInfo(token).data!!.userId
val result =
when (type) {
ChatType.Room -> chatService.deleteRoomChat(chatId, userId)
ChatType.Server -> chatService.deleteServerChat(chatId, userId)
}
val result = chatService.deleteChat(chatId, userId)
return ResponseEntity.ok().body(ApiResponse<Nothing>(status = 200))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package kpring.chat.chat.api.v1

import kpring.chat.chat.service.ChatService
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.request.DeleteChatRequest
import kpring.core.chat.chat.dto.request.GetChatsRequest
import kpring.core.chat.chat.dto.request.UpdateChatRequest
import kpring.core.chat.model.ChatType
import kpring.core.server.client.ServerClient
import kpring.core.server.dto.request.GetServerCondition
import lombok.RequiredArgsConstructor
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.messaging.handler.annotation.MessageMapping
import org.springframework.messaging.handler.annotation.Payload
import org.springframework.messaging.simp.SimpMessageHeaderAccessor
import org.springframework.messaging.simp.SimpMessagingTemplate
import org.springframework.stereotype.Controller
import org.springframework.validation.annotation.Validated
import java.security.Principal

@Controller
@RequiredArgsConstructor
class WebSocketChatController(
private val chatService: ChatService,
private val serverClient: ServerClient,
private val simpMessagingTemplate: SimpMessagingTemplate,
) {
private val logger: Logger = LoggerFactory.getLogger(WebSocketChatController::class.java)

@MessageMapping("/chat/create")
fun createChat(
@Payload @Validated request: CreateChatRequest,
principal: Principal,
headerAccessor: SimpMessageHeaderAccessor,
) {
val token = headerAccessor.getFirstNativeHeader("Authorization") ?: throw GlobalException(ErrorCode.MISSING_TOKEN)
val userId = principal.name
val contextId = request.contextId

val result =
when (request.type) {
ChatType.ROOM -> chatService.createRoomChat(request, userId)
ChatType.SERVER ->
chatService.createServerChat(
request,
userId,
serverClient.getServerList(token, GetServerCondition()).body!!.data!!,
)
}
simpMessagingTemplate.convertAndSend("/topic/chatroom/$contextId", result)
}

@MessageMapping("/chat/update")
fun updateChat(
@Payload @Validated request: UpdateChatRequest,
principal: Principal,
) {
val userId = principal.name
val contextId = request.contextId

val result = chatService.updateChat(request, userId)
simpMessagingTemplate.convertAndSend("/topic/chatroom/$contextId", result)
}

@MessageMapping("/chat/delete")
fun deleteChat(
@Payload @Validated request: DeleteChatRequest,
principal: Principal,
) {
val userId = principal.name
val chatId = request.id
val contextId = request.contextId

val result = chatService.deleteChat(chatId, userId)
simpMessagingTemplate.convertAndSend("/topic/chatroom/$contextId", result)
}

@MessageMapping("/chat")
fun getChats(
@Payload @Validated request: GetChatsRequest,
principal: Principal,
headerAccessor: SimpMessageHeaderAccessor,
) {
val token = headerAccessor.getFirstNativeHeader("Authorization") ?: throw GlobalException(ErrorCode.MISSING_TOKEN)
val userId = principal.name
val type = request.type
val contextId = request.contextId
val page = request.page
val size = request.size

val result =
when (type) {
ChatType.ROOM -> chatService.getRoomChats(contextId, userId, page, size)
ChatType.SERVER ->
chatService.getServerChats(
contextId,
userId,
page,
size,
serverClient.getServerList(token, GetServerCondition()).body!!.data!!,
)
}
logger.info("Chat result: $result")
simpMessagingTemplate.convertAndSend("/topic/chatroom/$contextId", result)
}
}
4 changes: 4 additions & 0 deletions chat/src/main/kotlin/kpring/chat/chat/model/Chat.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package kpring.chat.chat.model

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

Expand All @@ -11,6 +13,8 @@ class Chat(
@Id
val id: String? = null,
val userId: String,
val chatType: ChatType,
val eventType: EventType,
// roomId or serverId
val contextId: String,
var content: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package kpring.chat.chat.repository

import kpring.chat.chat.model.Chat
import kpring.core.chat.model.ChatType
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Sort
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Criteria
import org.springframework.data.mongodb.core.query.Query
import org.springframework.data.support.PageableExecutionUtils
import org.springframework.stereotype.Repository

@Repository
class ChatCustomRepository(
private val mongoTemplate: MongoTemplate,
) {
fun findListByContextIdWithPaging(
contextId: String,
page: Int,
size: Int,
type: ChatType,
): List<Chat> {
val sort: Sort = Sort.by(Sort.Order.desc("createdAt"))
val pageable: Pageable = PageRequest.of(page, size, sort)
var query: Query =
Query(
Criteria.where("contextId").`is`(contextId).and("chatType").`is`(type),
).with(pageable)
return mongoTemplate.find(query, Chat::class.java)
}

fun findPageByContextIdWithPaging(
contextId: String,
page: Int,
size: Int,
type: ChatType,
): Page<Chat> {
val sort: Sort = Sort.by(Sort.Order.desc("createdAt"))
val pageable: Pageable = PageRequest.of(page, size, sort)
val query: Query =
Query(
Criteria.where("contextId").`is`(contextId).and("chatType").`is`(type),
).with(pageable)
val list: List<Chat> = mongoTemplate.find(query, Chat::class.java)
return PageableExecutionUtils.getPage(
list,
pageable,
{
mongoTemplate.count(Query.of(query).limit(-1).skip(-1), Chat::class.java)
},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kpring.chat.chat.repository

import kpring.chat.chat.model.Chat
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.querydsl.QuerydslPredicateExecutor

interface ChatRepository : MongoRepository<Chat, String>, QuerydslPredicateExecutor<Chat>

This file was deleted.

Loading

0 comments on commit 48a4b02

Please sign in to comment.