Skip to content

Commit d004e03

Browse files
authored
feat : 링크별 owner 정보 추가 (#284)
1 parent f38d2ed commit d004e03

File tree

7 files changed

+89
-16
lines changed

7 files changed

+89
-16
lines changed

adapters/in-web/src/main/kotlin/com/pokit/content/dto/response/ContentsResponse.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ data class ContentsResponse(
1818
val isFavorite: Boolean,
1919
val keyword: String,
2020
val memoExists: Boolean,
21+
val author: AuthorProfile,
2122
)
2223

2324
fun ContentsResult.toResponse(): ContentsResponse {
@@ -37,5 +38,6 @@ fun ContentsResult.toResponse(): ContentsResponse {
3738
isFavorite = this.isFavorite,
3839
keyword = this.keyword,
3940
memoExists = this.memoExists,
41+
author = this.author,
4042
)
4143
}

adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/category/impl/CategoryAdapter.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class CategoryAdapter(
2828
override fun existsByNameAndUserId(name: String, userId: Long): Boolean =
2929
categoryRepository.existsByNameAndUserIdAndDeleted(name, userId, false)
3030

31+
override fun existsByNameAndUserIdAndIdNot(id: Long, name: String, userId: Long): Boolean {
32+
return categoryRepository.existsByNameAndUserIdAndDeletedAndIdNot(name, userId, false, id)
33+
}
34+
3135
override fun persist(category: Category): Category {
3236
val categoryEntity = CategoryEntity.of(category)
3337
return categoryRepository.save(categoryEntity).toDomain()

adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/category/persist/CategoryRepository.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import org.springframework.data.repository.query.Param
99

1010
interface CategoryRepository : JpaRepository<CategoryEntity, Long> {
1111
fun existsByNameAndUserIdAndDeleted(name: String, userId: Long, deleted: Boolean): Boolean
12+
fun existsByNameAndUserIdAndDeletedAndIdNot(name: String, userId: Long, deleted: Boolean, id: Long): Boolean
1213
fun findByUserIdAndDeleted(userId: Long, deleted: Boolean, pageable: Pageable): Slice<CategoryEntity>
1314
fun findByIdAndUserIdAndDeleted(id: Long, userId: Long, deleted: Boolean): CategoryEntity?
1415
fun countByUserIdAndDeleted(userId: Long, deleted: Boolean): Int

adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/content/impl/ContentAdapter.kt

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import com.pokit.out.persistence.content.persist.QContentEntity.contentEntity
1616
import com.pokit.out.persistence.content.persist.QReportedContentEntity.reportedContentEntity
1717
import com.pokit.out.persistence.content.persist.toDomain
1818
import com.pokit.out.persistence.log.persist.QUserLogEntity.userLogEntity
19+
import com.pokit.out.persistence.user.persist.QUserEntity.userEntity
20+
import com.pokit.out.persistence.user.persist.QUserImageEntity.userImageEntity
1921
import com.pokit.user.model.InterestType
2022
import com.querydsl.core.types.OrderSpecifier
2123
import com.querydsl.core.types.Predicate
@@ -71,11 +73,20 @@ class ContentAdapter(
7173
reportedContentEntity.isDeleted.isFalse
7274
)
7375

74-
val query = queryFactory.select(contentEntity, categoryEntity.name, userLogEntity.count(), bookmarkEntity.count())
76+
val query = queryFactory.select(
77+
contentEntity,
78+
categoryEntity.name,
79+
userLogEntity.count(),
80+
bookmarkEntity.count(),
81+
userEntity.nickname,
82+
userImageEntity.url
83+
)
7584
.from(contentEntity)
7685
.leftJoin(userLogEntity).on(userLogEntity.contentId.eq(contentEntity.id))
7786
.join(categoryEntity).on(categoryEntity.id.eq(contentEntity.categoryId))
7887
.leftJoin(bookmarkEntity).on(bookmarkEntity.contentId.eq(contentEntity.id).and(bookmarkEntity.deleted.isFalse))
88+
.join(userEntity).on(userEntity.id.eq(contentEntity.userId))
89+
.leftJoin(userImageEntity).on(userImageEntity.id.eq(userEntity.image.id))
7990

8091
if(condition.favorites == true) { // 즐겨찾기 필터링
8192
query.where(bookmarkEntity.isNotNull)
@@ -92,7 +103,7 @@ class ContentAdapter(
92103
containsWord(condition.searchWord),
93104
)
94105
.offset(pageable.offset)
95-
.groupBy(contentEntity)
106+
.groupBy(contentEntity, userEntity.nickname, userImageEntity.url)
96107
.orderBy(getSortOrder(contentEntity.createdAt, "createdAt", pageable))
97108
.limit(pageable.pageSize + 1L)
98109

@@ -105,26 +116,37 @@ class ContentAdapter(
105116
it[contentEntity]!!.toDomain(),
106117
it[categoryEntity.name]!!,
107118
it[userLogEntity.count()]!!,
108-
it[bookmarkEntity.count()]!!
119+
it[bookmarkEntity.count()]!!,
120+
it[userEntity.nickname]!!,
121+
it[userImageEntity.url]
109122
)
110123
}
111124

112125
return SliceImpl(contents, pageable, hasNext)
113126
}
114127

115128
override fun loadByUserIdAndCategoryName(userId: Long, categoryName: String, pageable: Pageable): Slice<ContentsResult> {
116-
val contents = queryFactory.select(contentEntity, categoryEntity.name, userLogEntity.count(), bookmarkEntity.count())
129+
val contents = queryFactory.select(
130+
contentEntity,
131+
categoryEntity.name,
132+
userLogEntity.count(),
133+
bookmarkEntity.count(),
134+
userEntity.nickname,
135+
userImageEntity.url
136+
)
117137
.from(contentEntity)
118138
.leftJoin(userLogEntity).on(userLogEntity.contentId.eq(contentEntity.id))
119139
.join(categoryEntity).on(categoryEntity.id.eq(contentEntity.categoryId))
120140
.leftJoin(bookmarkEntity).on(bookmarkEntity.contentId.eq(contentEntity.id).and(bookmarkEntity.deleted.isFalse))
141+
.join(userEntity).on(userEntity.id.eq(contentEntity.userId))
142+
.leftJoin(userImageEntity).on(userImageEntity.id.eq(userEntity.image.id))
121143
.where(
122144
categoryEntity.userId.eq(userId),
123145
categoryEntity.name.eq(categoryName),
124146
contentEntity.deleted.isFalse,
125147
)
126148
.offset(pageable.offset)
127-
.groupBy(contentEntity)
149+
.groupBy(contentEntity, userEntity.nickname, userImageEntity.url)
128150
.limit((pageable.pageSize + 1).toLong())
129151
.orderBy(getSortOrder(contentEntity.createdAt, "createdAt", pageable))
130152
.fetch()
@@ -136,28 +158,39 @@ class ContentAdapter(
136158
it[contentEntity]!!.toDomain(),
137159
it[categoryEntity.name]!!,
138160
it[userLogEntity.count()]!!,
139-
it[bookmarkEntity.count()]!!
161+
it[bookmarkEntity.count()]!!,
162+
it[userEntity.nickname]!!,
163+
it[userImageEntity.url]
140164
)
141165
}
142166

143167
return SliceImpl(contentResults, pageable, hasNext)
144168
}
145169

146170
override fun loadBookmarkedContentsByUserId(userId: Long, pageable: Pageable): Slice<ContentsResult> {
147-
val contents = queryFactory.select(contentEntity, categoryEntity.name, userLogEntity.count(), bookmarkEntity.count())
171+
val contents = queryFactory.select(
172+
contentEntity,
173+
categoryEntity.name,
174+
userLogEntity.count(),
175+
bookmarkEntity.count(),
176+
userEntity.nickname,
177+
userImageEntity.url
178+
)
148179
.from(contentEntity)
149180
.leftJoin(userLogEntity).on(userLogEntity.contentId.eq(contentEntity.id))
150181
.join(categoryEntity).on(categoryEntity.id.eq(contentEntity.categoryId))
151182
.leftJoin(reportedContentEntity).on(reportedContentEntity.contentId.eq(contentEntity.id))
152183
.leftJoin(bookmarkEntity).on(bookmarkEntity.contentId.eq(contentEntity.id).and(bookmarkEntity.deleted.isFalse))
184+
.join(userEntity).on(userEntity.id.eq(contentEntity.userId))
185+
.leftJoin(userImageEntity).on(userImageEntity.id.eq(userEntity.image.id))
153186
.where(
154187
categoryEntity.userId.eq(userId),
155188
reportedContentEntity.reporterId.ne(userId).or(reportedContentEntity.reporterId.isNull),
156189
contentEntity.deleted.isFalse,
157190
bookmarkEntity.deleted.isFalse,
158191
)
159192
.offset(pageable.offset)
160-
.groupBy(contentEntity)
193+
.groupBy(contentEntity, userEntity.nickname, userImageEntity.url)
161194
.limit((pageable.pageSize + 1).toLong())
162195
.orderBy(getSortOrder(contentEntity.createdAt, "createdAt", pageable))
163196
.fetch()
@@ -169,7 +202,9 @@ class ContentAdapter(
169202
it[contentEntity]!!.toDomain(),
170203
it[categoryEntity.name]!!,
171204
it[userLogEntity.count()]!!,
172-
it[bookmarkEntity.count()]!!
205+
it[bookmarkEntity.count()]!!,
206+
it[userEntity.nickname]!!,
207+
it[userImageEntity.url]
173208
)
174209
}
175210

@@ -230,10 +265,18 @@ class ContentAdapter(
230265
}
231266

232267
override fun loadAllByKeyword(userId: Long, searchKeywords: List<InterestType>, pageable: Pageable): Slice<ContentsResult> {
233-
val contents = queryFactory.select(contentEntity, categoryEntity.name, categoryEntity.keyword)
268+
val contents = queryFactory.select(
269+
contentEntity,
270+
categoryEntity.name,
271+
categoryEntity.keyword,
272+
userEntity.nickname,
273+
userImageEntity.url
274+
)
234275
.from(contentEntity)
235276
.join(categoryEntity).on(contentEntity.categoryId.eq(categoryEntity.id))
236277
.leftJoin(reportedContentEntity).on(reportedContentEntity.contentId.eq(contentEntity.id))
278+
.join(userEntity).on(userEntity.id.eq(contentEntity.userId))
279+
.leftJoin(userImageEntity).on(userImageEntity.id.eq(userEntity.image.id))
237280
.where(
238281
reportedContentEntity.reporterId.ne(userId).or(reportedContentEntity.reporterId.isNull),
239282
categoryEntity.openType.eq(OpenType.PUBLIC),
@@ -242,7 +285,7 @@ class ContentAdapter(
242285
contentEntity.deleted.isFalse
243286
)
244287
.offset(pageable.offset)
245-
.groupBy(contentEntity)
288+
.groupBy(contentEntity, userEntity.nickname, userImageEntity.url)
246289
.limit((pageable.pageSize + 1).toLong())
247290
.orderBy(getSortOrder(contentEntity.createdAt, "createdAt", pageable))
248291
.fetch()
@@ -253,8 +296,10 @@ class ContentAdapter(
253296
ContentsResult.of(
254297
it[contentEntity]!!.toDomain(),
255298
it[categoryEntity.name]!!,
256-
0,
257-
0,
299+
0L,
300+
0L,
301+
it[userEntity.nickname]!!,
302+
it[userImageEntity.url],
258303
it[categoryEntity.keyword]!!.kor
259304
)
260305
}

application/src/main/kotlin/com/pokit/category/port/out/CategoryPort.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface CategoryPort {
1010
fun loadByIdAndUserId(id: Long, userId: Long): Category?
1111
fun loadById(id: Long): Category?
1212
fun existsByNameAndUserId(name: String, userId: Long): Boolean
13+
fun existsByNameAndUserIdAndIdNot(id: Long, name: String, userId: Long): Boolean
1314
fun persist(category: Category): Category
1415
fun delete(category: Category)
1516
fun countByUserId(userId: Long): Int

application/src/main/kotlin/com/pokit/category/port/service/CategoryService.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class CategoryService(
4747
throw InvalidRequestException(CategoryErrorCode.UNAVAILABLE_CATEGORY_NAME)
4848
}
4949

50-
categoryPort.existsByNameAndIdOrThrow(command.categoryName, userId)
50+
categoryPort.existsByNameAndUserIdOrThrow(command.categoryName, userId)
5151

5252
if (categoryPort.countByUserId(userId) >= MAX_CATEGORY_COUNT) {
5353
throw InvalidRequestException(CategoryErrorCode.MAX_CATEGORY_LIMIT_EXCEEDED)
@@ -84,7 +84,7 @@ class CategoryService(
8484
val categoryImage = categoryImagePort.loadById(categoryCommand.categoryImageId)
8585
?: throw NotFoundCustomException(CategoryErrorCode.NOT_FOUND_CATEGORY_IMAGE)
8686

87-
categoryPort.existsByNameAndIdOrThrow(categoryCommand.categoryName, userId)
87+
categoryPort.existsByNameAndUserIdAndIdNot(category.categoryId, categoryCommand.categoryName, userId)
8888

8989
category.update(categoryCommand, categoryImage)
9090
return categoryPort.persist(category)
@@ -328,8 +328,14 @@ fun CategoryPort.loadByIdOrThrow(categoryId: Long) =
328328
loadById(categoryId)
329329
?: throw NotFoundCustomException(CategoryErrorCode.NOT_FOUND_CATEGORY)
330330

331-
fun CategoryPort.existsByNameAndIdOrThrow(categoryName: String, userId: Long) {
331+
fun CategoryPort.existsByNameAndUserIdOrThrow(categoryName: String, userId: Long) {
332332
if (existsByNameAndUserId(categoryName, userId)) {
333333
throw AlreadyExistsException(CategoryErrorCode.ALREADY_EXISTS_CATEGORY)
334334
}
335335
}
336+
337+
fun CategoryPort.existsByNameAndIdNotOrThrow(categoryId: Long, categoryName: String, userId: Long) {
338+
if (existsByNameAndUserIdAndIdNot(categoryId, categoryName, userId)) {
339+
throw AlreadyExistsException(CategoryErrorCode.ALREADY_EXISTS_CATEGORY)
340+
}
341+
}

domain/src/main/kotlin/com/pokit/content/dto/response/ContentsResult.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ data class ContentsResult(
1919
val isFavorite: Boolean,
2020
val keyword: String,
2121
val memoExists: Boolean,
22+
val author: AuthorProfile,
2223
) {
2324
companion object {
2425
fun of(
2526
content: Content,
2627
categoryName: String,
2728
isRead: Long,
2829
isFavorite: Long,
30+
authorNickname: String,
31+
authorProfileImageUrl: String?,
2932
keyword: String = "default"
3033
): ContentsResult {
3134
return ContentsResult(
@@ -42,7 +45,18 @@ data class ContentsResult(
4245
isFavorite = isFavorite > 0,
4346
keyword = keyword,
4447
memoExists = content.memo.isNotBlank(),
48+
author = AuthorProfile(
49+
userId = content.userId,
50+
nickname = authorNickname,
51+
profileImageUrl = authorProfileImageUrl
52+
)
4553
)
4654
}
4755
}
4856
}
57+
58+
data class AuthorProfile(
59+
val userId: Long,
60+
val nickname: String,
61+
val profileImageUrl: String?
62+
)

0 commit comments

Comments
 (0)