Skip to content

Commit

Permalink
Merge pull request #11 from gloddy-dev/feat/#7
Browse files Browse the repository at this point in the history
[Feat]: Article 조회(단건, 페이징) API 설계
  • Loading branch information
jihwan2da authored Jan 21, 2024
2 parents 0e5e9e2 + 60005c2 commit 7c7a483
Show file tree
Hide file tree
Showing 52 changed files with 828 additions and 60 deletions.
1 change: 1 addition & 0 deletions bootstrap/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ spring:
config:
import:
- application-persistence.yml
- application-internal.yml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package gloddy.article.port.`in`

import gloddy.article.dto.command.ArticleCreateCommand
import gloddy.article.dto.read.ArticleIdReadData
import gloddy.article.port.`in`.dto.command.ArticleCreateRequest
import gloddy.article.port.`in`.dto.read.ArticleCreateResponse

interface ArticleCommandUseCase {
fun create(userId: Long, command: ArticleCreateCommand): ArticleIdReadData
fun create(userId: Long, command: ArticleCreateRequest): ArticleCreateResponse
fun delete(userId: Long, articleId: Long)
fun like(userId: Long, articleId: Long)
fun upsertLike(userId: Long, articleId: Long)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gloddy.article.port.`in`

enum class ArticleOrder(
val value: String
) {
LATEST("최신순")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package gloddy.article.port.`in`

import gloddy.article.port.`in`.dto.command.ArticleDetailGetRequest
import gloddy.article.port.`in`.dto.command.ArticleDetailPageGetRequest
import gloddy.article.port.`in`.dto.read.ArticleDetailResponse
import gloddy.core.dto.PageResponse

interface ArticleQueryUseCase {
fun getArticleDetailPage(request: ArticleDetailPageGetRequest): PageResponse<ArticleDetailResponse>
fun getArticleDetail(request: ArticleDetailGetRequest): ArticleDetailResponse
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package gloddy.article.dto.command
package gloddy.article.port.`in`.dto.command

data class ArticleCreateCommand(
data class ArticleCreateRequest(
val categoryId: Long,
val title: String,
val content: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package gloddy.article.port.`in`.dto.command

data class ArticleDetailGetRequest(
val id: Long,
val userId: Long
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package gloddy.article.port.`in`.dto.command

import gloddy.article.port.`in`.ArticleOrder

data class ArticleDetailPageGetRequest(
val categoryId: Long?,
val userId: Long,
val size: Int,
val page: Int,
val order: ArticleOrder
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package gloddy.article.port.`in`.dto.read

data class ArticleCreateResponse(
val articleId: Long
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package gloddy.article.port.`in`.dto.read

import gloddy.user.port.`in`.dto.UserPreviewUnit

data class ArticleDetailResponse(
val article: ArticleDetailUnit,
val writer: UserPreviewUnit
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package gloddy.article.port.`in`.dto.read

import gloddy.category.port.`in`.dto.CategoryGetResponse

data class ArticleDetailUnit(
val id: Long,
val userId: Long,
val isWriter: Boolean,
val isLiked: Boolean,
val category: CategoryGetResponse,
val title: String,
val content: String,
val thumbnail: String?,
val images: List<String>?,
val likeCount: Int,
val commentCount: Int,
val createdAt: String
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package gloddy.article.port.out

import gloddy.article.Article
import gloddy.article.ArticleLike

interface ArticleCommandPersistencePort {
fun save(article: Article) : Article
fun delete(id: Long)
fun upsertLike(articleLike: ArticleLike, article: Article)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
package gloddy.article.port.out

import gloddy.article.Article
import gloddy.article.port.`in`.dto.read.ArticleDetailUnit
import gloddy.article.port.`in`.ArticleOrder
import gloddy.core.dto.PageResponse

interface ArticleQueryPersistencePort {
fun findById(id: Long): Article

fun findArticleDetailUnitPageByCategoryId(
categoryId: Long? = null,
userId: Long,
size: Int,
page: Int,
order: ArticleOrder,
): PageResponse<ArticleDetailUnit>

fun findArticleDetailUnitById(
id: Long,
userId: Long
): ArticleDetailUnit
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package gloddy.article.service

import gloddy.article.Article
import gloddy.article.ArticleLike
import gloddy.article.dto.command.ArticleCreateCommand
import gloddy.article.dto.read.ArticleIdReadData
import gloddy.article.port.`in`.dto.command.ArticleCreateRequest
import gloddy.article.port.`in`.dto.read.ArticleCreateResponse
import gloddy.article.port.`in`.ArticleCommandUseCase
import gloddy.article.port.out.ArticleCommandPersistencePort
import gloddy.article.port.out.ArticleLikeCommandPersistencePort
Expand All @@ -20,10 +20,10 @@ class ArticleCommandService(
private val articleQueryPersistencePort: ArticleQueryPersistencePort,
private val articleCommandPersistencePort: ArticleCommandPersistencePort,
private val articleLikeCommandPersistencePort: ArticleLikeCommandPersistencePort,
private val articleLikeQueryPersistencePort: ArticleLikeQueryPersistencePort
private val articleLikeQueryPersistencePort: ArticleLikeQueryPersistencePort,
) : ArticleCommandUseCase {

override fun create(userId: Long, command: ArticleCreateCommand) : ArticleIdReadData {
override fun create(userId: Long, command: ArticleCreateRequest): ArticleCreateResponse {

val category = categoryQueryPersistencePort.findById(CategoryId(command.categoryId))

Expand All @@ -34,7 +34,7 @@ class ArticleCommandService(
content = command.content,
images = command.images,
).let { articleCommandPersistencePort.save(it) }
return ArticleIdReadData(articleId = article.id!!.value)
return ArticleCreateResponse(articleId = article.id!!.value)
}

override fun delete(userId: Long, articleId: Long) {
Expand All @@ -43,17 +43,21 @@ class ArticleCommandService(
articleCommandPersistencePort.delete(article.id!!.value)
}

override fun like(userId: Long, articleId: Long) {

override fun upsertLike(userId: Long, articleId: Long) {
val article = articleQueryPersistencePort.findById(articleId)

articleLikeQueryPersistencePort.findByUserIdAndArticleOrNull(userId, article)
?.run { articleLikeCommandPersistencePort.delete(this) }
?: articleLikeCommandPersistencePort.save(
ArticleLike(
?.run {
articleCommandPersistencePort.upsertLike(
articleLike = this,
article = article.unlike()
)
}
?: articleCommandPersistencePort.upsertLike(
articleLike = ArticleLike(
userId = UserId(userId),
article = article
)
),
article = article.like()
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package gloddy.article.service

import gloddy.article.port.`in`.ArticleQueryUseCase
import gloddy.article.port.`in`.dto.command.ArticleDetailGetRequest
import gloddy.article.port.`in`.dto.command.ArticleDetailPageGetRequest
import gloddy.article.port.`in`.dto.read.ArticleDetailResponse
import gloddy.article.port.out.ArticleQueryPersistencePort
import gloddy.core.dto.PageResponse
import gloddy.user.port.out.UserQueryPort
import org.springframework.stereotype.Service

@Service
class ArticleQueryService(
private val userQueryPort: UserQueryPort,
private val articleQueryPersistencePort: ArticleQueryPersistencePort,
) : ArticleQueryUseCase {

override fun getArticleDetailPage(request: ArticleDetailPageGetRequest): PageResponse<ArticleDetailResponse> {
val articleDetailUnitPage = articleQueryPersistencePort.findArticleDetailUnitPageByCategoryId(
categoryId = request.categoryId,
userId = request.userId,
size = request.size,
page = request.page,
order = request.order
)

val userPreviewUnits = userQueryPort.getUserPreviewUnits(
userIds = articleDetailUnitPage.contents.map { it.userId }.toSet()
)

return PageResponse(
totalCount = articleDetailUnitPage.totalCount,
currentCount = articleDetailUnitPage.currentCount,
totalPage = articleDetailUnitPage.totalPage,
currentPage = articleDetailUnitPage.currentPage,
contents = articleDetailUnitPage.contents
.map {
ArticleDetailResponse(
article = it,
writer = userPreviewUnits[it.userId]!!
)
}
)
}

override fun getArticleDetail(request: ArticleDetailGetRequest): ArticleDetailResponse {
val articleDetailUnit = articleQueryPersistencePort.findArticleDetailUnitById(
id = request.id,
userId = request.userId
)
val userPreviewUnit = userQueryPort.getUserPreviewUnit(request.userId)
return ArticleDetailResponse(
article = articleDetailUnit,
writer = userPreviewUnit
)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package gloddy.category.port.`in`

import gloddy.category.port.dto.CategoryReadData
import gloddy.category.port.`in`.dto.CategoryGetResponse

interface CategoryQueryUseCase {
fun getAll(): List<CategoryReadData>
fun getAll(): List<CategoryGetResponse>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package gloddy.category.port.`in`.dto

data class CategoryGetResponse(
val id: Long,
val name: String
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package gloddy.category.port.service

import gloddy.category.port.dto.CategoryReadData
import gloddy.category.port.`in`.dto.CategoryGetResponse
import gloddy.category.port.`in`.CategoryQueryUseCase
import gloddy.category.port.out.CategoryQueryPersistencePort
import org.springframework.stereotype.Service
Expand All @@ -10,10 +10,10 @@ class CategoryQueryService(
private val categoryQueryPersistencePort: CategoryQueryPersistencePort,
) : CategoryQueryUseCase {

override fun getAll(): List<CategoryReadData> {
override fun getAll(): List<CategoryGetResponse> {
val categories = categoryQueryPersistencePort.findAll()
return categories.map {
CategoryReadData(
CategoryGetResponse(
id = it.id!!.value,
name = it.name
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gloddy.core.dto

data class PageResponse<T>(
val totalCount: Long,
val currentCount: Int,
val totalPage: Int,
val currentPage: Int,
val contents: List<T>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package gloddy.core.util

import java.time.LocalDateTime
import java.time.format.DateTimeFormatter.*

fun LocalDateTime.toResponse(): String =
this.format(ofPattern("yyyy-MM-dd hh:mm"))
.replace(" ", "T")
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package gloddy.user.port.`in`.dto

data class UserPreviewUnit(
val id: Long,
val isCertifiedStudent: Boolean,
val profileImage: String,
val nickName: String,
val countryName: String?,
val countryImage: String?,
val reliabilityLevel: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package gloddy.user.port.out

import gloddy.user.port.`in`.dto.UserPreviewUnit

interface UserQueryPort {
fun getUserPreviewUnit(userId: Long): UserPreviewUnit
fun getUserPreviewUnits(userIds: Set<Long>): Map<Long, UserPreviewUnit>
}
Loading

0 comments on commit 7c7a483

Please sign in to comment.