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) + } +}