From 88df83fdc00b3ed80f36dff681936e1ab4fb920a Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 4 Aug 2023 22:32:34 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A9=94=EB=89=B4=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/menu/GetMenuResponse.kt | 12 +++++ .../kr/co/vividnext/sodalive/menu/Menu.kt | 32 +++++++++++++ .../vividnext/sodalive/menu/MenuController.kt | 17 +++++++ .../vividnext/sodalive/menu/MenuRepository.kt | 47 +++++++++++++++++++ .../co/vividnext/sodalive/menu/MenuService.kt | 18 +++++++ 5 files changed, 126 insertions(+) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/menu/GetMenuResponse.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/menu/Menu.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuController.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuRepository.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuService.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/menu/GetMenuResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/menu/GetMenuResponse.kt new file mode 100644 index 0000000..254ac78 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/menu/GetMenuResponse.kt @@ -0,0 +1,12 @@ +package kr.co.vividnext.sodalive.menu + +import com.fasterxml.jackson.annotation.JsonInclude +import com.querydsl.core.annotations.QueryProjection + +data class GetMenuResponse @QueryProjection constructor( + val title: String, + @JsonInclude(JsonInclude.Include.NON_NULL) + val route: String? = null, + @JsonInclude(JsonInclude.Include.NON_NULL) + val items: List? = null +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/menu/Menu.kt b/src/main/kotlin/kr/co/vividnext/sodalive/menu/Menu.kt new file mode 100644 index 0000000..d790707 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/menu/Menu.kt @@ -0,0 +1,32 @@ +package kr.co.vividnext.sodalive.menu + +import kr.co.vividnext.sodalive.common.BaseEntity +import kr.co.vividnext.sodalive.member.MemberRole +import javax.persistence.CascadeType +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 +import javax.persistence.OneToMany + +@Entity +data class Menu( + @Column(nullable = false) + val title: String, + @Column(nullable = false) + val route: String, + @Enumerated(value = EnumType.STRING) + val roles: MemberRole, + val orders: Int, + val isActive: Boolean +) : BaseEntity() { + @ManyToOne(fetch = FetchType.LAZY, cascade = [CascadeType.ALL]) + @JoinColumn(name = "parent_id", nullable = true) + var parent: Menu? = null + + @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER) + var children: MutableList = mutableListOf() +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuController.kt new file mode 100644 index 0000000..5146119 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuController.kt @@ -0,0 +1,17 @@ +package kr.co.vividnext.sodalive.menu + +import kr.co.vividnext.sodalive.common.ApiResponse +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.security.core.annotation.AuthenticationPrincipal +import org.springframework.security.core.userdetails.User +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/menu") +class MenuController(private val service: MenuService) { + @GetMapping + @PreAuthorize("hasAnyRole('AGENT', 'ADMIN')") + fun getMenus(@AuthenticationPrincipal user: User) = ApiResponse.ok(service.getMenus(user)) +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuRepository.kt new file mode 100644 index 0000000..c5eb43f --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuRepository.kt @@ -0,0 +1,47 @@ +package kr.co.vividnext.sodalive.menu + +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.member.MemberRole +import kr.co.vividnext.sodalive.menu.QMenu.menu +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface MenuRepository : JpaRepository, MenuQueryRepository + +interface MenuQueryRepository { + fun getMenu(role: MemberRole): List +} + +class MenuQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : MenuQueryRepository { + override fun getMenu(role: MemberRole): List { + return queryFactory + .selectFrom(menu) + .where( + menu.isActive.isTrue + .and(menu.roles.eq(role)) + .and( + (menu.route.isNotNull.and(menu.parent.isNull)) + .or(menu.route.isNull.and(menu.children.isNotEmpty)) + ) + ) + .orderBy(menu.orders.asc()) + .fetch() + .asSequence() + .map { + GetMenuResponse( + title = it.title, + route = it.route, + items = if (it.children.isNotEmpty()) { + it.children + .asSequence() + .map { menu -> GetMenuResponse(menu.title, menu.route) } + .toList() + } else { + null + } + ) + } + .toList() + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuService.kt new file mode 100644 index 0000000..bb7dc6e --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/menu/MenuService.kt @@ -0,0 +1,18 @@ +package kr.co.vividnext.sodalive.menu + +import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.member.MemberRepository +import org.springframework.security.core.userdetails.User +import org.springframework.stereotype.Service + +@Service +class MenuService( + private val repository: MenuRepository, + private val memberRepository: MemberRepository +) { + fun getMenus(user: User): List { + val member = memberRepository.findByEmail(user.username) + ?: throw SodaException("로그인 정보를 확인해주세요.") + return repository.getMenu(member.role) + } +}