Skip to content

Commit bd6d645

Browse files
committed
feat: 이벤트 조회
1 parent b586771 commit bd6d645

File tree

18 files changed

+337
-56
lines changed

18 files changed

+337
-56
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.backgu.amaker.api.notification.config
2+
3+
import com.backgu.amaker.api.notification.dto.request.NotificationQueryRequest
4+
import com.backgu.amaker.api.notification.dto.response.EventNotificationViewResponse
5+
import com.backgu.amaker.common.http.response.ApiResult
6+
import com.backgu.amaker.common.security.jwt.authentication.JwtAuthentication
7+
import io.swagger.v3.oas.annotations.Operation
8+
import io.swagger.v3.oas.annotations.responses.ApiResponse
9+
import io.swagger.v3.oas.annotations.responses.ApiResponses
10+
import org.springframework.http.ResponseEntity
11+
import org.springframework.security.core.annotation.AuthenticationPrincipal
12+
import org.springframework.web.bind.annotation.ModelAttribute
13+
import org.springframework.web.bind.annotation.PathVariable
14+
15+
interface EventNotificationSwagger {
16+
@Operation(summary = "이벤트 알림 조회", description = "이벤트 알림을 조회합니다.")
17+
@ApiResponses(
18+
value = [
19+
ApiResponse(
20+
responseCode = "200",
21+
description = "이벤트 알림 리스트 성공",
22+
),
23+
],
24+
)
25+
fun getNotifications(
26+
@AuthenticationPrincipal token: JwtAuthentication,
27+
@PathVariable("workspace-id") workspaceId: Long,
28+
@ModelAttribute notificationQueryRequest: NotificationQueryRequest,
29+
): ResponseEntity<ApiResult<EventNotificationViewResponse>>
30+
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
package com.backgu.amaker.api.notification.config
22

3+
import com.backgu.amaker.application.notification.service.NotificationQueryService
4+
import com.backgu.amaker.infra.jpa.notification.repository.EventNotificationRepository
35
import com.backgu.amaker.infra.notification.kafka.config.NotificationKafkaProducerConfig
6+
import org.springframework.context.annotation.Bean
47
import org.springframework.context.annotation.Configuration
58
import org.springframework.context.annotation.Import
69

710
@Configuration
811
@Import(NotificationKafkaProducerConfig::class)
9-
class NotificationConfig
12+
class NotificationConfig {
13+
@Bean
14+
fun notificationQueryService(notificationRepository: EventNotificationRepository): NotificationQueryService =
15+
NotificationQueryService(notificationRepository)
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.backgu.amaker.api.notification.controller
2+
3+
import com.backgu.amaker.api.notification.config.EventNotificationSwagger
4+
import com.backgu.amaker.api.notification.dto.request.NotificationQueryRequest
5+
import com.backgu.amaker.api.notification.dto.response.EventNotificationViewResponse
6+
import com.backgu.amaker.api.notification.service.NotificationFacadeService
7+
import com.backgu.amaker.common.http.ApiHandler
8+
import com.backgu.amaker.common.http.response.ApiResult
9+
import com.backgu.amaker.common.security.jwt.authentication.JwtAuthentication
10+
import org.springframework.data.domain.PageRequest
11+
import org.springframework.data.domain.Sort
12+
import org.springframework.http.ResponseEntity
13+
import org.springframework.security.core.annotation.AuthenticationPrincipal
14+
import org.springframework.web.bind.annotation.GetMapping
15+
import org.springframework.web.bind.annotation.ModelAttribute
16+
import org.springframework.web.bind.annotation.PathVariable
17+
import org.springframework.web.bind.annotation.RequestMapping
18+
import org.springframework.web.bind.annotation.RestController
19+
20+
@RestController
21+
@RequestMapping("/api/v1/workspaces/{workspace-id}/notifications")
22+
class EventNotificationController(
23+
private val notificationFacadeService: NotificationFacadeService,
24+
private val apiHandler: ApiHandler,
25+
) : EventNotificationSwagger {
26+
@GetMapping
27+
override fun getNotifications(
28+
@AuthenticationPrincipal token: JwtAuthentication,
29+
@PathVariable("workspace-id") workspaceId: Long,
30+
@ModelAttribute notificationQueryRequest: NotificationQueryRequest,
31+
): ResponseEntity<ApiResult<EventNotificationViewResponse>> {
32+
val pageable =
33+
PageRequest.of(
34+
notificationQueryRequest.page,
35+
notificationQueryRequest.size,
36+
Sort.by("id").ascending(),
37+
)
38+
39+
return ResponseEntity.ok(
40+
apiHandler.onSuccess(
41+
EventNotificationViewResponse.of(
42+
notificationFacadeService.getNotifications(
43+
token.id,
44+
workspaceId,
45+
pageable,
46+
),
47+
),
48+
),
49+
)
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.backgu.amaker.api.notification.controller
2+
3+
import com.backgu.amaker.api.event.dto.response.ReplyEventDetailResponse
4+
import com.backgu.amaker.common.http.response.ApiResult
5+
import com.backgu.amaker.common.security.jwt.authentication.JwtAuthentication
6+
import io.swagger.v3.oas.annotations.Operation
7+
import io.swagger.v3.oas.annotations.responses.ApiResponse
8+
import io.swagger.v3.oas.annotations.responses.ApiResponses
9+
import io.swagger.v3.oas.annotations.tags.Tag
10+
import org.springframework.http.ResponseEntity
11+
import org.springframework.security.core.annotation.AuthenticationPrincipal
12+
import org.springframework.web.bind.annotation.PathVariable
13+
14+
@Tag(name = "notification", description = "알림 API")
15+
interface NotificationSwagger {
16+
@Operation(summary = "알림 리스트 조회", description = "알림 내역들을 조회합니다.")
17+
@ApiResponses(
18+
value = [
19+
ApiResponse(
20+
responseCode = "200",
21+
description = "알림내역 조회 성공",
22+
),
23+
],
24+
)
25+
fun getNotifications(
26+
@AuthenticationPrincipal token: JwtAuthentication,
27+
@PathVariable("workspace-id") workspaceId: Long,
28+
): ResponseEntity<ApiResult<ReplyEventDetailResponse>>
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.backgu.amaker.api.notification.dto
2+
3+
import com.backgu.amaker.domain.notifiacation.EventNotification
4+
5+
data class EventNotificationDto(
6+
val id: Long,
7+
val title: String,
8+
val content: String,
9+
val userId: String,
10+
val eventId: Long,
11+
) {
12+
companion object {
13+
fun from(eventNotification: EventNotification): EventNotificationDto =
14+
EventNotificationDto(
15+
id = eventNotification.id,
16+
title = eventNotification.title,
17+
content = eventNotification.content,
18+
userId = eventNotification.userId,
19+
eventId = eventNotification.eventId,
20+
)
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.backgu.amaker.api.notification.dto
2+
3+
data class NotificationQueryDto(
4+
val notificationId: Long,
5+
val size: Int,
6+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.backgu.amaker.api.notification.dto.request
2+
3+
import com.backgu.amaker.api.notification.dto.NotificationQueryDto
4+
import io.swagger.v3.oas.annotations.media.Schema
5+
6+
data class NotificationQueryRequest(
7+
@Schema(description = "읽어올 페이지 번호", example = "2", defaultValue = "0")
8+
val page: Int = 0,
9+
@Schema(description = "읽어올 응답의 개수", example = "100", defaultValue = "20")
10+
val size: Int = 20,
11+
) {
12+
fun toDto(notificationId: Long): NotificationQueryDto =
13+
NotificationQueryDto(
14+
notificationId = notificationId,
15+
size = size,
16+
)
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.backgu.amaker.api.notification.dto.response
2+
3+
import com.backgu.amaker.api.notification.dto.EventNotificationDto
4+
import io.swagger.v3.oas.annotations.media.Schema
5+
6+
data class EventNotificationResponse(
7+
@Schema(description = "이벤트 id", example = "1")
8+
val id: Long,
9+
@Schema(description = "이벤트 제목", example = "이벤트 제목")
10+
val title: String,
11+
@Schema(description = "이벤트 내용", example = "이벤트 내용")
12+
val content: String,
13+
@Schema(description = "유저 id", example = "2")
14+
val userId: String,
15+
@Schema(description = "이벤트 id", example = "2")
16+
val eventId: Long,
17+
) {
18+
companion object {
19+
fun of(eventNotification: EventNotificationDto) =
20+
EventNotificationResponse(
21+
id = eventNotification.id,
22+
title = eventNotification.title,
23+
content = eventNotification.content,
24+
userId = eventNotification.userId,
25+
eventId = eventNotification.eventId,
26+
)
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.backgu.amaker.api.notification.dto.response
2+
3+
import com.backgu.amaker.api.notification.dto.EventNotificationDto
4+
import com.backgu.amaker.common.http.response.PageResponse
5+
import org.springframework.data.domain.Page
6+
7+
class EventNotificationViewResponse(
8+
override val content: List<EventNotificationResponse>,
9+
override val pageNumber: Int,
10+
override val pageSize: Int,
11+
override val totalElements: Long,
12+
override val totalPages: Int,
13+
override val hasNext: Boolean,
14+
override val hasPrevious: Boolean,
15+
override val isFirst: Boolean,
16+
override val isLast: Boolean,
17+
) : PageResponse<EventNotificationResponse> {
18+
companion object {
19+
fun of(eventNotifications: Page<EventNotificationDto>): EventNotificationViewResponse {
20+
val content = eventNotifications.content.map { EventNotificationResponse.of(it) }
21+
return EventNotificationViewResponse(
22+
content = content,
23+
pageNumber = eventNotifications.number,
24+
pageSize = eventNotifications.size,
25+
totalElements = eventNotifications.totalElements,
26+
totalPages = eventNotifications.totalPages,
27+
hasNext = eventNotifications.hasNext(),
28+
hasPrevious = eventNotifications.hasPrevious(),
29+
isFirst = eventNotifications.isFirst,
30+
isLast = eventNotifications.isLast,
31+
)
32+
}
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.backgu.amaker.api.notification.service
2+
3+
import com.backgu.amaker.api.notification.dto.EventNotificationDto
4+
import com.backgu.amaker.application.event.service.EventAssignedUserService
5+
import com.backgu.amaker.application.event.service.ReactionCommentService
6+
import com.backgu.amaker.application.event.service.ReactionEventService
7+
import com.backgu.amaker.application.event.service.ReactionOptionService
8+
import com.backgu.amaker.application.event.service.ReplyCommentService
9+
import com.backgu.amaker.application.event.service.ReplyEventService
10+
import com.backgu.amaker.application.notification.service.NotificationQueryService
11+
import com.backgu.amaker.application.user.service.UserService
12+
import com.backgu.amaker.application.workspace.WorkspaceUserService
13+
import org.springframework.context.ApplicationEventPublisher
14+
import org.springframework.data.domain.Page
15+
import org.springframework.data.domain.Pageable
16+
import org.springframework.stereotype.Service
17+
import org.springframework.transaction.annotation.Transactional
18+
19+
@Service
20+
@Transactional(readOnly = true)
21+
class NotificationFacadeService(
22+
private val userService: UserService,
23+
private val replyEventService: ReplyEventService,
24+
private val reactionEventService: ReactionEventService,
25+
private val eventAssignedUserService: EventAssignedUserService,
26+
private val replyCommentService: ReplyCommentService,
27+
private val reactionCommentService: ReactionCommentService,
28+
private val reactionOptionService: ReactionOptionService,
29+
private val workspaceUserService: WorkspaceUserService,
30+
private val notificationQueryService: NotificationQueryService,
31+
private val eventPublisher: ApplicationEventPublisher,
32+
) {
33+
fun getNotifications(
34+
userId: String,
35+
workspaceId: Long,
36+
pageable: Pageable,
37+
): Page<EventNotificationDto> {
38+
workspaceUserService.validateUserInWorkspace(userId, workspaceId)
39+
40+
return notificationQueryService.getNotification(userId, workspaceId, pageable).map { EventNotificationDto.from(it) }
41+
}
42+
}

api/src/main/resources/logback-spring.xml

-43
This file was deleted.

api/src/test/kotlin/com/backgu/amaker/api/event/service/EventCommentFacadeServiceTest.kt api/src/test/kotlin/com/backgu/amaker/api/event/service/NotificationFacadeServiceTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import kotlin.test.Test
1818

1919
@DisplayName("EventFacadeService 테스트")
2020
@Transactional
21-
class EventCommentFacadeServiceTest : IntegrationTest() {
21+
class NotificationFacadeServiceTest : IntegrationTest() {
2222
@Autowired
2323
lateinit var eventCommentFacadeService: EventCommentFacadeService
2424

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.backgu.amaker.domain.notifiacation
2+
3+
class EventNotification(
4+
val id: Long,
5+
val title: String,
6+
val content: String,
7+
val userId: String,
8+
val eventId: Long,
9+
)

domain/src/main/kotlin/com/backgu/amaker/domain/notifiacation/Notification.kt

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,5 @@ interface Notification : Serializable {
88
val keyPrefix: String
99
val keyValue: String
1010

11-
fun getNotificationKey(): String {
12-
return "$keyPrefix:$keyValue"
13-
}
11+
fun getNotificationKey(): String = "$keyPrefix:$keyValue"
1412
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.backgu.amaker.application.notification.service
2+
3+
import com.backgu.amaker.domain.notifiacation.EventNotification
4+
import com.backgu.amaker.infra.jpa.notification.repository.EventNotificationRepository
5+
import org.springframework.data.domain.Page
6+
import org.springframework.data.domain.Pageable
7+
import org.springframework.stereotype.Service
8+
import org.springframework.transaction.annotation.Transactional
9+
10+
@Service
11+
@Transactional(readOnly = true)
12+
class NotificationQueryService(
13+
private val eventNotificationRepository: EventNotificationRepository,
14+
) {
15+
fun getNotification(
16+
userId: String,
17+
workspaceId: Long,
18+
page: Pageable,
19+
): Page<EventNotification> = eventNotificationRepository.findByUserId(userId, workspaceId, page).map { it.toDomain() }
20+
}

0 commit comments

Comments
 (0)