Skip to content

Commit

Permalink
Merge pull request #111 from soma-baekgu/feature/BG-244-reaction-comm…
Browse files Browse the repository at this point in the history
…ent-create

[BG-244]: 리엑션 이벤트에 대한 응답 등록 API를 개발한다 (2h / 3h)
  • Loading branch information
Dltmd202 authored Sep 7, 2024
2 parents b3e0f66 + 636c33e commit fed1d09
Show file tree
Hide file tree
Showing 21 changed files with 389 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package com.backgu.amaker.api.event.config

import com.backgu.amaker.application.event.service.EventAssignedUserService
import com.backgu.amaker.application.event.service.EventService
import com.backgu.amaker.application.event.service.ReactionCommentService
import com.backgu.amaker.application.event.service.ReactionEventService
import com.backgu.amaker.application.event.service.ReactionOptionService
import com.backgu.amaker.application.event.service.ReplyCommentService
import com.backgu.amaker.application.event.service.ReplyEventService
import com.backgu.amaker.infra.jpa.event.repository.EventAssignedUserRepository
import com.backgu.amaker.infra.jpa.event.repository.EventRepository
import com.backgu.amaker.infra.jpa.event.repository.ReactionCommentRepository
import com.backgu.amaker.infra.jpa.event.repository.ReactionEventRepository
import com.backgu.amaker.infra.jpa.event.repository.ReactionOptionRepository
import com.backgu.amaker.infra.jpa.event.repository.ReplyCommentRepository
Expand Down Expand Up @@ -38,4 +40,8 @@ class EventServiceConfig {
@Bean
fun reactionOptionService(reactionOptionRepository: ReactionOptionRepository): ReactionOptionService =
ReactionOptionService(reactionOptionRepository)

@Bean
fun reactionCommentService(reactionCommentRepository: ReactionCommentRepository): ReactionCommentService =
ReactionCommentService(reactionCommentRepository)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.backgu.amaker.api.event.controller

import com.backgu.amaker.api.event.dto.query.ReplyQueryRequest
import com.backgu.amaker.api.event.dto.request.ReactionCommentCreateRequest
import com.backgu.amaker.api.event.dto.request.ReplyCommentCreateRequest
import com.backgu.amaker.api.event.dto.response.ReplyCommentWithUserResponse
import com.backgu.amaker.api.event.dto.response.ReplyCommentsViewResponse
Expand Down Expand Up @@ -29,16 +30,6 @@ class EventCommentController(
private val eventCommentFacadeService: EventCommentFacadeService,
private val apiHandler: ApiHandler,
) : EventCommentSwagger {
@PostMapping("/events/{event-id}/reply/comments")
override fun createReplyComment(
@AuthenticationPrincipal token: JwtAuthentication,
@PathVariable("event-id") eventId: Long,
@RequestBody @Valid replyCommentCreateRequest: ReplyCommentCreateRequest,
): ResponseEntity<Unit> {
eventCommentFacadeService.createReplyComment(token.id, eventId, replyCommentCreateRequest.toDto())
return ResponseEntity.status(HttpStatus.CREATED).build()
}

@GetMapping("/events/{event-id}/reply/comments")
override fun findReplyComments(
@AuthenticationPrincipal token: JwtAuthentication,
Expand All @@ -63,4 +54,24 @@ class EventCommentController(
),
)
}

@PostMapping("/events/{event-id}/reply/comments")
override fun createReplyComment(
@AuthenticationPrincipal token: JwtAuthentication,
@PathVariable("event-id") eventId: Long,
@RequestBody @Valid replyCommentCreateRequest: ReplyCommentCreateRequest,
): ResponseEntity<Unit> {
eventCommentFacadeService.createReplyComment(token.id, eventId, replyCommentCreateRequest.toDto())
return ResponseEntity.status(HttpStatus.CREATED).build()
}

@PostMapping("/events/{event-id}/reaction/comments")
override fun createReactionComment(
@AuthenticationPrincipal token: JwtAuthentication,
@PathVariable("event-id") eventId: Long,
@RequestBody @Valid reactionCommentCreateRequest: ReactionCommentCreateRequest,
): ResponseEntity<Unit> {
eventCommentFacadeService.createReactionComment(token.id, eventId, reactionCommentCreateRequest.toDto())
return ResponseEntity.status(HttpStatus.CREATED).build()
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.backgu.amaker.api.event.controller

import com.backgu.amaker.api.event.dto.query.ReplyQueryRequest
import com.backgu.amaker.api.event.dto.request.ReactionCommentCreateRequest
import com.backgu.amaker.api.event.dto.request.ReplyCommentCreateRequest
import com.backgu.amaker.api.event.dto.response.ReplyCommentWithUserResponse
import com.backgu.amaker.common.http.response.ApiResult
Expand All @@ -14,6 +15,21 @@ import org.springframework.http.ResponseEntity

@Tag(name = "eventComment", description = "이벤트 응답 API")
interface EventCommentSwagger {
@Operation(summary = "reply 이벤트 응답 조회", description = "reply 이벤트 응답 조회합니다.")
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "reply 이벤트 응답 조회 성공",
),
],
)
fun findReplyComments(
token: JwtAuthentication,
eventId: Long,
replyQueryRequest: ReplyQueryRequest,
): ResponseEntity<ApiResult<PageResponse<ReplyCommentWithUserResponse>>>

