feat(channel-donation): 소유자 전용 후원 숨김 API와 조회 필터를 추가한다
This commit is contained in:
+11
@@ -6,6 +6,7 @@ import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.donation.application.CreatorChannelDonationFacade
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.web.bind.annotation.DeleteMapping
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
@@ -18,6 +19,16 @@ class CreatorChannelDonationController(
|
||||
private val creatorChannelDonationFacade: CreatorChannelDonationFacade,
|
||||
private val langContext: LangContext
|
||||
) {
|
||||
@DeleteMapping("/{creatorId}/donations/{donationId}")
|
||||
fun hideDonation(
|
||||
@PathVariable creatorId: Long,
|
||||
@PathVariable donationId: Long,
|
||||
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||
): ApiResponse<Unit> {
|
||||
creatorChannelDonationFacade.hide(creatorId, donationId, requireMember(member))
|
||||
return ApiResponse.ok<Unit>()
|
||||
}
|
||||
|
||||
@GetMapping("/{creatorId}/donations")
|
||||
fun getDonationTab(
|
||||
@PathVariable creatorId: Long,
|
||||
|
||||
+8
-1
@@ -4,6 +4,7 @@ import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.donation.dto.CreatorChannelDonationTabResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.application.CreatorChannelDonationQueryService
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.application.HideCreatorChannelDonationService
|
||||
import kr.co.vividnext.sodalive.v2.creatorname.application.CreatorLocalizedNameService
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
@@ -13,8 +14,14 @@ import java.time.LocalDateTime
|
||||
@Transactional(readOnly = true)
|
||||
class CreatorChannelDonationFacade(
|
||||
private val creatorChannelDonationQueryService: CreatorChannelDonationQueryService,
|
||||
private val creatorLocalizedNameService: CreatorLocalizedNameService
|
||||
private val creatorLocalizedNameService: CreatorLocalizedNameService,
|
||||
private val hideCreatorChannelDonationService: HideCreatorChannelDonationService
|
||||
) {
|
||||
@Transactional
|
||||
fun hide(creatorId: Long, donationId: Long, actor: Member) {
|
||||
hideCreatorChannelDonationService.hide(creatorId, donationId, actor)
|
||||
}
|
||||
|
||||
fun getDonationTab(
|
||||
creatorId: Long,
|
||||
viewer: Member,
|
||||
|
||||
+4
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.donation.dto
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import kr.co.vividnext.sodalive.extensions.toUtcIso
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.domain.CreatorChannelDonation
|
||||
@@ -48,6 +49,8 @@ data class MemberDonationRankingResponse(
|
||||
}
|
||||
|
||||
data class CreatorChannelDonationResponse(
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
val donationId: Long?,
|
||||
val nickname: String,
|
||||
val profileImageUrl: String,
|
||||
val can: Int,
|
||||
@@ -59,6 +62,7 @@ data class CreatorChannelDonationResponse(
|
||||
companion object {
|
||||
fun from(donation: CreatorChannelDonation): CreatorChannelDonationResponse {
|
||||
return CreatorChannelDonationResponse(
|
||||
donationId = donation.donationId,
|
||||
nickname = donation.nickname,
|
||||
profileImageUrl = donation.profileImageUrl,
|
||||
can = donation.can,
|
||||
|
||||
+2
@@ -87,6 +87,7 @@ class DefaultCreatorChannelDonationQueryRepository(
|
||||
.select(
|
||||
Projections.constructor(
|
||||
CreatorChannelDonationRecord::class.java,
|
||||
channelDonationMessage.id,
|
||||
channelDonationMessage.member.id,
|
||||
donorName.displayName,
|
||||
channelDonationMessage.member.profileImage,
|
||||
@@ -113,6 +114,7 @@ class DefaultCreatorChannelDonationQueryRepository(
|
||||
): BooleanExpression {
|
||||
val monthRange = queryPolicy.currentKstMonthRange(now)
|
||||
return channelDonationMessage.creator.id.eq(creatorId)
|
||||
.and(channelDonationMessage.isHidden.isFalse)
|
||||
.and(channelDonationMessage.createdAt.goe(monthRange.startInclusiveUtc))
|
||||
.and(channelDonationMessage.createdAt.lt(monthRange.endExclusiveUtc))
|
||||
}
|
||||
|
||||
+4
-2
@@ -68,7 +68,7 @@ class CreatorChannelDonationQueryService(
|
||||
return CreatorChannelDonationTab(
|
||||
donationCount = queryPort.countChannelDonations(creatorId, viewerId, now),
|
||||
rankings = findRankings(creator, viewerId),
|
||||
donations = queryPolicy.limitItems(fetchedDonations, donationPage).map { it.toDomain(creatorId, viewerId, lang) },
|
||||
donations = queryPolicy.limitItems(fetchedDonations, donationPage).map { it.toDomain(creatorId, viewer, lang) },
|
||||
page = donationPage,
|
||||
hasNext = queryPolicy.hasNext(fetchedDonations, donationPage)
|
||||
)
|
||||
@@ -95,9 +95,11 @@ class CreatorChannelDonationQueryService(
|
||||
).map { it.toDomain() }
|
||||
}
|
||||
|
||||
private fun CreatorChannelDonationRecord.toDomain(creatorId: Long, viewerId: Long, lang: Lang): CreatorChannelDonation {
|
||||
private fun CreatorChannelDonationRecord.toDomain(creatorId: Long, viewer: Member, lang: Lang): CreatorChannelDonation {
|
||||
val viewerId = viewer.id!!
|
||||
val isMasked = isSecret && viewerId != creatorId && viewerId != memberId
|
||||
return CreatorChannelDonation(
|
||||
donationId = donationId.takeIf { viewer.role == MemberRole.CREATOR && viewerId == creatorId },
|
||||
memberId = memberId,
|
||||
nickname = when {
|
||||
isMasked -> messageSource.getMessage("explorer.channel_donation.anonymous.nickname", lang).orEmpty()
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package kr.co.vividnext.sodalive.v2.creator.channel.donation.application
|
||||
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.port.out.HideCreatorChannelDonationPort
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
@Service
|
||||
class HideCreatorChannelDonationService(
|
||||
private val hideCreatorChannelDonationPort: HideCreatorChannelDonationPort
|
||||
) {
|
||||
@Transactional
|
||||
fun hide(creatorId: Long, donationId: Long, actor: Member) {
|
||||
if (actor.role != MemberRole.CREATOR || actor.id != creatorId) {
|
||||
throw SodaException(messageKey = "common.error.access_denied")
|
||||
}
|
||||
if (!hideCreatorChannelDonationPort.hideOwnedDonation(creatorId, donationId)) {
|
||||
throw SodaException(messageKey = "common.error.invalid_request")
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -19,6 +19,7 @@ data class CreatorChannelDonationRanking(
|
||||
)
|
||||
|
||||
data class CreatorChannelDonation(
|
||||
val donationId: Long?,
|
||||
val memberId: Long,
|
||||
val nickname: String,
|
||||
val profileImageUrl: String,
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ data class CreatorChannelDonationCreatorRecord(
|
||||
)
|
||||
|
||||
data class CreatorChannelDonationRecord(
|
||||
val donationId: Long,
|
||||
val memberId: Long,
|
||||
val nickname: String,
|
||||
val profileImagePath: String?,
|
||||
|
||||
Reference in New Issue
Block a user