Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KAN-80 (BE) 식당 - 좋아요 조회/변경 API 개발 #51

Merged
merged 6 commits into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.restaurant.be.common.response.CommonResponse
import com.restaurant.be.restaurant.presentation.controller.dto.GetLikeRestaurantsResponse
import com.restaurant.be.restaurant.presentation.controller.dto.LikeRestaurantRequest
import com.restaurant.be.restaurant.presentation.controller.dto.LikeRestaurantResponse
import com.restaurant.be.restaurant.presentation.domain.service.LikeRestaurantService
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.v3.oas.annotations.media.Content
Expand All @@ -23,21 +24,24 @@ import javax.validation.Valid
@Api(tags = ["02. Restaurant Info"], description = "음식점 서비스")
@RestController
@RequestMapping("/v1/restaurants")
class LikeRestaurantController {
class LikeRestaurantController(
private val likeRestaurantService: LikeRestaurantService
) {

@GetMapping("/like")
@GetMapping("/my-like")
@PreAuthorize("hasRole('USER')")
@ApiOperation(value = "좋아요한 음식점 리스트 조회 API")
@ApiResponse(
responseCode = "200",
description = "성공",
content = [Content(schema = Schema(implementation = GetLikeRestaurantsResponse::class))]
)
fun getLikeRestaurants(
fun getMyLikeRestaurants(
principal: Principal,
pageable: Pageable
): CommonResponse<GetLikeRestaurantsResponse> {
return CommonResponse.success()
val response = likeRestaurantService.getMyLikeRestaurant(pageable, principal.name)
return CommonResponse.success(response)
}

@PostMapping("/{restaurantId}/like")
Expand All @@ -50,10 +54,12 @@ class LikeRestaurantController {
)
fun likeRestaurant(
principal: Principal,
@PathVariable restaurantId: String,
@PathVariable restaurantId: Long,
@RequestBody @Valid
request: LikeRestaurantRequest
): CommonResponse<LikeRestaurantResponse> {
return CommonResponse.success()
val response =
likeRestaurantService.likeRestaurant(principal.name, restaurantId, request.isLike)
return CommonResponse.success(response)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package com.restaurant.be.restaurant.presentation.controller.dto
import com.restaurant.be.restaurant.presentation.controller.dto.common.RestaurantDto
import io.swagger.annotations.ApiModelProperty
import io.swagger.v3.oas.annotations.media.Schema
import org.springframework.data.domain.Page

data class GetLikeRestaurantsResponse(
@Schema(description = "좋아요한 식당 리스트")
val restaurants: List<RestaurantDto>
val restaurants: Page<RestaurantDto>
)

data class LikeRestaurantRequest(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.restaurant.be.restaurant.presentation.domain.service

import com.restaurant.be.common.exception.NotFoundRestaurantException
import com.restaurant.be.common.exception.NotFoundUserEmailException
import com.restaurant.be.common.exception.NotFoundUserException
import com.restaurant.be.restaurant.domain.entity.RestaurantLike
import com.restaurant.be.restaurant.presentation.controller.dto.GetLikeRestaurantsResponse
import com.restaurant.be.restaurant.presentation.controller.dto.LikeRestaurantResponse
import com.restaurant.be.restaurant.repository.RestaurantLikeRepository
import com.restaurant.be.restaurant.repository.RestaurantRepository
import com.restaurant.be.restaurant.repository.dto.RestaurantProjectionDto
import com.restaurant.be.user.domain.entity.User
import com.restaurant.be.user.repository.UserRepository
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class LikeRestaurantService(
private val restaurantRepository: RestaurantRepository,
private val restaurantLikeRepository: RestaurantLikeRepository,
private val userRepository: UserRepository
) {
@Transactional
fun likeRestaurant(email: String, restaurantId: Long, isLike: Boolean): LikeRestaurantResponse {
val user: User = userRepository.findByEmail(email) ?: throw NotFoundUserEmailException()
val userId: Long = user.id ?: throw NotFoundUserException()

val restaurant: RestaurantProjectionDto = restaurantRepository.findDtoById(restaurantId)
?: throw NotFoundRestaurantException()
one0955 marked this conversation as resolved.
Show resolved Hide resolved

// 좋아요 요청
if (isLike) {
// 실제 좋아요가 아닐 시 Insert
if (!restaurant.isLike) {
restaurantLikeRepository.save(
RestaurantLike(
restaurantId = restaurantId,
userId = userId
)
)
}
} else {
restaurantLikeRepository.deleteByUserIdAndRestaurantId(userId, restaurantId)
}

return LikeRestaurantResponse(restaurant.toDto())
}

@Transactional
fun getMyLikeRestaurant(pageable: Pageable, email: String): GetLikeRestaurantsResponse {
val userId = userRepository.findByEmail(email)?.id ?: throw NotFoundUserEmailException()

return GetLikeRestaurantsResponse(
restaurantRepository.findMyLikeRestaurants(userId, pageable)
.map { it.toDto() }
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ package com.restaurant.be.restaurant.repository
import com.restaurant.be.restaurant.domain.entity.RestaurantLike
import org.springframework.data.jpa.repository.JpaRepository

interface RestaurantLikeRepository : JpaRepository<RestaurantLike, Long>
interface RestaurantLikeRepository : JpaRepository<RestaurantLike, Long> {
fun deleteByUserIdAndRestaurantId(userId: Long, restaurantId: Long)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import org.springframework.data.domain.Pageable

interface RestaurantRepositoryCustom {
fun findDtoById(restaurantId: Long): RestaurantProjectionDto?

fun findDtoByIds(
restaurantIds: List<Long>,
userId: Long,
isLikeFilter: Boolean?,
pageable: Pageable
): Page<RestaurantProjectionDto>

fun findMyLikeRestaurants(userId: Long, pageable: Pageable): Page<RestaurantProjectionDto>
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,65 @@ class RestaurantRepositoryCustomImpl(

return PageImpl(restaurantDtos, pageable, total)
}

override fun findMyLikeRestaurants(
userId: Long,
pageable: Pageable
): Page<RestaurantProjectionDto> {
val myLikeQuery = queryFactory
.select(restaurantLike.restaurantId)
.from(restaurantLike)
.where(restaurantLike.userId.eq(userId))

val total = myLikeQuery.fetchCount()

val restaurantIds = myLikeQuery
.offset(pageable.offset)
.limit(pageable.pageSize.toLong())
.fetch()

val restaurantInfos = queryFactory
.select(restaurant)
.from(restaurant)
.where(restaurant.id.`in`(restaurantIds))
.fetch()

val menus = queryFactory
.select(menu)
.from(menu)
.where(menu.restaurantId.`in`(restaurantIds))
.fetch()

val reviews = queryFactory
.select(review)
.from(review)
.where(review.restaurantId.`in`(restaurantIds))
.orderBy(review.likeCount.desc())
.fetch()

val categories = queryFactory
.select(restaurantCategory, category)
.from(restaurantCategory)
.leftJoin(category).on(restaurantCategory.categoryId.eq(category.id))
.where(restaurantCategory.restaurantId.`in`(restaurantIds))
.fetch()

val restaurantDtos = restaurantInfos.map { restaurantInfo ->
val likedUserIds = restaurantIds.map { true }
val menuList = menus.filter { it.restaurantId == restaurantInfo.id }
val review = reviews.firstOrNull { it.restaurantId == restaurantInfo.id }
val categoryList = categories
.filter { it.get(restaurantCategory)?.restaurantId == restaurantInfo.id }
.mapNotNull { it.get(category) }
RestaurantProjectionDto(
restaurantInfo,
likedUserIds.isNotEmpty(),
menuList,
review,
categoryList
)
}

return PageImpl(restaurantDtos, pageable, total)
}
}
Loading