| @@ -166,7 +166,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { | |||||||
|                     .and(useCan.createdAt.loe(endDate)) |                     .and(useCan.createdAt.loe(endDate)) | ||||||
|             ) |             ) | ||||||
|             .groupBy(donationFormattedDate, audioContent.id) |             .groupBy(donationFormattedDate, audioContent.id) | ||||||
|             .orderBy(member.id.asc(), donationFormattedDate.desc()) |             .orderBy(member.id.asc(), donationFormattedDate.desc(), audioContent.id.desc()) | ||||||
|             .fetch() |             .fetch() | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -219,7 +219,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { | |||||||
|                     .and(useCan.createdAt.loe(endDate)) |                     .and(useCan.createdAt.loe(endDate)) | ||||||
|             ) |             ) | ||||||
|             .groupBy(formattedDate, creatorCommunity.id, creatorSettlementRatio.communitySettlementRatio) |             .groupBy(formattedDate, creatorCommunity.id, creatorSettlementRatio.communitySettlementRatio) | ||||||
|             .orderBy(member.id.asc(), formattedDate.desc()) |             .orderBy(member.id.asc(), formattedDate.desc(), creatorCommunity.id.desc()) | ||||||
|             .offset(offset) |             .offset(offset) | ||||||
|             .limit(limit) |             .limit(limit) | ||||||
|             .fetch() |             .fetch() | ||||||
|   | |||||||
| @@ -1,13 +1,13 @@ | |||||||
| package kr.co.vividnext.sodalive.content.comment | package kr.co.vividnext.sodalive.content.comment | ||||||
|  |  | ||||||
|  | import com.querydsl.core.types.dsl.Expressions | ||||||
| import com.querydsl.jpa.impl.JPAQueryFactory | import com.querydsl.jpa.impl.JPAQueryFactory | ||||||
| import kr.co.vividnext.sodalive.content.QAudioContent.audioContent | import kr.co.vividnext.sodalive.content.QAudioContent.audioContent | ||||||
| import kr.co.vividnext.sodalive.content.comment.QAudioContentComment.audioContentComment | import kr.co.vividnext.sodalive.content.comment.QAudioContentComment.audioContentComment | ||||||
| import kr.co.vividnext.sodalive.member.QMember.member | import kr.co.vividnext.sodalive.member.QMember.member | ||||||
| import org.springframework.data.jpa.repository.JpaRepository | import org.springframework.data.jpa.repository.JpaRepository | ||||||
| import org.springframework.stereotype.Repository | import org.springframework.stereotype.Repository | ||||||
| import java.time.ZoneId | import java.time.LocalDateTime | ||||||
| import java.time.format.DateTimeFormatter |  | ||||||
|  |  | ||||||
| @Repository | @Repository | ||||||
| interface AudioContentCommentRepository : JpaRepository<AudioContentComment, Long>, AudioContentCommentQueryRepository | interface AudioContentCommentRepository : JpaRepository<AudioContentComment, Long>, AudioContentCommentQueryRepository | ||||||
| @@ -64,8 +64,33 @@ class AudioContentCommentQueryRepositoryImpl( | |||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         val formattedDate = Expressions.stringTemplate( | ||||||
|  |             "DATE_FORMAT({0}, {1})", | ||||||
|  |             Expressions.dateTimeTemplate( | ||||||
|  |                 LocalDateTime::class.java, | ||||||
|  |                 "CONVERT_TZ({0},{1},{2})", | ||||||
|  |                 audioContentComment.createdAt, | ||||||
|  |                 "UTC", | ||||||
|  |                 "Asia/Seoul" | ||||||
|  |             ), | ||||||
|  |             "%Y.%m.%d %W %h:%i %p" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|         return queryFactory |         return queryFactory | ||||||
|             .selectFrom(audioContentComment) |             .select( | ||||||
|  |                 QGetAudioContentCommentListItem( | ||||||
|  |                     audioContentComment.id, | ||||||
|  |                     audioContentComment.member.id, | ||||||
|  |                     audioContentComment.member.nickname, | ||||||
|  |                     audioContentComment.member.profileImage.prepend("/").prepend(cloudFrontHost), | ||||||
|  |                     audioContentComment.comment, | ||||||
|  |                     audioContentComment.isSecret, | ||||||
|  |                     audioContentComment.donationCan.coalesce(0), | ||||||
|  |                     formattedDate, | ||||||
|  |                     Expressions.constant(0) | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |             .from(audioContentComment) | ||||||
|             .innerJoin(audioContentComment.audioContent, audioContent) |             .innerJoin(audioContentComment.audioContent, audioContent) | ||||||
|             .innerJoin(audioContentComment.member, member) |             .innerJoin(audioContentComment.member, member) | ||||||
|             .where(where) |             .where(where) | ||||||
| @@ -74,25 +99,8 @@ class AudioContentCommentQueryRepositoryImpl( | |||||||
|             .orderBy(audioContentComment.createdAt.desc()) |             .orderBy(audioContentComment.createdAt.desc()) | ||||||
|             .fetch() |             .fetch() | ||||||
|             .map { |             .map { | ||||||
|                 val date = it.createdAt!! |                 it.replyCount = commentReplyCountByAudioContentCommentId(it.id) | ||||||
|                     .atZone(ZoneId.of("UTC")) |                 it | ||||||
|                     .withZoneSameInstant(ZoneId.of(timezone)) |  | ||||||
|  |  | ||||||
|                 GetAudioContentCommentListItem( |  | ||||||
|                     id = it.id!!, |  | ||||||
|                     writerId = it.member!!.id!!, |  | ||||||
|                     nickname = it.member!!.nickname, |  | ||||||
|                     profileUrl = if (it.member!!.profileImage != null) { |  | ||||||
|                         "$cloudFrontHost/${it.member!!.profileImage}" |  | ||||||
|                     } else { |  | ||||||
|                         "$cloudFrontHost/profile/default-profile.png" |  | ||||||
|                     }, |  | ||||||
|                     comment = it.comment, |  | ||||||
|                     isSecret = it.isSecret, |  | ||||||
|                     donationCan = it.donationCan ?: 0, |  | ||||||
|                     date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")), |  | ||||||
|                     replyCount = commentReplyCountByAudioContentCommentId(it.id!!) |  | ||||||
|                 ) |  | ||||||
|             } |             } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -137,7 +145,34 @@ class AudioContentCommentQueryRepositoryImpl( | |||||||
|         offset: Long, |         offset: Long, | ||||||
|         limit: Int |         limit: Int | ||||||
|     ): List<GetAudioContentCommentListItem> { |     ): List<GetAudioContentCommentListItem> { | ||||||
|         return queryFactory.selectFrom(audioContentComment) |         val formattedDate = Expressions.stringTemplate( | ||||||
|  |             "DATE_FORMAT({0}, {1})", | ||||||
|  |             Expressions.dateTimeTemplate( | ||||||
|  |                 LocalDateTime::class.java, | ||||||
|  |                 "CONVERT_TZ({0},{1},{2})", | ||||||
|  |                 audioContentComment.createdAt, | ||||||
|  |                 "UTC", | ||||||
|  |                 "Asia/Seoul" | ||||||
|  |             ), | ||||||
|  |             "%Y.%m.%d %W %h:%i %p" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         return queryFactory | ||||||
|  |             .select( | ||||||
|  |                 QGetAudioContentCommentListItem( | ||||||
|  |                     audioContentComment.id, | ||||||
|  |                     audioContentComment.member.id, | ||||||
|  |                     audioContentComment.member.nickname, | ||||||
|  |                     audioContentComment.member.profileImage.prepend("/").prepend(cloudFrontHost), | ||||||
|  |                     audioContentComment.comment, | ||||||
|  |                     audioContentComment.isSecret, | ||||||
|  |                     audioContentComment.donationCan.coalesce(0), | ||||||
|  |                     formattedDate, | ||||||
|  |                     Expressions.constant(0) | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |             .from(audioContentComment) | ||||||
|  |             .innerJoin(audioContentComment.member, member) | ||||||
|             .where( |             .where( | ||||||
|                 audioContentComment.parent.isNotNull |                 audioContentComment.parent.isNotNull | ||||||
|                     .and(audioContentComment.parent.id.eq(commentId)) |                     .and(audioContentComment.parent.id.eq(commentId)) | ||||||
| @@ -147,29 +182,6 @@ class AudioContentCommentQueryRepositoryImpl( | |||||||
|             .limit(limit.toLong()) |             .limit(limit.toLong()) | ||||||
|             .orderBy(audioContentComment.createdAt.desc()) |             .orderBy(audioContentComment.createdAt.desc()) | ||||||
|             .fetch() |             .fetch() | ||||||
|             .asSequence() |  | ||||||
|             .map { |  | ||||||
|                 val date = it.createdAt!! |  | ||||||
|                     .atZone(ZoneId.of("UTC")) |  | ||||||
|                     .withZoneSameInstant(ZoneId.of(timezone)) |  | ||||||
|  |  | ||||||
|                 GetAudioContentCommentListItem( |  | ||||||
|                     id = it.id!!, |  | ||||||
|                     writerId = it.member!!.id!!, |  | ||||||
|                     nickname = it.member!!.nickname, |  | ||||||
|                     profileUrl = if (it.member!!.profileImage != null) { |  | ||||||
|                         "$cloudFrontHost/${it.member!!.profileImage}" |  | ||||||
|                     } else { |  | ||||||
|                         "$cloudFrontHost/profile/default-profile.png" |  | ||||||
|                     }, |  | ||||||
|                     comment = it.comment, |  | ||||||
|                     isSecret = it.isSecret, |  | ||||||
|                     donationCan = it.donationCan ?: 0, |  | ||||||
|                     date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")), |  | ||||||
|                     replyCount = 0 |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|             .toList() |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun findPushTokenByContentIdAndCommentParentIdMyMemberId( |     override fun findPushTokenByContentIdAndCommentParentIdMyMemberId( | ||||||
|   | |||||||
| @@ -132,7 +132,11 @@ class AudioContentCommentService( | |||||||
|         return GetAudioContentCommentListResponse(totalCount, commentList) |         return GetAudioContentCommentListResponse(totalCount, commentList) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun getCommentReplyList(commentId: Long, timezone: String, pageable: Pageable): GetAudioContentCommentListResponse { |     fun getCommentReplyList( | ||||||
|  |         commentId: Long, | ||||||
|  |         timezone: String, | ||||||
|  |         pageable: Pageable | ||||||
|  |     ): GetAudioContentCommentListResponse { | ||||||
|         val commentList = repository.getAudioContentCommentReplyList( |         val commentList = repository.getAudioContentCommentReplyList( | ||||||
|             cloudFrontHost = cloudFrontHost, |             cloudFrontHost = cloudFrontHost, | ||||||
|             commentId = commentId, |             commentId = commentId, | ||||||
|   | |||||||
| @@ -16,5 +16,5 @@ data class GetAudioContentCommentListItem @QueryProjection constructor( | |||||||
|     val isSecret: Boolean, |     val isSecret: Boolean, | ||||||
|     val donationCan: Int, |     val donationCan: Int, | ||||||
|     val date: String, |     val date: String, | ||||||
|     val replyCount: Int |     var replyCount: Int = 0 | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | package kr.co.vividnext.sodalive.member | ||||||
|  |  | ||||||
|  | import com.querydsl.core.annotations.QueryProjection | ||||||
|  |  | ||||||
|  | data class GetMemberProfileResponse @QueryProjection constructor( | ||||||
|  |     val memberId: Long, | ||||||
|  |     val nickname: String, | ||||||
|  |     val profileImageUrl: String, | ||||||
|  |     val isBlocked: Boolean | ||||||
|  | ) | ||||||
| @@ -10,6 +10,7 @@ import org.springframework.data.domain.Pageable | |||||||
| import org.springframework.security.core.annotation.AuthenticationPrincipal | import org.springframework.security.core.annotation.AuthenticationPrincipal | ||||||
| import org.springframework.security.core.userdetails.User | import org.springframework.security.core.userdetails.User | ||||||
| import org.springframework.web.bind.annotation.GetMapping | import org.springframework.web.bind.annotation.GetMapping | ||||||
|  | import org.springframework.web.bind.annotation.PathVariable | ||||||
| import org.springframework.web.bind.annotation.PostMapping | import org.springframework.web.bind.annotation.PostMapping | ||||||
| import org.springframework.web.bind.annotation.PutMapping | import org.springframework.web.bind.annotation.PutMapping | ||||||
| import org.springframework.web.bind.annotation.RequestBody | import org.springframework.web.bind.annotation.RequestBody | ||||||
| @@ -240,4 +241,13 @@ class MemberController(private val service: MemberService) { | |||||||
|     fun forgotPassword( |     fun forgotPassword( | ||||||
|         @RequestBody request: ForgotPasswordRequest |         @RequestBody request: ForgotPasswordRequest | ||||||
|     ) = ApiResponse.ok(service.forgotPassword(request)) |     ) = ApiResponse.ok(service.forgotPassword(request)) | ||||||
|  |  | ||||||
|  |     @GetMapping("/profile/{id}") | ||||||
|  |     fun getMemberProfile( | ||||||
|  |         @PathVariable id: Long, | ||||||
|  |         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? | ||||||
|  |     ) = run { | ||||||
|  |         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||||
|  |         ApiResponse.ok(service.getMemberProfile(memberId = id, myMemberId = member.id!!)) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,10 +8,12 @@ import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom | |||||||
| import kr.co.vividnext.sodalive.member.QMember.member | import kr.co.vividnext.sodalive.member.QMember.member | ||||||
| import kr.co.vividnext.sodalive.member.auth.QAuth.auth | import kr.co.vividnext.sodalive.member.auth.QAuth.auth | ||||||
| import kr.co.vividnext.sodalive.member.block.BlockMemberRepository | import kr.co.vividnext.sodalive.member.block.BlockMemberRepository | ||||||
|  | import kr.co.vividnext.sodalive.member.block.QBlockMember.blockMember | ||||||
| import kr.co.vividnext.sodalive.member.following.QCreatorFollowing.creatorFollowing | import kr.co.vividnext.sodalive.member.following.QCreatorFollowing.creatorFollowing | ||||||
| import kr.co.vividnext.sodalive.member.nickname.QNicknameChangeLog.nicknameChangeLog | import kr.co.vividnext.sodalive.member.nickname.QNicknameChangeLog.nicknameChangeLog | ||||||
| import kr.co.vividnext.sodalive.member.notification.QMemberNotification.memberNotification | import kr.co.vividnext.sodalive.member.notification.QMemberNotification.memberNotification | ||||||
| import kr.co.vividnext.sodalive.message.QMessage.message | import kr.co.vividnext.sodalive.message.QMessage.message | ||||||
|  | import org.springframework.beans.factory.annotation.Value | ||||||
| import org.springframework.data.jpa.repository.JpaRepository | import org.springframework.data.jpa.repository.JpaRepository | ||||||
| import org.springframework.stereotype.Repository | import org.springframework.stereotype.Repository | ||||||
|  |  | ||||||
| @@ -54,12 +56,17 @@ interface MemberQueryRepository { | |||||||
|  |  | ||||||
|     fun getChangeNoticeRecipientPushTokens(creatorId: Long): Map<String, List<List<String>>> |     fun getChangeNoticeRecipientPushTokens(creatorId: Long): Map<String, List<List<String>>> | ||||||
|     fun getPushTokenFromReservationList(roomId: Long): Map<String, List<List<String>>> |     fun getPushTokenFromReservationList(roomId: Long): Map<String, List<List<String>>> | ||||||
|  |  | ||||||
|  |     fun getMemberProfile(memberId: Long, myMemberId: Long): GetMemberProfileResponse | ||||||
| } | } | ||||||
|  |  | ||||||
| @Repository | @Repository | ||||||
| class MemberQueryRepositoryImpl( | class MemberQueryRepositoryImpl( | ||||||
|     private val queryFactory: JPAQueryFactory, |     private val queryFactory: JPAQueryFactory, | ||||||
|     private val blockMemberRepository: BlockMemberRepository |     private val blockMemberRepository: BlockMemberRepository, | ||||||
|  |  | ||||||
|  |     @Value("\${cloud.aws.cloud-front.host}") | ||||||
|  |     private val cloudFrontHost: String | ||||||
| ) : MemberQueryRepository { | ) : MemberQueryRepository { | ||||||
|     override fun findByPushToken(pushToken: String): List<Member> { |     override fun findByPushToken(pushToken: String): List<Member> { | ||||||
|         return queryFactory |         return queryFactory | ||||||
| @@ -415,4 +422,25 @@ class MemberQueryRepositoryImpl( | |||||||
|  |  | ||||||
|         return mapOf("aos" to aosPushTokens, "ios" to iosPushTokens) |         return mapOf("aos" to aosPushTokens, "ios" to iosPushTokens) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     override fun getMemberProfile(memberId: Long, myMemberId: Long): GetMemberProfileResponse { | ||||||
|  |         return queryFactory | ||||||
|  |             .select( | ||||||
|  |                 QGetMemberProfileResponse( | ||||||
|  |                     member.id, | ||||||
|  |                     member.nickname, | ||||||
|  |                     member.profileImage.prepend("/").prepend(cloudFrontHost), | ||||||
|  |                     blockMember.id.isNotNull | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |             .from(member) | ||||||
|  |             .leftJoin(blockMember) | ||||||
|  |             .on( | ||||||
|  |                 member.id.eq(blockMember.blockedMember.id) | ||||||
|  |                     .and(blockMember.isActive.isTrue) | ||||||
|  |                     .and(blockMember.member.id.eq(myMemberId)) | ||||||
|  |             ) | ||||||
|  |             .where(member.id.eq(memberId)) | ||||||
|  |             .fetchFirst() | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -622,6 +622,10 @@ class MemberService( | |||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fun getMemberProfile(memberId: Long, myMemberId: Long): GetMemberProfileResponse { | ||||||
|  |         return repository.getMemberProfile(memberId, myMemberId) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private fun getOrCreateLock(memberId: Long): ReentrantReadWriteLock { |     private fun getOrCreateLock(memberId: Long): ReentrantReadWriteLock { | ||||||
|         return tokenLocks.computeIfAbsent(memberId) { ReentrantReadWriteLock() } |         return tokenLocks.computeIfAbsent(memberId) { ReentrantReadWriteLock() } | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user