Skip to content

Commit

Permalink
[Feature/379] 연락처 차단 목록 등록 및 매칭 알고리즘 반영 (#379)
Browse files Browse the repository at this point in the history
* feat: 연락처 차단 목록 등록 및 매칭 알고리즘 반영

* feat: 코드 깨지는 것 수정

* feat: 코드리뷰 반영

* feat: 코드리뷰 반영2

* feat: 코드 깨진 것 수정
  • Loading branch information
injoon2019 authored Sep 3, 2024
1 parent 10079f3 commit 4eb95d9
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import com.nexters.bottles.api.bottle.facade.dto.PingPongLetter
import com.nexters.bottles.api.bottle.facade.dto.PingPongListResponse
import com.nexters.bottles.api.bottle.facade.dto.PingPongUserProfile
import com.nexters.bottles.api.bottle.facade.dto.RegisterLetterRequest
import com.nexters.bottles.api.bottle.util.getLastActivatedAtInKorean
import com.nexters.bottles.api.user.component.event.dto.UserApplicationEventDto
import com.nexters.bottles.app.bottle.domain.Bottle
import com.nexters.bottles.app.bottle.domain.Letter
Expand All @@ -34,6 +33,7 @@ import com.nexters.bottles.app.bottle.service.QuestionCachingService
import com.nexters.bottles.app.config.CacheType.Name.PING_PONG_BOTTLE
import com.nexters.bottles.app.user.domain.User
import com.nexters.bottles.app.user.domain.UserProfile
import com.nexters.bottles.app.user.service.BlockContactListService
import com.nexters.bottles.app.user.service.UserReportService
import com.nexters.bottles.app.user.service.UserService
import org.springframework.beans.factory.annotation.Value
Expand All @@ -52,16 +52,21 @@ class BottleFacade(
private val bottleCachingService: BottleCachingService,
private val questionCachingService: QuestionCachingService,
private val applicationEventPublisher: ApplicationEventPublisher,
private val blockContactListService: BlockContactListService,

@Value("\${matching.isActive}")
private val isActiveMatching: Boolean,
) {

fun getNewBottles(userId: Long): BottleListResponse {
val user = userService.findByIdAndNotDeleted(userId)
val blockUserIds = blockContactListService.findAllByUserId(userId).map{ it.userId }.toSet() // 내가 차단한 유저
val blockedMeUserIds = blockContactListService.findAllByPhoneNumber(user.phoneNumber ?: throw IllegalStateException("핸드폰 번호를 등록해주세요"))
.map{ it.userId }.toSet() // 나를 차단한 유저

if (isActiveMatching) {
val matchingHour = 18
bottleService.matchRandomBottle(user, matchingHour)
bottleService.matchRandomBottle(user, matchingHour, blockUserIds, blockedMeUserIds)
?.also {
applicationEventPublisher.publishEvent(
BottleMatchEventDto(
Expand All @@ -73,14 +78,19 @@ class BottleFacade(
}
val bottles = bottleService.getNewBottles(user)
val groupByStatus = bottles.groupBy { it.bottleStatus }
val blockedUserIds = userReportService.getReportRespondentList(userId)
val reportUserIds = userReportService.getReportRespondentList(userId)
.map { it.respondentUserId }
.toSet()

val randomBottles = groupByStatus[BottleStatus.RANDOM]?.map { toBottleDto(it, userId) } ?: emptyList()
val randomBottles = groupByStatus[BottleStatus.RANDOM]
?.map { toBottleDto(it, userId) }
?: emptyList()

val sentBottles = groupByStatus[BottleStatus.SENT]
?.map { toBottleDto(it, userId) }
?.filter { it.userId !in blockedUserIds }
?.filter { it.userId !in reportUserIds }
?.filter { it.userId !in blockUserIds }
?.filter { it.userId !in blockedMeUserIds }
?: emptyList()

return BottleListResponse(
Expand Down Expand Up @@ -172,13 +182,18 @@ class BottleFacade(
val user = userService.findByIdAndNotDeleted(userId)
val pingPongBottles = bottleCachingService.getPingPongBottles(userId)
val groupByStatus = pingPongBottles.groupBy { it.pingPongStatus }
val blockedUserIds = userReportService.getReportRespondentList(userId)
val reportUserIds = userReportService.getReportRespondentList(userId)
.map { it.respondentUserId }
.toSet()
val blockUserIds = blockContactListService.findAllByUserId(userId).map{ it.userId }.toSet() // 내가 차단한 유저
val blockMeUserIds = blockContactListService.findAllByPhoneNumber(user.phoneNumber ?: throw IllegalStateException("핸드폰 번호를 등록해주세요"))
.map{ it.userId }.toSet() // 나를 차단한 유저

val activeBottles = groupByStatus[PingPongStatus.ACTIVE]
?.map { toPingPongBottleDto(it, user) }
?.filter { it.userId !in blockedUserIds }
?.filter { it.userId !in reportUserIds }
?.filter { it.userId !in blockUserIds}
?.filter { it.userId !in blockMeUserIds }
?: emptyList()
val doneBottles =
(groupByStatus[PingPongStatus.STOPPED]
Expand All @@ -187,7 +202,9 @@ class BottleFacade(
groupByStatus[PingPongStatus.MATCHED].orEmpty()
)
.map { toPingPongBottleDto(it, user) }
.filter { it.userId !in blockedUserIds }
.filter { it.userId !in reportUserIds }
.filter { it.userId !in blockUserIds}
.filter { it.userId !in blockMeUserIds }
return PingPongListResponse(activeBottles = activeBottles, doneBottles = doneBottles)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.nexters.bottles.api.user.controller
import com.nexters.bottles.api.global.interceptor.AuthRequired
import com.nexters.bottles.api.global.resolver.AuthUserId
import com.nexters.bottles.api.user.facade.UserFacade
import com.nexters.bottles.api.user.facade.dto.BlockContactListRequest
import com.nexters.bottles.api.user.facade.dto.ReportUserRequest
import io.swagger.annotations.ApiOperation
import org.springframework.web.bind.annotation.PostMapping
Expand All @@ -22,4 +23,11 @@ class UserController(
fun reportUser(@AuthUserId userId: Long, @RequestBody reportUserRequest: ReportUserRequest) {
userFacade.reportUser(userId, reportUserRequest)
}

@ApiOperation("연락처 차단 목록 등록")
@PostMapping("/block/contact-list")
@AuthRequired
fun blockContactList(@AuthUserId userId: Long, @RequestBody blockContactListRequest: BlockContactListRequest) {
userFacade.blockContactList(userId, blockContactListRequest.blockContacts)
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.nexters.bottles.api.user.facade

import com.nexters.bottles.api.user.facade.dto.ReportUserRequest
import com.nexters.bottles.app.user.domain.BlockContact
import com.nexters.bottles.app.user.domain.UserReport
import com.nexters.bottles.app.user.service.BlockContactListService
import com.nexters.bottles.app.user.service.UserReportService
import org.springframework.stereotype.Component

@Component
class UserFacade(
private val userReportService: UserReportService,
private val blockContactListService: BlockContactListService,
) {


Expand All @@ -20,4 +23,14 @@ class UserFacade(
)
)
}


fun blockContactList(userId: Long, blockContacts: Set<String>) {
val savedBlockContacts = blockContactListService.findAllByUserId(userId = userId).map { it.phoneNumber }.toSet()
val newBlockContacts = blockContacts.minus(savedBlockContacts).map { BlockContact(userId = userId, phoneNumber = it) }.toList()
val deletedBlockContacts = savedBlockContacts.minus(blockContacts).map { BlockContact(userId = userId, phoneNumber = it) }.toList()

blockContactListService.saveAll(newBlockContacts)
blockContactListService.deleteAll(deletedBlockContacts)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.nexters.bottles.api.user.facade.dto

data class BlockContactListRequest(
val blockContacts: Set<String> = setOf<String>(),
) {
}
13 changes: 13 additions & 0 deletions api/src/main/resources/sql/ddl/table_query.sql
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,16 @@ CREATE TABLE user_report
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_reporter_user_id (reporter_user_id)
);

CREATE TABLE block_contact_list
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL COMMENT '차단등록한 userId',
phone_number varchar(255) NOT NULL COMMENT '차단된 연락처',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_reporter_user_id (user_id),
INDEX idx_phone_number (phone_number),
INDEX idx_created_at (created_at),
INDEX idx_updated_at (updated_at)
);
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,17 @@ class BottleService(
}

@Transactional
fun matchRandomBottle(user: User, matchingHour: Int): Bottle? {
fun matchRandomBottle(user: User, matchingHour: Int, blockUserIds: Set<Long>, blockedMeUserIds: Set<Long>): Bottle? {
if (user.isNotRegisterProfile()) return null
if (user.isMatchInactive()) return null

val matchingTime = getMatchingTime(matchingHour)
if (user.lastRandomMatchedAt > matchingTime) return null

val usersCanBeMatched = bottleMatchingRepository.findAllUserCanBeMatched(user.id, user.gender!!)
.filter { it.willMatchUserId !in blockUserIds }
.filter { it.willMatchUserId !in blockedMeUserIds }

if (usersCanBeMatched.isEmpty()) return null

val matchingUserDto = findUserSameRegionOrRandom(usersCanBeMatched, user)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.nexters.bottles.app.user.domain

import com.nexters.bottles.app.common.BaseEntity
import javax.persistence.*

@Entity
class BlockContact(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L,

val userId: Long, // 차단 등록한 유저

var phoneNumber: String,
) : BaseEntity() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.nexters.bottles.app.user.repository

import com.nexters.bottles.app.user.domain.BlockContact
import org.springframework.data.jpa.repository.JpaRepository

interface BlockContactRepository : JpaRepository<BlockContact, Long> {

fun findAllByUserId(userId: Long): List<BlockContact>

fun findAllByPhoneNumber(phoneNumber: String): List<BlockContact>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.nexters.bottles.app.user.service

import com.nexters.bottles.app.user.domain.BlockContact
import com.nexters.bottles.app.user.repository.BlockContactRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class BlockContactListService(
private val blockContactListRepository: BlockContactRepository,
) {

@Transactional(readOnly = true)
fun findAllByUserId(userId: Long): List<BlockContact> {
return blockContactListRepository.findAllByUserId(userId)
}

@Transactional
fun saveAll(newBlockContactList: List<BlockContact>) {
blockContactListRepository.saveAll(newBlockContactList)
}

@Transactional
fun deleteAll(newBlockContacts: List<BlockContact>) {
blockContactListRepository.deleteAll(newBlockContacts)
}

@Transactional(readOnly = true)
fun findAllByPhoneNumber(phoneNumber: String): List<BlockContact> {
return blockContactListRepository.findAllByPhoneNumber(phoneNumber)
}
}

0 comments on commit 4eb95d9

Please sign in to comment.