@Operation(summary = "reply 이벤트 응답 생성", description = "reply 이벤트 응답 생성합니다.")
@ApiResponses(
value = [
Expand All @@ -29,18 +45,18 @@ interface EventCommentSwagger {
replyCommentCreateRequest: ReplyCommentCreateRequest,
): ResponseEntity<Unit>

@Operation(summary = "reply 이벤트 응답 조회", description = "reply 이벤트 응답 조회합니다.")
@Operation(summary = "reaction 이벤트 응답 생성", description = "reaction 이벤트 응답 생성합니다.")
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "reply 이벤트 응답 조회 성공",
responseCode = "201",
description = "reaction 이벤트 응답 생성 성공",
),
],
)
fun findReplyComments(
fun createReactionComment(
token: JwtAuthentication,
eventId: Long,
replyQueryRequest: ReplyQueryRequest,
): ResponseEntity<ApiResult<PageResponse<ReplyCommentWithUserResponse>>>
reactionCommentCreateRequest: ReactionCommentCreateRequest,
): ResponseEntity<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.backgu.amaker.api.event.dto

data class ReactionCommentCreateDto(
val optionId: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.backgu.amaker.api.event.dto

import com.backgu.amaker.domain.event.ReactionComment
import java.time.LocalDateTime

data class ReactionCommentDto(
val id: Long,
val userId: String,
val eventId: Long,
val optionId: Long,
val createdAt: LocalDateTime = LocalDateTime.now(),
val updatedAt: LocalDateTime = LocalDateTime.now(),
) {
companion object {
fun of(reactionComment: ReactionComment) =
ReactionCommentDto(
id = reactionComment.id,
userId = reactionComment.userId,
eventId = reactionComment.eventId,
optionId = reactionComment.optionId,
createdAt = reactionComment.createdAt,
updatedAt = reactionComment.updatedAt,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.backgu.amaker.api.event.dto.request

import com.backgu.amaker.api.event.dto.ReactionCommentCreateDto
import io.swagger.v3.oas.annotations.media.Schema

data class ReactionCommentCreateRequest(
@Schema(description = "option id", example = "1")
val optionId: Long,
) {
fun toDto() =
ReactionCommentCreateDto(
optionId = optionId,
)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.backgu.amaker.api.event.service

import com.backgu.amaker.api.event.dto.ReactionCommentCreateDto
import com.backgu.amaker.api.event.dto.ReactionCommentDto
import com.backgu.amaker.api.event.dto.ReplyCommentCreateDto
import com.backgu.amaker.api.event.dto.ReplyCommentDto
import com.backgu.amaker.api.event.dto.ReplyCommentWithUserDto
import com.backgu.amaker.application.chat.event.FinishedCountUpdateEvent
import com.backgu.amaker.application.event.service.EventAssignedUserService
import com.backgu.amaker.application.event.service.ReactionCommentService
import com.backgu.amaker.application.event.service.ReactionEventService
import com.backgu.amaker.application.event.service.ReactionOptionService
import com.backgu.amaker.application.event.service.ReplyCommentService
import com.backgu.amaker.application.event.service.ReplyEventService
import com.backgu.amaker.application.user.service.UserService
Expand All @@ -22,8 +27,11 @@ import org.springframework.transaction.annotation.Transactional
class EventCommentFacadeService(
private val userService: UserService,
private val replyEventService: ReplyEventService,
private val reactionEventService: ReactionEventService,
private val eventAssignedUserService: EventAssignedUserService,
private val replyCommentService: ReplyCommentService,
private val reactionCommentService: ReactionCommentService,
private val reactionOptionService: ReactionOptionService,
private val workspaceUserService: WorkspaceUserService,
private val eventPublisher: ApplicationEventPublisher,
) {
Expand All @@ -47,6 +55,34 @@ class EventCommentFacadeService(
return ReplyCommentDto.of(replyComment)
}

@Transactional
fun createReactionComment(
userId: String,
eventId: Long,
reactionCommentCreateDto: ReactionCommentCreateDto,
): ReactionCommentDto {
val user = userService.getById(userId)
val event = reactionEventService.getById(eventId)

val eventAssignedUser = eventAssignedUserService.getByUserAndEvent(user, event)

reactionOptionService.validateOptionInEvent(reactionCommentCreateDto.optionId, eventId)

val reactionComment =
reactionCommentService.save(
reactionCommentService
.findByEventIdAndUserId(event, user)
?.also { it.toggleOptionId(reactionCommentCreateDto.optionId) }
?: event.createReactionComment(userId, reactionCommentCreateDto.optionId),
)

eventAssignedUserService.save(eventAssignedUser.updateIsFinished(true))

eventPublisher.publishEvent(FinishedCountUpdateEvent.of(chatId = event.id))

return ReactionCommentDto.of(reactionComment)
}

fun findReplyComments(
userId: String,
eventId: Long,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.backgu.amaker.api.event.service

import com.backgu.amaker.api.common.container.IntegrationTest
import com.backgu.amaker.api.event.dto.ReactionCommentCreateDto
import com.backgu.amaker.api.event.dto.ReplyCommentCreateDto
import com.backgu.amaker.api.fixture.ReactionCommentFixtureFacade
import com.backgu.amaker.api.fixture.ReplyCommentFixtureFacade
import com.backgu.amaker.common.exception.BusinessException
import com.backgu.amaker.common.status.StatusCode
Expand All @@ -23,6 +25,9 @@ class EventCommentFacadeServiceTest : IntegrationTest() {
@Autowired
lateinit var replyCommentFixtures: ReplyCommentFixtureFacade

@Autowired
lateinit var reactionCommentFixtures: ReactionCommentFixtureFacade

@Test
@DisplayName("reply comment 생성 테스트")
fun createReplyComment() {
Expand Down Expand Up @@ -115,4 +120,66 @@ class EventCommentFacadeServiceTest : IntegrationTest() {
.extracting("statusCode")
.isEqualTo(StatusCode.WORKSPACE_UNREACHABLE)
}

@Test
@DisplayName("reaction comment 생성 테스트")
fun createReactionComment() {
// given
val userId = "test-user-id"
val (reactionEvent, options) = reactionCommentFixtures.setUp(userId = "test-user-id")
val reactionCommentCreateDto = ReactionCommentCreateDto(options[0].id)

// when
val result =
eventCommentFacadeService.createReactionComment(userId, reactionEvent.id, reactionCommentCreateDto)

// then
assertThat(result).isNotNull
assertThat(result.eventId).isEqualTo(reactionEvent.id)
assertThat(result.optionId).isEqualTo(options[0].id)
}

@Test
@DisplayName("reaction comment 변경 테스트")
fun toggleReactionComment() {
// given
val userId = "test-user-id"
val (reactionEvent, options) = reactionCommentFixtures.setUp(userId = "test-user-id")
reactionCommentFixtures.reactionCommentFixture.createPersistedReactionComment(
userId,
reactionEvent.id,
options[0].id,
)
val reactionCommentCreateDto = ReactionCommentCreateDto(options[1].id)

// when
val result =
eventCommentFacadeService.createReactionComment(userId, reactionEvent.id, reactionCommentCreateDto)

// then
assertThat(result).isNotNull
assertThat(result.eventId).isEqualTo(reactionEvent.id)
assertThat(result.optionId).isEqualTo(options[1].id)
}

@Test
@DisplayName("reaction comment 생성 실패 테스트 - 할당되지 않은 유저")
fun failCreateReactionCommentNotAssignedUser() {
// given
val userId = "diff-user-id"
val (reactionEvent, options) = reactionCommentFixtures.setUp(userId = "test-user-id")
val reactionCommentCreateDto = ReactionCommentCreateDto(options[0].id)
reactionCommentFixtures.userFixture.createPersistedUser(userId)

// when & then
assertThatThrownBy {
eventCommentFacadeService.createReactionComment(
userId,
reactionEvent.id,
reactionCommentCreateDto,
)
}.isInstanceOf(BusinessException::class.java)
.extracting("statusCode")
.isEqualTo(StatusCode.EVENT_ASSIGNED_USER_NOT_FOUND)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.backgu.amaker.api.fixture

import com.backgu.amaker.api.fixture.dto.ChatRoomFixtureDto
import com.backgu.amaker.domain.user.User
import com.backgu.amaker.domain.workspace.Workspace
import com.backgu.amaker.domain.workspace.WorkspaceUser
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.backgu.amaker.api.fixture

import com.backgu.amaker.domain.event.ReactionComment
import com.backgu.amaker.infra.jpa.event.entity.ReactionCommentEntity
import com.backgu.amaker.infra.jpa.event.repository.ReactionCommentRepository
import org.springframework.stereotype.Component

@Component
class ReactionCommentFixture(
val reactionCommentRepository: ReactionCommentRepository,
) {
fun createPersistedReactionComment(
userId: String,
eventId: Long,
optionId: Long,
): ReactionComment =
reactionCommentRepository
.save(
ReactionCommentEntity(
userId = userId,
eventId = eventId,
optionId = optionId,
),
).toDomain()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.backgu.amaker.api.fixture

import com.backgu.amaker.api.fixture.dto.ReactionCommentFixtureDto
import com.backgu.amaker.domain.chat.ChatRoomType
import com.backgu.amaker.domain.chat.ChatType
import org.springframework.stereotype.Component

@Component
class ReactionCommentFixtureFacade(
val reactionCommentFixture: ReactionCommentFixture,
val reactionEventFixture: ReactionEventFixture,
val reactionOptionFixture: ReactionOptionFixture,
val chatRoomFixture: ChatRoomFixture,
val chatFixture: ChatFixture,
val eventAssignedUserFixture: EventAssignedUserFixture,
val userFixture: UserFixture,
private val workspaceFixture: WorkspaceFixture,
private val workspaceUserFixture: WorkspaceUserFixture,
) {
fun setUp(
userId: String = "test-user-id",
name: String = "김리더",
workspaceId: Long = 1L,
): ReactionCommentFixtureDto {
val workspace = workspaceFixture.createPersistedWorkspace(workspaceId, "test-workspace")
workspaceUserFixture.createPersistedWorkspaceUser(workspace.id, userId)
userFixture.createPersistedUser(id = userId, name = name)
val chatRoom = chatRoomFixture.createPersistedChatRoom(workspace.id, ChatRoomType.DEFAULT)
val chat = chatFixture.createPersistedChat(chatRoom.id, userId, chatType = ChatType.REPLY)
val reactionEvent = reactionEventFixture.createPersistedReactionEvent(chat.id)
val options = reactionOptionFixture.createPersistedReactionOptions(reactionEvent.id)
eventAssignedUserFixture.createPersistedEventAssignedUser(userId, reactionEvent.id)
return ReactionCommentFixtureDto(reactionEvent, options)
}
}
Loading

0 comments on commit fed1d09

Please sign in to comment.