diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerQueryRepository.kt index 674d5c4..e119fc9 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerQueryRepository.kt @@ -18,8 +18,6 @@ import kr.co.vividnext.sodalive.explorer.profile.CreatorCheers import kr.co.vividnext.sodalive.explorer.profile.QChannelNotice.channelNotice import kr.co.vividnext.sodalive.explorer.profile.QCreatorCheers.creatorCheers import kr.co.vividnext.sodalive.explorer.profile.TimeDifferenceResult -import kr.co.vividnext.sodalive.explorer.section.ExplorerSection -import kr.co.vividnext.sodalive.explorer.section.QExplorerSection.explorerSection import kr.co.vividnext.sodalive.live.room.LiveRoom import kr.co.vividnext.sodalive.live.room.LiveRoomType import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom @@ -36,6 +34,7 @@ import kr.co.vividnext.sodalive.member.tag.QMemberCreatorTag.memberCreatorTag import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Repository import java.time.Duration +import java.time.LocalDate import java.time.LocalDateTime import java.time.ZoneId import java.time.format.DateTimeFormatter @@ -172,36 +171,38 @@ class ExplorerQueryRepository( .where( member.role.eq(MemberRole.CREATOR) .and(member.createdAt.goe(LocalDateTime.now().minusDays(30))) + .and(member.isActive.isTrue) ) .orderBy(Expressions.numberTemplate(Double::class.java, "function('rand')").asc()) .limit(20) .fetch() } - fun getExplorerSectionData(isAdult: Boolean): List { - var explorerSectionCondition = explorerSection.isActive.eq(true) - if (!isAdult) { - explorerSectionCondition = explorerSectionCondition.and(explorerSection.isAdult.isFalse) + fun findCreatorByGender(gender: Int): List { + val today = LocalDate.now() + val offset = (today.dayOfMonth - 1) % 26 + val characters = ('A'..'Z').map { it.toString() } + val rotatedChars = characters.drop(offset) + characters.take(offset) + + val caseWhenClauses = rotatedChars.withIndex().joinToString(" ") { + "WHEN ${member.email} LIKE '${it.value}%' THEN ${it.index + 1}" } + val caseExpression = Expressions.stringTemplate("CASE $caseWhenClauses END") - return queryFactory - .selectFrom(explorerSection) - .where(explorerSectionCondition) - .orderBy(explorerSection.orders.asc()) - .fetch() - } + val randomExpression = Expressions.numberTemplate(Double::class.java, "function('rand')").asc() - fun findMemberByTag(tags: List): List { return queryFactory .selectFrom(member) - .leftJoin(member.tags, memberCreatorTag) - .join(memberCreatorTag.tag, creatorTag) + .innerJoin(member.auth, auth) .where( member.role.eq(MemberRole.CREATOR) - .and(creatorTag.tag.`in`(tags)) + .and(member.isActive.isTrue) + .and(auth.gender.eq(gender)) ) + .orderBy(caseExpression.asc(), randomExpression) + .offset(0) + .limit(10) .fetch() - .distinct() } fun getSearchChannel(channel: String, memberId: Long): List { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt index 2a1515d..b46fa76 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt @@ -29,6 +29,7 @@ import java.time.LocalDate import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.time.temporal.TemporalAdjusters +import kotlin.random.Random @Service @Transactional(readOnly = true) @@ -52,25 +53,8 @@ class ExplorerService( // 인기 크리에이터 val creatorRankings = queryRepository .getCreatorRankings() - .asSequence() .filter { !memberService.isBlocked(blockedMemberId = member.id!!, memberId = it.id!!) } - .map { - GetExplorerSectionCreatorResponse( - id = it.id!!, - nickname = it.nickname, - tags = it.tags - .asSequence() - .filter { tag -> tag.tag.isActive } - .map { tag -> tag.tag.tag } - .joinToString(" ") { tag -> "#$tag" }, - profileImageUrl = if (it.profileImage != null) { - "$cloudFrontHost/${it.profileImage}" - } else { - "$cloudFrontHost/profile/default-profile.png" - } - ) - } - .toList() + .map { it.toExplorerSectionCreator(cloudFrontHost) } val currentDateTime = LocalDateTime.now() val lastMonday = currentDateTime @@ -97,25 +81,8 @@ class ExplorerService( // 새로 시작 (newCreators) val newCreators = queryRepository .getNewCreators() - .asSequence() .filter { !memberService.isBlocked(blockedMemberId = member.id!!, memberId = it.id!!) } - .map { - GetExplorerSectionCreatorResponse( - id = it.id!!, - nickname = it.nickname, - tags = it.tags - .asSequence() - .filter { tag -> tag.tag.isActive } - .map { tag -> tag.tag.tag } - .joinToString(" ") { tag -> "#$tag" }, - profileImageUrl = if (it.profileImage != null) { - "$cloudFrontHost/${it.profileImage}" - } else { - "$cloudFrontHost/profile/default-profile.png" - } - ) - } - .toList() + .map { it.toExplorerSectionCreator(cloudFrontHost) } val newCreatorsSection = GetExplorerSectionResponse( title = "새로 시작", @@ -125,52 +92,35 @@ class ExplorerService( ) sections.add(newCreatorsSection) - // 관리자에서 설정한 타이틀과 크리에이터 - sections.addAll( - queryRepository - .getExplorerSectionData(isAdult = member.auth != null) - .asSequence() - .map { - val tags = it.tags.asSequence().map { explorerSectionTag -> explorerSectionTag.tag!!.tag }.toList() - val creators = queryRepository.findMemberByTag(tags) - .asSequence() - .filter { creator -> - !memberService.isBlocked( - blockedMemberId = member.id!!, - memberId = creator.id!! - ) - } - .toList() - - GetExplorerSectionResponse( - it.title, - it.coloredTitle, - it.color, - creators = creators - .asSequence() - .map { account -> - GetExplorerSectionCreatorResponse( - id = account.id!!, - nickname = account.nickname, - tags = account.tags - .asSequence() - .filter { counselorTag -> counselorTag.tag.isActive } - .toList() - .joinToString(" ") { counselorTag -> - "#${counselorTag.tag.tag}" - }, - profileImageUrl = if (account.profileImage != null) { - "$cloudFrontHost/${account.profileImage}" - } else { - "$cloudFrontHost/profile/default-profile.png" - } - ) - }.toList() - ) - } - .toList() + val maleCreatorSection = GetExplorerSectionResponse( + title = "남자 크리에이터", + coloredTitle = "남자", + color = "39abde", + creators = queryRepository + .findCreatorByGender(1) + .filter { !memberService.isBlocked(blockedMemberId = member.id!!, memberId = it.id!!) } + .map { it.toExplorerSectionCreator(cloudFrontHost) } ) + val femaleCreatorSection = GetExplorerSectionResponse( + title = "여자 크리에이터", + coloredTitle = "여자", + color = "ff5c49", + creators = queryRepository + .findCreatorByGender(0) + .filter { !memberService.isBlocked(blockedMemberId = member.id!!, memberId = it.id!!) } + .map { it.toExplorerSectionCreator(cloudFrontHost) } + ) + + val randomInt = Random.nextInt(0, 2) + if (randomInt == 0) { + sections.add(femaleCreatorSection) + sections.add(maleCreatorSection) + } else { + sections.add(maleCreatorSection) + sections.add(femaleCreatorSection) + } + return GetExplorerResponse(sections = sections) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/Member.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/Member.kt index f48575b..fa268fc 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/member/Member.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/Member.kt @@ -1,6 +1,7 @@ package kr.co.vividnext.sodalive.member import kr.co.vividnext.sodalive.common.BaseEntity +import kr.co.vividnext.sodalive.explorer.GetExplorerSectionCreatorResponse import kr.co.vividnext.sodalive.member.auth.Auth import kr.co.vividnext.sodalive.member.following.CreatorFollowing import kr.co.vividnext.sodalive.member.notification.MemberNotification @@ -107,6 +108,22 @@ data class Member( } } } + + fun toExplorerSectionCreator(imageHost: String): GetExplorerSectionCreatorResponse { + return GetExplorerSectionCreatorResponse( + id = id!!, + nickname = nickname, + tags = tags + .filter { tag -> tag.tag.isActive } + .map { tag -> tag.tag.tag } + .joinToString(" ") { tag -> "#$tag" }, + profileImageUrl = if (profileImage != null) { + "$imageHost/$profileImage" + } else { + "$imageHost/profile/default-profile.png" + } + ) + } } enum class Gender {