diff --git a/app/src/main/kotlin/com/wespot/message/schedule/MessageScheduler.kt b/app/src/main/kotlin/com/wespot/message/schedule/MessageScheduler.kt index fb247656..7c0e6ae1 100644 --- a/app/src/main/kotlin/com/wespot/message/schedule/MessageScheduler.kt +++ b/app/src/main/kotlin/com/wespot/message/schedule/MessageScheduler.kt @@ -14,4 +14,5 @@ class MessageScheduler( fun scheduleMessageUpdate() { schedulerMessageUseCase.sendScheduledMessages() } + } diff --git a/app/src/main/kotlin/com/wespot/vote/VoteController.kt b/app/src/main/kotlin/com/wespot/vote/VoteController.kt index 08cf1f97..64b16fab 100644 --- a/app/src/main/kotlin/com/wespot/vote/VoteController.kt +++ b/app/src/main/kotlin/com/wespot/vote/VoteController.kt @@ -1,7 +1,7 @@ package com.wespot.vote import com.wespot.vote.dto.request.VoteRequests -import com.wespot.vote.dto.response.SaveVoteResponse +import com.wespot.vote.dto.response.SavedVoteResponse import com.wespot.vote.dto.response.VoteItems import com.wespot.vote.dto.response.received.ReceivedVoteResponse import com.wespot.vote.dto.response.received.ReceivedVotesResponses @@ -41,8 +41,8 @@ class VoteController( @PostMapping fun createVote( @RequestBody requests: VoteRequests - ): ResponseEntity { - val savedId: SaveVoteResponse = savedVoteUseCase.saveVote(requests) + ): ResponseEntity { + val savedId: SavedVoteResponse = savedVoteUseCase.saveVote(requests) return ResponseEntity.status(HttpStatus.CREATED) .body(savedId) } diff --git a/app/src/test/kotlin/com/wespot/auth/service/AuthServiceTest.kt b/app/src/test/kotlin/com/wespot/auth/service/AuthServiceTest.kt index 0eb4da80..a5578d69 100644 --- a/app/src/test/kotlin/com/wespot/auth/service/AuthServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/auth/service/AuthServiceTest.kt @@ -17,9 +17,6 @@ import com.wespot.exception.CustomException import com.wespot.exception.ExceptionView import com.wespot.school.port.out.SchoolPort import com.wespot.user.SocialType -import com.wespot.user.event.CreatedVoteEvent -import com.wespot.user.event.SignUpUserEvent -import com.wespot.user.event.WelcomeMessageEvent import com.wespot.user.fixture.UserFixture import com.wespot.user.port.out.FCMPort import com.wespot.user.port.out.ProfilePort @@ -36,7 +33,6 @@ import io.mockk.every import io.mockk.just import io.mockk.mockk import io.mockk.spyk -import org.springframework.context.ApplicationEventPublisher import org.springframework.http.HttpStatus import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.core.Authentication @@ -56,7 +52,6 @@ class AuthServiceTest : BehaviorSpec({ val authenticationManager = mockk() val passwordEncoder = mockk() val refreshTokenService = mockk() - val eventPublisher = mockk() val fcmPort = mockk() val restrictionPort = mockk() val personalInfoPort = mockk() @@ -77,7 +72,6 @@ class AuthServiceTest : BehaviorSpec({ authenticationManager = authenticationManager, passwordEncoder = passwordEncoder, refreshTokenService = refreshTokenService, - eventPublisher = eventPublisher, fcmPort = fcmPort, secretKey = secretKey, restrictionPort = restrictionPort, @@ -219,9 +213,6 @@ class AuthServiceTest : BehaviorSpec({ every { userPort.save(any()) } returns user every { authService.saveRelatedEntities(user, signUpRequest, authData.fcmToken) } just Runs every { authService.signIn(any()) } returns tokenAndUserDetailResponse - every { eventPublisher.publishEvent(SignUpUserEvent(user)) } returns Unit - every { eventPublisher.publishEvent(CreatedVoteEvent(user)) } returns Unit - every { eventPublisher.publishEvent(WelcomeMessageEvent(user)) } returns Unit `when`("사용자가 signUp을 호출할 때") { val response = authService.signUp(signUpRequest) diff --git a/app/src/test/kotlin/com/wespot/message/domain/MessageTest.kt b/app/src/test/kotlin/com/wespot/message/domain/MessageTest.kt index 8ba32689..8a4d6452 100644 --- a/app/src/test/kotlin/com/wespot/message/domain/MessageTest.kt +++ b/app/src/test/kotlin/com/wespot/message/domain/MessageTest.kt @@ -4,6 +4,9 @@ import com.wespot.exception.CustomException import com.wespot.message.Message import com.wespot.message.MessageTimeValidator import com.wespot.message.fixture.MessageFixture +import com.wespot.user.RestrictionType +import com.wespot.user.fixture.ProfileFixture +import com.wespot.user.fixture.UserFixture import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe @@ -63,8 +66,8 @@ class MessageTest : BehaviorSpec({ val shouldThrow = shouldThrow { Message.sendMessage( badWordsContent, - 1, - 2, + UserFixture.createWithId(1), + UserFixture.createWithId(2), "senderName", false ) @@ -77,8 +80,8 @@ class MessageTest : BehaviorSpec({ val shouldThrow = shouldThrow { Message.sendMessage( emptyContent, - 1, - 2, + UserFixture.createWithId(1), + UserFixture.createWithId(2), "senderName", false ) @@ -90,4 +93,145 @@ class MessageTest : BehaviorSpec({ unmockkStatic(LocalDateTime::class) } + given("쪽지를 수정할 때") { + val restrictionUser = + UserFixture.createUserWithIdAndRestrictionTypeAndRestrictDay( + 1, + listOf(Pair(RestrictionType.PERMANENT_BAN_MESSAGE_REPORT, Long.MAX_VALUE)) + ) + val withDrawUser = UserFixture.createWithId(2).withdraw().completeWithdraw(ProfileFixture.createWithId(1)) + val restrictionUserMessage = MessageFixture.createMessage("Hello", 2, 1, "senderName") + val withDrawUserMessage = MessageFixture.createMessage("Hello", 1, 2, "senderName") + `when`("수정하는 자가 탈퇴 혹은 이용제재를 당한 사용자라면") { + val shouldThrow1 = shouldThrow { + restrictionUserMessage.updateMessage( + "Hello1", + restrictionUser, + withDrawUser.id, + restrictionUser.name + ) + } + val shouldThrow2 = shouldThrow { + withDrawUserMessage.updateMessage( + "Hello2", + withDrawUser, + restrictionUser.id, + withDrawUser.name + ) + } + then("예외가 발생한다.") { + shouldThrow1 shouldHaveMessage "이용제한을 당한 학생은 해당 서비스를 이용할 수 없습니다." + shouldThrow2 shouldHaveMessage "탈퇴한 학생은 해당 서비스를 이용할 수 없습니다." + } + } + } + + given("쪽지를 보낼 때") { + val restrictionUser = + UserFixture.createUserWithIdAndRestrictionTypeAndRestrictDay( + 1, + listOf(Pair(RestrictionType.PERMANENT_BAN_MESSAGE_REPORT, Long.MAX_VALUE)) + ) + val withDrawUser = UserFixture.createWithId(2).withdraw().completeWithdraw(ProfileFixture.createWithId(1)) + `when`("송신자가 탈퇴 혹은 이용제재를 당한 사용자라면") { + val shouldThrow1 = shouldThrow { + Message.sendMessage( + "hello", + UserFixture.createWithId(3), + withDrawUser, + withDrawUser.name, + false, + ) + } + val shouldThrow2 = shouldThrow { + Message.sendMessage( + "hello", + UserFixture.createWithId(3), + restrictionUser, + restrictionUser.name, + false + ) + } + + then("예외가 발생한다.") { + shouldThrow1 shouldHaveMessage "탈퇴한 학생은 해당 서비스를 이용할 수 없습니다." + shouldThrow2 shouldHaveMessage "이용제한을 당한 학생은 해당 서비스를 이용할 수 없습니다." + } + } + + `when`("수신자가 탈퇴 혹은 이용제재를 당한 사용자라면") { + val shouldThrow1 = shouldThrow { + Message.sendMessage( + "hello", + withDrawUser, + UserFixture.createWithId(3), + "senderName", + false, + ) + } + val shouldThrow2 = shouldThrow { + Message.sendMessage( + "hello", + restrictionUser, + UserFixture.createWithId(3), + "senderName", + false + ) + } + + then("예외가 발생한다.") { + shouldThrow1 shouldHaveMessage "탈퇴한 학생은 해당 서비스를 이용할 수 없습니다." + shouldThrow2 shouldHaveMessage "이용제한을 당한 학생은 해당 서비스를 이용할 수 없습니다." + } + } + } + + given("받은 쪽지를 삭제할 때") { + val restrictionUser = + UserFixture.createUserWithIdAndRestrictionTypeAndRestrictDay( + 1, + listOf(Pair(RestrictionType.PERMANENT_BAN_MESSAGE_REPORT, Long.MAX_VALUE)) + ) + val withDrawUser = UserFixture.createWithId(2).withdraw().completeWithdraw(ProfileFixture.createWithId(1)) + val restrictionUserMessage = MessageFixture.createMessage("Hello", 2, 1, "senderName") + val withDrawUserMessage = MessageFixture.createMessage("Hello", 1, 2, "senderName") + `when`("수신자가 탈퇴 혹은 이용제재를 당한 사용자라면") { + val shouldThrow1 = shouldThrow { + withDrawUserMessage.receivedMessageSoftDelete(restrictionUser) + } + val shouldThrow2 = shouldThrow { + restrictionUserMessage.receivedMessageSoftDelete(withDrawUser) + } + + then("예외가 발생한다.") { + shouldThrow1 shouldHaveMessage "이용제한을 당한 학생은 해당 서비스를 이용할 수 없습니다." + shouldThrow2 shouldHaveMessage "탈퇴한 학생은 해당 서비스를 이용할 수 없습니다." + } + } + } + + given("보낸 쪽지를 삭제할 때") { + val restrictionUser = + UserFixture.createUserWithIdAndRestrictionTypeAndRestrictDay( + 1, + listOf(Pair(RestrictionType.PERMANENT_BAN_MESSAGE_REPORT, Long.MAX_VALUE)) + ) + val withDrawUser = UserFixture.createWithId(2).withdraw().completeWithdraw(ProfileFixture.createWithId(1)) + val restrictionUserMessage = MessageFixture.createMessage("Hello", 2, 1, "senderName") + val withDrawUserMessage = MessageFixture.createMessage("Hello", 1, 2, "senderName") + `when`("송신자가 탈퇴 혹은 이용제재를 당한 사용자라면") { + val shouldThrow1 = shouldThrow { + restrictionUserMessage.sendMessageSoftDelete(restrictionUser) + } + val shouldThrow2 = shouldThrow { + withDrawUserMessage.sendMessageSoftDelete(withDrawUser) + } + + then("예외가 발생한다.") { + shouldThrow1 shouldHaveMessage "이용제한을 당한 학생은 해당 서비스를 이용할 수 없습니다." + shouldThrow2 shouldHaveMessage "탈퇴한 학생은 해당 서비스를 이용할 수 없습니다." + } + } + } + }) diff --git a/app/src/test/kotlin/com/wespot/message/fixture/MessageFixture.kt b/app/src/test/kotlin/com/wespot/message/fixture/MessageFixture.kt index 248edf13..5e52d8fb 100644 --- a/app/src/test/kotlin/com/wespot/message/fixture/MessageFixture.kt +++ b/app/src/test/kotlin/com/wespot/message/fixture/MessageFixture.kt @@ -3,6 +3,7 @@ package com.wespot.message.fixture import com.wespot.message.Message import com.wespot.message.MessageContent import com.wespot.message.MessageType +import com.wespot.user.fixture.UserFixture import java.time.LocalDateTime @@ -89,8 +90,8 @@ object MessageFixture { ): Message { return Message.sendMessage( content = content, - receiverId = receiverId, - senderId = senderId, + receiver = UserFixture.createWithId(receiverId), + sender = UserFixture.createWithId(senderId), senderName = senderName, isAnonymous = false, ) diff --git a/app/src/test/kotlin/com/wespot/message/service/ModifyMessageServiceTest.kt b/app/src/test/kotlin/com/wespot/message/service/ModifyMessageServiceTest.kt index f9a9e710..deba9591 100644 --- a/app/src/test/kotlin/com/wespot/message/service/ModifyMessageServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/message/service/ModifyMessageServiceTest.kt @@ -6,7 +6,6 @@ import com.wespot.message.MessageContent import com.wespot.message.MessageTimeValidator import com.wespot.message.dto.request.UpdateMessageRequest import com.wespot.message.dto.response.UpdateMessageResponse -import com.wespot.message.event.ReadMessageByReceiverEvent import com.wespot.message.fixture.MessageFixture import com.wespot.message.port.out.MessagePort import com.wespot.user.User @@ -18,7 +17,6 @@ import io.mockk.clearAllMocks import io.mockk.every import io.mockk.mockk import io.mockk.verify -import org.springframework.context.ApplicationEventPublisher import java.time.Clock import java.time.Instant import java.time.ZoneId @@ -27,11 +25,9 @@ class ModifyMessageServiceTest : BehaviorSpec({ val messagePort = mockk() val userPort = mockk() - val eventPublisher = mockk() val modifyMessageService = ModifyMessageService( messagePort = messagePort, userPort = userPort, - eventPublisher = eventPublisher ) lateinit var sender: User @@ -99,16 +95,6 @@ class ModifyMessageServiceTest : BehaviorSpec({ every { userPort.findById(1) } returns sender every { messagePort.findById(messageId) } returns receivedMessage every { messagePort.save(any()) } returns receivedMessage.copy(isReceiverRead = true) - every { - eventPublisher.publishEvent( - ReadMessageByReceiverEvent( - sender, - receiver, - messageId, - false - ) - ) - } returns Unit then("메시지가 읽은 상태로 업데이트되어야 한다") { modifyMessageService.readMessage(messageId) diff --git a/app/src/test/kotlin/com/wespot/message/service/SendMessageServiceTest.kt b/app/src/test/kotlin/com/wespot/message/service/SendMessageServiceTest.kt index 8090e460..887d4841 100644 --- a/app/src/test/kotlin/com/wespot/message/service/SendMessageServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/message/service/SendMessageServiceTest.kt @@ -5,8 +5,6 @@ import com.wespot.message.Message import com.wespot.message.MessageTimeValidator import com.wespot.message.dto.request.SendMessageRequest import com.wespot.message.dto.response.SendMessageResponse -import com.wespot.message.event.MessageLimitEvent -import com.wespot.message.event.ReceivedMessageEvent import com.wespot.message.fixture.MessageFixture import com.wespot.message.port.out.MessagePort import com.wespot.user.User @@ -19,7 +17,6 @@ import io.mockk.clearAllMocks import io.mockk.every import io.mockk.mockk import io.mockk.verify -import org.springframework.context.ApplicationEventPublisher import java.time.Clock import java.time.Instant import java.time.ZoneId @@ -29,12 +26,10 @@ class SendMessageServiceTest : BehaviorSpec({ val messagePort = mockk() val userPort = mockk() val blockedUserPort = mockk() - val eventPublisher = mockk() val sendMessageService = SendMessageService( messagePort = messagePort, userPort = userPort, blockedUserPort = blockedUserPort, - eventPublisher = eventPublisher ) lateinit var sender: User @@ -75,8 +70,6 @@ class SendMessageServiceTest : BehaviorSpec({ every { messagePort.save(any()) } returns message every { messagePort.sendMessageCount(sender.id) } returns 0 every { messagePort.hasSentMessageToday(sender.id, receiver.id) } returns false - every { eventPublisher.publishEvent(MessageLimitEvent(sender.id, 0)) } returns Unit - every { eventPublisher.publishEvent(ReceivedMessageEvent(receiver, 0)) } returns Unit every { blockedUserPort.existsByBlockerIdAndBlockedId(1, 2) } returns false every { blockedUserPort.existsByBlockerIdAndBlockedId(2, 1) } returns false diff --git a/app/src/test/kotlin/com/wespot/message/service/real/RealSendMessageServiceTest.kt b/app/src/test/kotlin/com/wespot/message/service/real/RealSendMessageServiceTest.kt index cf4f3ae8..0d9b7cf1 100644 --- a/app/src/test/kotlin/com/wespot/message/service/real/RealSendMessageServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/message/service/real/RealSendMessageServiceTest.kt @@ -38,8 +38,8 @@ class RealSendMessageServiceTest @Autowired constructor( val message = messagePort.save( Message.sendMessage( content = "content", - receiverId = receiver.id, - senderId = sender.id, + receiver = receiver, + sender = sender, senderName = "senderName", isAnonymous = false ) diff --git a/app/src/test/kotlin/com/wespot/notification/service/listener/NotificationEventListenerTest.kt b/app/src/test/kotlin/com/wespot/notification/service/listener/NotificationEventListenerTest.kt index 00ba00bd..59332bd3 100644 --- a/app/src/test/kotlin/com/wespot/notification/service/listener/NotificationEventListenerTest.kt +++ b/app/src/test/kotlin/com/wespot/notification/service/listener/NotificationEventListenerTest.kt @@ -4,7 +4,6 @@ import com.wespot.common.service.ServiceTest import com.wespot.message.Message import com.wespot.message.MessageTimeValidator import com.wespot.message.event.ReceivedMessageEvent -import com.wespot.message.fixture.MessageFixture import com.wespot.message.port.out.MessagePort import com.wespot.notification.NotificationType import com.wespot.notification.port.out.NotificationPort @@ -40,8 +39,8 @@ class NotificationEventListenerTest @Autowired constructor( val message = messagePort.save( Message.sendMessage( content = "content", - receiverId = receiver.id, - senderId = sender.id, + receiver = receiver, + sender = sender, senderName = sender.name, isAnonymous = false ) diff --git a/app/src/test/kotlin/com/wespot/notification/service/listener/VoteNotificationEventListenerTest.kt b/app/src/test/kotlin/com/wespot/notification/service/listener/VoteNotificationEventListenerTest.kt index 15c3fc3c..b4b35c7d 100644 --- a/app/src/test/kotlin/com/wespot/notification/service/listener/VoteNotificationEventListenerTest.kt +++ b/app/src/test/kotlin/com/wespot/notification/service/listener/VoteNotificationEventListenerTest.kt @@ -18,7 +18,6 @@ import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest import java.time.LocalDate import java.time.LocalDateTime import kotlin.test.Test @@ -65,14 +64,14 @@ class VoteNotificationEventListenerTest @Autowired constructor( val notifications = notificationPort.findAll() // then - notifications.size shouldBe 5 - notifications[0].userId shouldBe users[1].id - notifications[1].userId shouldBe users[2].id - notifications[2].userId shouldBe users[3].id - notifications[3].userId shouldBe users[4].id - notifications[0].type shouldBe NotificationType.VOTE_RESULT - notifications[0].targetId shouldBe 0 - notifications[0].date shouldBe LocalDate.now() + notifications.size shouldBe 10 + notifications[5].userId shouldBe users[1].id + notifications[6].userId shouldBe users[2].id + notifications[7].userId shouldBe users[3].id + notifications[8].userId shouldBe users[4].id + notifications[5].type shouldBe NotificationType.VOTE_RESULT + notifications[5].targetId shouldBe 0 + notifications[5].date shouldBe LocalDate.now() } @Test diff --git a/app/src/test/kotlin/com/wespot/user/fixture/UserFixture.kt b/app/src/test/kotlin/com/wespot/user/fixture/UserFixture.kt index 4cb9d7f8..25760d0c 100644 --- a/app/src/test/kotlin/com/wespot/user/fixture/UserFixture.kt +++ b/app/src/test/kotlin/com/wespot/user/fixture/UserFixture.kt @@ -1,7 +1,6 @@ package com.wespot.user.fixture import com.wespot.auth.PrincipalDetails -import com.wespot.auth.dto.request.ProfileRequest import com.wespot.user.restriction.Restriction import com.wespot.user.Role import com.wespot.user.Setting @@ -392,4 +391,94 @@ object UserFixture { ) } + fun createUserWithNameAndEmailAndRestrictionTypeAndRestrictDayAndSchoolId( + name: String, + email: String, + restrictions: List>, + schoolId: Long, + ): User { + var restriction = Restriction.createInitialState() + for (eachRestriction in restrictions) { + restriction = restriction.addRestrict(eachRestriction.first, eachRestriction.second) + } + return User( + id = 0, + email = email, + password = "TestPassword", + role = Role.USER, + name = name, + introduction = UserIntroduction.from("hello"), + gender = Gender.MALE, + schoolId = schoolId, + grade = 1, + classNumber = 1, + setting = Setting(), + profile = Profile(0, "black", "image.png"), + fcm = FCM(0, "token", LocalDateTime.now()), + social = Social( + socialType = SocialType.KAKAO, + socialId = "1123123", + socialEmail = null, + socialRefreshToken = "refreshToken" + ), + userConsent = UserConsent( + id = 0, + consentType = ConsentType.MARKETING, + consentValue = true, + consentedAt = LocalDateTime.now() + ), + restriction = restriction, + createdAt = LocalDateTime.now(), + updatedAt = LocalDateTime.now(), + withdrawalStatus = WithdrawalStatus.NONE, + withdrawalRequestAt = null, + withdrawalCancelAt = null, + withdrawalCompleteAt = null + ) + } + + fun createUserWithIdAndRestrictionTypeAndRestrictDay( + id: Long, + restrictions: List> + ): User { + var restriction = Restriction.createInitialState() + for (eachRestriction in restrictions) { + restriction = restriction.addRestrict(eachRestriction.first, eachRestriction.second) + } + return User( + id = id, + email = "TestEmail@Kakako", + password = "TestPassword", + role = Role.USER, + name = "TestUser", + introduction = UserIntroduction.from("hello"), + gender = Gender.MALE, + schoolId = 1L, + grade = 1, + classNumber = 1, + setting = Setting(), + profile = Profile(0, "black", "image.png"), + fcm = FCM(0, "token", LocalDateTime.now()), + social = Social( + socialType = SocialType.KAKAO, + socialId = "1123123", + socialEmail = null, + socialRefreshToken = "refreshToken" + ), + userConsent = UserConsent( + id = 0, + consentType = ConsentType.MARKETING, + consentValue = true, + consentedAt = LocalDateTime.now() + ), + restriction = restriction, + createdAt = LocalDateTime.now(), + updatedAt = LocalDateTime.now(), + withdrawalStatus = WithdrawalStatus.NONE, + withdrawalRequestAt = null, + withdrawalCancelAt = null, + withdrawalCompleteAt = null + ) + } + } diff --git a/app/src/test/kotlin/com/wespot/user/infrastructure/mysql/UserJpaRepositoryTest.kt b/app/src/test/kotlin/com/wespot/user/infrastructure/mysql/UserJpaRepositoryTest.kt new file mode 100644 index 00000000..6c682d59 --- /dev/null +++ b/app/src/test/kotlin/com/wespot/user/infrastructure/mysql/UserJpaRepositoryTest.kt @@ -0,0 +1,135 @@ +package com.wespot.user.infrastructure.mysql + +import com.wespot.common.service.ServiceTest +import com.wespot.school.SchoolJpaRepository +import com.wespot.school.SchoolMapper +import com.wespot.school.fixture.SchoolFixture +import com.wespot.user.RestrictionType +import com.wespot.user.fixture.ProfileFixture +import com.wespot.user.fixture.UserFixture +import com.wespot.user.port.out.UserPort +import com.wespot.user.repository.UserJpaRepository +import io.kotest.matchers.shouldBe +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.PageRequest +import kotlin.test.Test + +class UserJpaRepositoryTest @Autowired constructor( + private val userPort: UserPort, + private val userJpaRepository: UserJpaRepository, + private val schoolJpaRepository: SchoolJpaRepository +) : ServiceTest() { + + @Test + fun `친구를 검색할 때, 탈퇴 및 이용제재에 걸려있는 친구와 본인은 조회하지 않는다`() { + // given + val school = SchoolFixture.createWithId(0) + val savedSchool = schoolJpaRepository.save(SchoolMapper.mapToJpaEntity(school)) + val user1 = userPort.save( + UserFixture.createUser( + 0, + "hello@kakao", + "hello", + savedSchool.id, + 0 + ) + ) + val user2 = userPort.save( + UserFixture.createUser( + 0, + "hello4@kakao", + "hello4", + savedSchool.id, + 0 + ) + ) + val restrictionUser = userPort.save( + UserFixture.createUserWithNameAndEmailAndRestrictionTypeAndRestrictDayAndSchoolId( + "hell", + "hello1@kakao", + listOf(Pair(RestrictionType.TEMPORARY_BAN_MESSAGE_REPORT, 30)), + savedSchool.id + ) + ) + val withDrawUser = userPort.save( + UserFixture.createUser( + 0, + "hello2@kakao", + "helloo", + savedSchool.id, + 0 + ).withdraw().completeWithdraw(ProfileFixture.createWithId(0)) + ) + + // when + val searchUsers = userJpaRepository.searchUsers( + "he", + "hello", + "Test School", + 2, + 0, + user1.id, + PageRequest.of(0, 10), + ) + + // then + searchUsers.size shouldBe 1 + searchUsers[0].id shouldBe user2.id + } + + @Test + fun `탈퇴 및 이용제재가 아닌 유저만 반 친구로 조회한다`() { + // given + val school = SchoolFixture.createWithId(0) + val savedSchool = schoolJpaRepository.save(SchoolMapper.mapToJpaEntity(school)) + val user1 = userPort.save( + UserFixture.createUser( + 0, + "hello@kakao", + "hello", + savedSchool.id, + 0 + ) + ) + UserFixture.setSecurityContextUser(user1) + val user2 = userPort.save( + UserFixture.createUser( + 0, + "hello4@kakao", + "hello4", + savedSchool.id, + 0 + ) + ) + val restrictionUser = userPort.save( + UserFixture.createUserWithNameAndEmailAndRestrictionTypeAndRestrictDayAndSchoolId( + "hell", + "hello1@kakao", + listOf(Pair(RestrictionType.TEMPORARY_BAN_MESSAGE_REPORT, 30)), + savedSchool.id + ) + ) + val withDrawUser = userPort.save( + UserFixture.createUser( + 0, + "hello1@kakao", + "helloo", + savedSchool.id, + 0 + ).withdraw().completeWithdraw(ProfileFixture.createWithId(0)) + ) + + // when + val classmateWithoutRegulationUser = userJpaRepository.findAllBySchoolIdAndGradeAndClassNumber( + savedSchool.id, + 1, + 1 + ) + + // then + classmateWithoutRegulationUser.size shouldBe 2 + classmateWithoutRegulationUser[0].id shouldBe user1.id + classmateWithoutRegulationUser[1].id shouldBe user2.id + } + +} diff --git a/app/src/test/kotlin/com/wespot/user/service/SearchServiceTest.kt b/app/src/test/kotlin/com/wespot/user/service/SearchServiceTest.kt index 30211fa6..bb7a63bf 100644 --- a/app/src/test/kotlin/com/wespot/user/service/SearchServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/user/service/SearchServiceTest.kt @@ -1,5 +1,6 @@ package com.wespot.user.service +import com.wespot.auth.service.SecurityUtils import com.wespot.school.SchoolType import com.wespot.school.fixture.SchoolFixture import com.wespot.school.port.out.SchoolPort @@ -9,6 +10,8 @@ import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkStatic import io.mockk.verify import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Sort @@ -34,9 +37,12 @@ class SearchServiceTest : BehaviorSpec({ val school1 = SchoolFixture.createSchool(1L, "서울고등학교", SchoolType.HIGH, "서울", "서울시 강남구") val school2 = SchoolFixture.createSchool(2L, "부산고등학교", SchoolType.HIGH, "부산", "부산시 남구") val school3 = SchoolFixture.createSchool(3L, "광주고등학교", SchoolType.HIGH, "광주", "광주시 서구") + val loginUser = UserFixture.createWithId(1L) - every { userPort.searchUsers(keyword, null, null, null, null, pageable) } returns users - every { userPort.countUsersAfterCursor(keyword, null, null, null, null) } returns 0L + mockkStatic(SecurityUtils::class) + every { SecurityUtils.getLoginUser(userPort) } returns loginUser + every { userPort.searchUsers(keyword, null, null, null, null, pageable, loginUser.id) } returns users + every { userPort.countUsersAfterCursor(keyword, null, null, null, null, loginUser.id) } returns 0L every { schoolPort.findById(1L) } returns school1 every { schoolPort.findById(2L) } returns school2 every { schoolPort.findById(3L) } returns school3 @@ -44,10 +50,12 @@ class SearchServiceTest : BehaviorSpec({ val result = searchUserService.searchUsers(keyword, cursorId) then("첫 페이지의 사용자들을 반환한다") { - verify { userPort.searchUsers(keyword, null, null, null, null, pageable) } + verify { userPort.searchUsers(keyword, null, null, null, null, pageable, loginUser.id) } result.users.size shouldBe 3 result.hasNext shouldBe false } + + unmockkStatic(SecurityUtils::class) } } @@ -62,21 +70,26 @@ class SearchServiceTest : BehaviorSpec({ UserFixture.createUser(2L, "user2@example.com", "김경식", 2L), UserFixture.createUser(3L, "user3@example.com", "김경수", 3L) ) + val loginUser = UserFixture.createWithId(1L) + mockkStatic(SecurityUtils::class) + every { SecurityUtils.getLoginUser(userPort) } returns loginUser every { userPort.findById(cursorId) } returns cursorUser - every { userPort.countUsersAfterCursor("경", "김갑수", "서울고등학교", 2, 1) } returns 0L + every { userPort.countUsersAfterCursor("경", "김갑수", "서울고등학교", 2, 1, loginUser.id) } returns 0L every { schoolPort.findById(1L) } returns school - every { userPort.searchUsers(keyword, "김갑수", "서울고등학교", 2, cursorId, pageable) } returns users + every { userPort.searchUsers(keyword, "김갑수", "서울고등학교", 2, cursorId, pageable, loginUser.id) } returns users val result = searchUserService.searchUsers(keyword, cursorId) then("커서 기반의 사용자들을 반환한다") { verify { userPort.findById(cursorId) } verify { schoolPort.findById(1L) } - verify { userPort.searchUsers(keyword, "김갑수", "서울고등학교", 2, cursorId, pageable) } + verify { userPort.searchUsers(keyword, "김갑수", "서울고등학교", 2, cursorId, pageable, loginUser.id) } result.users.size shouldBe 2 result.hasNext shouldBe false } + + unmockkStatic(SecurityUtils::class) } } @@ -90,21 +103,26 @@ class SearchServiceTest : BehaviorSpec({ val users = listOf( UserFixture.createUser(3L, "user3@example.com", "김경수", 3L) ) + val loginUser = UserFixture.createWithId(1L) - every { userPort.countUsersAfterCursor("경", "김경식", "부산고등학교", 2, 2) } returns 0L + mockkStatic(SecurityUtils::class) + every { SecurityUtils.getLoginUser(userPort) } returns loginUser + every { userPort.countUsersAfterCursor("경", "김경식", "부산고등학교", 2, 2, loginUser.id) } returns 0L every { userPort.findById(cursorId) } returns cursorUser every { schoolPort.findById(2L) } returns school - every { userPort.searchUsers(keyword, "김경식", "부산고등학교", 2, cursorId, pageable) } returns users + every { userPort.searchUsers(keyword, "김경식", "부산고등학교", 2, cursorId, pageable, loginUser.id) } returns users val result = searchUserService.searchUsers(keyword, cursorId) then("다음 페이지의 사용자들을 반환한다") { verify { userPort.findById(cursorId) } verify { schoolPort.findById(2L) } - verify { userPort.searchUsers(keyword, "김경식", "부산고등학교", 2, cursorId, pageable) } + verify { userPort.searchUsers(keyword, "김경식", "부산고등학교", 2, cursorId, pageable, loginUser.id) } result.users.size shouldBe 1 result.hasNext shouldBe false } + + unmockkStatic(SecurityUtils::class) } } @@ -122,8 +140,11 @@ class SearchServiceTest : BehaviorSpec({ val school1 = SchoolFixture.createSchool(1L, "서울고등학교", SchoolType.HIGH, "서울", "서울시 강남구") val school2 = SchoolFixture.createSchool(2L, "부산고등학교", SchoolType.HIGH, "부산", "부산시 남구") val school3 = SchoolFixture.createSchool(3L, "광주고등학교", SchoolType.HIGH, "광주", "광주시 서구") + val loginUser = UserFixture.createWithId(1L) - every { userPort.searchUsers(keyword, null, null, null, null, pageable) } returns users + mockkStatic(SecurityUtils::class) + every { SecurityUtils.getLoginUser(userPort) } returns loginUser + every { userPort.searchUsers(keyword, null, null, null, null, pageable, loginUser.id) } returns users every { schoolPort.findById(1L) } returns school1 every { schoolPort.findById(2L) } returns school2 every { schoolPort.findById(3L) } returns school3 @@ -131,7 +152,7 @@ class SearchServiceTest : BehaviorSpec({ val result = searchUserService.searchUsers(keyword, cursorId) then("정렬된 사용자들을 반환한다") { - verify { userPort.searchUsers(keyword, null, null, null, null, pageable) } + verify { userPort.searchUsers(keyword, null, null, null, null, pageable, loginUser.id) } result.users.size shouldBe 3 result.hasNext shouldBe false @@ -139,6 +160,8 @@ class SearchServiceTest : BehaviorSpec({ result.users[1].name shouldBe "김경수" result.users[2].name shouldBe "김갑수" } + + unmockkStatic(SecurityUtils::class) } } }) diff --git a/app/src/test/kotlin/com/wespot/user/service/SearchUserServiceTest.kt b/app/src/test/kotlin/com/wespot/user/service/SearchUserServiceTest.kt new file mode 100644 index 00000000..400809c5 --- /dev/null +++ b/app/src/test/kotlin/com/wespot/user/service/SearchUserServiceTest.kt @@ -0,0 +1,122 @@ +package com.wespot.user.service + +import com.wespot.common.service.ServiceTest +import com.wespot.exception.CustomException +import com.wespot.school.SchoolJpaRepository +import com.wespot.school.SchoolMapper +import com.wespot.school.fixture.SchoolFixture +import com.wespot.user.RestrictionType +import com.wespot.user.fixture.ProfileFixture +import com.wespot.user.fixture.UserFixture +import com.wespot.user.port.out.UserPort +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.kotest.matchers.throwable.shouldHaveMessage +import org.springframework.beans.factory.annotation.Autowired +import kotlin.test.Test + +class SearchUserServiceTest @Autowired constructor( + private val searchUserService: SearchUserService, + private val schoolJpaRepository: SchoolJpaRepository, + private val userPort: UserPort, +) : ServiceTest() { + + @Test + fun `탈퇴 및 제재를 당한 유저가 검색을 하는 경우 예외가 발생한다`() { + // given + val school = SchoolFixture.createWithId(0) + val savedSchool = schoolJpaRepository.save(SchoolMapper.mapToJpaEntity(school)) + val restrictionUser = userPort.save( + UserFixture.createUserWithNameAndEmailAndRestrictionTypeAndRestrictDayAndSchoolId( + "hell", + "hello1@kakao", + listOf(Pair(RestrictionType.TEMPORARY_BAN_MESSAGE_REPORT, 30)), + savedSchool.id + ) + ) + val withDrawUser = userPort.save( + UserFixture.createUser( + 0, + "hello2@kakao", + "helloo", + savedSchool.id, + 0 + ).withdraw().completeWithdraw(ProfileFixture.createWithId(0)) + ) + + // when + UserFixture.setSecurityContextUser(restrictionUser) + val shouldThrow1 = shouldThrow { + searchUserService.searchUsers( + "he", + 0 + ) + } + UserFixture.setSecurityContextUser(withDrawUser) + val shouldThrow2 = shouldThrow { + searchUserService.searchUsers( + "he", + 0 + ) + } + + // then + shouldThrow1 shouldHaveMessage "규제를 당한 유저는 해당 서비스를 사용할 수 없습니다." + shouldThrow2 shouldHaveMessage "규제를 당한 유저는 해당 서비스를 사용할 수 없습니다." + } + + @Test + fun `탈퇴 및 제재를 당하지 않은 유저가 검색을 하는 경우 예외가 발생하지 않는다`() { + // given + val school = SchoolFixture.createWithId(0) + val savedSchool = schoolJpaRepository.save(SchoolMapper.mapToJpaEntity(school)) + val user1 = userPort.save( + UserFixture.createUser( + 0, + "hello@kakao", + "hello", + savedSchool.id, + 0 + ) + ) + val user2 = userPort.save( + UserFixture.createUser( + 0, + "hello2@kakao", + "hello2", + savedSchool.id, + 0 + ) + ) + val restrictionUser = userPort.save( + UserFixture.createUserWithNameAndEmailAndRestrictionTypeAndRestrictDayAndSchoolId( + "hell", + "hello1@kakao", + listOf(Pair(RestrictionType.TEMPORARY_BAN_MESSAGE_REPORT, 30)), + savedSchool.id + ) + ) + val withDrawUser = userPort.save( + UserFixture.createUser( + 0, + "hello2@kakao", + "helloo", + savedSchool.id, + 0 + ).withdraw().completeWithdraw(ProfileFixture.createWithId(0)) + ) + + // when + UserFixture.setSecurityContextUser(user1) + val searchUsers = searchUserService.searchUsers( + "he", + 0 + ) + + // then + searchUsers.users.size shouldBe 1 + searchUsers.hasNext shouldBe false + searchUsers.users[0].id shouldBe user2.id + } + +} diff --git a/app/src/test/kotlin/com/wespot/vote/domain/VoteTest.kt b/app/src/test/kotlin/com/wespot/vote/domain/VoteTest.kt index 4a51a525..cc47ca73 100644 --- a/app/src/test/kotlin/com/wespot/vote/domain/VoteTest.kt +++ b/app/src/test/kotlin/com/wespot/vote/domain/VoteTest.kt @@ -1,7 +1,9 @@ package com.wespot.vote.domain import com.wespot.exception.CustomException +import com.wespot.user.RestrictionType import com.wespot.user.User +import com.wespot.user.fixture.ProfileFixture import com.wespot.user.fixture.UserFixture import com.wespot.vote.RankCalculateService import com.wespot.vote.ReceivedVoteCalculateService @@ -98,6 +100,68 @@ class VoteTest() : BehaviorSpec({ } } + `when`("투표를 진행할 때, 송신자가 탈퇴 및 이용제재를 당한 상태라면") { + val vote = Vote.of(voteIdentifier, voteOptions, null) + val restrictionUser = + UserFixture.createUserWithIdAndRestrictionTypeAndRestrictDay( + 1, + listOf(Pair(RestrictionType.PERMANENT_BAN_MESSAGE_REPORT, Long.MAX_VALUE)) + ) + val withDrawUser = UserFixture.createWithId(2).withdraw().completeWithdraw(ProfileFixture.createWithId(1)) + val shouldThrow1 = shouldThrow { + vote.addBallot( + 1, + restrictionUser, + UserFixture.createWithId(3), + LocalDateTime.now() + ) + } + val shouldThrow2 = shouldThrow { + vote.addBallot( + 1, + withDrawUser, + UserFixture.createWithId(3), + LocalDateTime.now() + ) + } + + then("정상적으로 투표가 진행된다.") { + shouldThrow1 shouldHaveMessage "이용제한을 당한 학생은 해당 서비스를 이용할 수 없습니다." + shouldThrow2 shouldHaveMessage "탈퇴한 학생은 해당 서비스를 이용할 수 없습니다." + } + } + + `when`("투표를 진행할 때, 수신자가 탈퇴 및 이용제재를 당한 상태라면") { + val vote = Vote.of(voteIdentifier, voteOptions, null) + val restrictionUser = + UserFixture.createUserWithIdAndRestrictionTypeAndRestrictDay( + 1, + listOf(Pair(RestrictionType.PERMANENT_BAN_MESSAGE_REPORT, Long.MAX_VALUE)) + ) + val withDrawUser = UserFixture.createWithId(2).withdraw().completeWithdraw(ProfileFixture.createWithId(1)) + val shouldThrow1 = shouldThrow { + vote.addBallot( + 1, + UserFixture.createWithId(3), + restrictionUser, + LocalDateTime.now() + ) + } + val shouldThrow2 = shouldThrow { + vote.addBallot( + 1, + UserFixture.createWithId(3), + withDrawUser, + LocalDateTime.now() + ) + } + then("예외가 발생한다.") { + shouldThrow1 shouldHaveMessage "이용제한을 당한 학생은 해당 서비스를 이용할 수 없습니다." + shouldThrow2 shouldHaveMessage "탈퇴한 학생은 해당 서비스를 이용할 수 없습니다." + } + } + + `when`("중복되지 않은 투표를 하는 경우") { val vote = Vote.of(voteIdentifier, voteOptions, null) val users = listOf( @@ -171,6 +235,24 @@ class VoteTest() : BehaviorSpec({ } } + `when`("투표할 친구를 찾는 과정에서 탈퇴 및 제재를 당한 유저가 있다면") { + val users = createUserByCount(3).toMutableList() + users.add(UserFixture.createWithId(4).withdraw().completeWithdraw(ProfileFixture.createWithId(1))) + users.add( + UserFixture.createUserWithIdAndRestrictionTypeAndRestrictDay( + 5, + listOf(Pair(RestrictionType.PERMANENT_BAN_MESSAGE_REPORT, Long.MAX_VALUE)) + ) + ) + val vote = VoteFixture.createWithVoteNumberAndBallots(0, ballots) + val me = users[0] + val voteUsers = vote.findUsersForVote(users, me) + then("제외시킨다.") { + voteUsers.size shouldBe 1 + voteUsers.find { it.id == 3L } shouldNotBe null + } + } + } given("투표 결과를 통해") { @@ -622,8 +704,8 @@ class VoteTest() : BehaviorSpec({ shouldThrow { vote.findUsersForVote(classmates, user) } then("예외가 발생한다.") { - shouldThrow1 shouldHaveMessage "다른 반의 학생이(을) 투표할 수 없습니다." - shouldThrow2 shouldHaveMessage "다른 반의 학생이(을) 투표할 수 없습니다." + shouldThrow1 shouldHaveMessage "다른 반 학생과 상호작용 할 수 없습니다." + shouldThrow2 shouldHaveMessage "다른 반 학생과 상호작용 할 수 없습니다." } } } @@ -640,8 +722,8 @@ class VoteTest() : BehaviorSpec({ val shouldThrow2 = shouldThrow { vote.addBallot(1, otherClassmate, user, LocalDateTime.now()) } then("예외가 발생한다.") { - shouldThrow1 shouldHaveMessage "다른 반의 학생이(을) 투표할 수 없습니다." - shouldThrow2 shouldHaveMessage "다른 반의 학생이(을) 투표할 수 없습니다." + shouldThrow1 shouldHaveMessage "다른 반 학생과 상호작용 할 수 없습니다." + shouldThrow2 shouldHaveMessage "다른 반 학생과 상호작용 할 수 없습니다." } } } diff --git a/app/src/test/kotlin/com/wespot/vote/service/SavedVoteServiceTest.kt b/app/src/test/kotlin/com/wespot/vote/service/SavedVoteServiceTest.kt index d5ebd390..9fd3e7ac 100644 --- a/app/src/test/kotlin/com/wespot/vote/service/SavedVoteServiceTest.kt +++ b/app/src/test/kotlin/com/wespot/vote/service/SavedVoteServiceTest.kt @@ -1,6 +1,5 @@ package com.wespot.vote.service -import com.wespot.DatabaseCleanup import com.wespot.common.service.ServiceTest import com.wespot.exception.CustomException import com.wespot.notification.port.out.NotificationPort @@ -93,7 +92,7 @@ class SavedVoteServiceTest @Autowired constructor( // then val shouldThrow = shouldThrow(throwingCallable) - shouldThrow shouldHaveMessage "투표하고자 하는 회원이 존재하지 않습니다." + shouldThrow shouldHaveMessage "투표 대상을 찾을 수 없습니다." } @Test diff --git a/common/src/main/kotlin/com/wespot/EventUtils.kt b/common/src/main/kotlin/com/wespot/EventUtils.kt new file mode 100644 index 00000000..f9af6a47 --- /dev/null +++ b/common/src/main/kotlin/com/wespot/EventUtils.kt @@ -0,0 +1,26 @@ +package com.wespot + +import org.springframework.context.ApplicationEventPublisher +import org.springframework.stereotype.Component + +@Component +class EventUtils private constructor(applicationEventPublisher: ApplicationEventPublisher) { + + init { + Companion.applicationEventPublisher = applicationEventPublisher + } + + companion object { + + private var applicationEventPublisher: ApplicationEventPublisher? = null + + fun publish(event: Any) { + if (applicationEventPublisher == null) { + return + } + applicationEventPublisher!!.publishEvent(event) + } + + } + +} diff --git a/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt b/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt index dbb0acfe..e27579df 100644 --- a/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt +++ b/core/src/main/kotlin/com/wespot/auth/service/AuthService.kt @@ -1,5 +1,6 @@ package com.wespot.auth.service +import com.wespot.EventUtils import com.wespot.auth.dto.AuthData import com.wespot.auth.dto.request.* import com.wespot.auth.dto.response.SettingResponse @@ -25,7 +26,6 @@ import com.wespot.user.port.out.UserConsentPort import com.wespot.user.port.out.UserPort import com.wespot.user.port.out.FCMPort import org.springframework.beans.factory.annotation.Value -import org.springframework.context.ApplicationEventPublisher import org.springframework.http.HttpStatus import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.crypto.password.PasswordEncoder @@ -50,7 +50,6 @@ class AuthService( private val passwordEncoder: PasswordEncoder, private val refreshTokenService: RefreshTokenService, private val restrictionPort: RestrictionPort, - private val eventPublisher: ApplicationEventPublisher, private val fcmPort: FCMPort, private val personalInfoPort: PersonalInfoPort, @@ -98,15 +97,14 @@ class AuthService( } - override fun signUp(signUpRequest: SignUpRequest): TokenAndUserDetailResponse { val signUpToken = checkSignUpToken(signUpRequest.signUpToken) val user = createUser(signUpToken, signUpRequest) val savedUser = userPort.save(user) - eventPublisher.publishEvent(CreatedVoteEvent(savedUser)) - eventPublisher.publishEvent(SignUpUserEvent(savedUser)) - eventPublisher.publishEvent(WelcomeMessageEvent(savedUser)) + EventUtils.publish(CreatedVoteEvent(savedUser)) + EventUtils.publish(SignUpUserEvent(savedUser)) + EventUtils.publish(WelcomeMessageEvent(savedUser)) saveRelatedEntities(savedUser, signUpRequest, signUpToken.fcmToken) @@ -237,8 +235,10 @@ class AuthService( personalInfo?.let { restrictionPort.findById(it.restriction)?.let { restriction -> - val isPermBanMessage = restriction.messageRestriction.restrictionType == RestrictionType.PERMANENT_BAN_MESSAGE_REPORT - val isPermBanVote = restriction.voteRestriction.restrictionType == RestrictionType.PERMANENT_BAN_VOTE_REPORT + val isPermBanMessage = + restriction.messageRestriction.restrictionType == RestrictionType.PERMANENT_BAN_MESSAGE_REPORT + val isPermBanVote = + restriction.voteRestriction.restrictionType == RestrictionType.PERMANENT_BAN_VOTE_REPORT require(!(isPermBanMessage || isPermBanVote)) { "영구 제한된 계정입니다." } } diff --git a/core/src/main/kotlin/com/wespot/message/service/ModifyMessageService.kt b/core/src/main/kotlin/com/wespot/message/service/ModifyMessageService.kt index ac8e4cc2..366d4b71 100644 --- a/core/src/main/kotlin/com/wespot/message/service/ModifyMessageService.kt +++ b/core/src/main/kotlin/com/wespot/message/service/ModifyMessageService.kt @@ -1,5 +1,6 @@ package com.wespot.message.service +import com.wespot.EventUtils import com.wespot.auth.service.SecurityUtils.getLoginUser import com.wespot.message.dto.request.UpdateMessageRequest import com.wespot.message.dto.response.UpdateMessageResponse @@ -9,7 +10,6 @@ import com.wespot.message.port.out.MessagePort import com.wespot.message.service.MessageFinder.findMessageById import com.wespot.message.service.MessageFinder.findUserById import com.wespot.user.port.out.UserPort -import org.springframework.context.ApplicationEventPublisher import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -18,7 +18,6 @@ import org.springframework.transaction.annotation.Transactional class ModifyMessageService( private val messagePort: MessagePort, private val userPort: UserPort, - private val eventPublisher: ApplicationEventPublisher ) : ModifyMessageUseCase { override fun updateMessage( @@ -49,7 +48,7 @@ class ModifyMessageService( val readMessage = message.readMessage(loginUser) messagePort.save(readMessage) - eventPublisher.publishEvent( + EventUtils.publish( ReadMessageByReceiverEvent( sender, loginUser, diff --git a/core/src/main/kotlin/com/wespot/message/service/ScheduledMessageSenderService.kt b/core/src/main/kotlin/com/wespot/message/service/ScheduledMessageSenderService.kt index 028ca484..c2717bc8 100644 --- a/core/src/main/kotlin/com/wespot/message/service/ScheduledMessageSenderService.kt +++ b/core/src/main/kotlin/com/wespot/message/service/ScheduledMessageSenderService.kt @@ -1,5 +1,6 @@ package com.wespot.message.service +import com.wespot.EventUtils import com.wespot.exception.CustomException import com.wespot.exception.ExceptionView import com.wespot.message.Message @@ -8,7 +9,6 @@ import com.wespot.message.port.`in`.SchedulerMessageUseCase import com.wespot.message.port.out.MessagePort import com.wespot.user.port.out.UserPort import com.wespot.user.service.UserFinder -import org.springframework.context.ApplicationEventPublisher import org.springframework.http.HttpStatus import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Propagation @@ -20,7 +20,6 @@ import java.time.LocalDateTime class ScheduledMessageSenderService( private val messagePort: MessagePort, private val userPort: UserPort, - private val eventPublisher: ApplicationEventPublisher, ) : SchedulerMessageUseCase { @Transactional @@ -43,7 +42,7 @@ class ScheduledMessageSenderService( id = receivedMessage.receiverId, userPort = userPort ) - eventPublisher.publishEvent( + EventUtils.publish( ReceivedMessageEvent( receiver = receiver, messageId = receivedMessage.id diff --git a/core/src/main/kotlin/com/wespot/message/service/SendMessageService.kt b/core/src/main/kotlin/com/wespot/message/service/SendMessageService.kt index 6ee61c39..ba18c678 100644 --- a/core/src/main/kotlin/com/wespot/message/service/SendMessageService.kt +++ b/core/src/main/kotlin/com/wespot/message/service/SendMessageService.kt @@ -1,5 +1,6 @@ package com.wespot.message.service +import com.wespot.EventUtils import com.wespot.auth.service.SecurityUtils.getLoginUser import com.wespot.message.Message import com.wespot.message.MessageTimeValidator.validateMessageSendTime @@ -14,7 +15,6 @@ import com.wespot.message.service.MessageSendValidator.validateSendMessageLimit import com.wespot.message.service.MessageSendValidator.validateUserBlockStatus import com.wespot.user.port.out.BlockedUserPort import com.wespot.user.port.out.UserPort -import org.springframework.context.ApplicationEventPublisher import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -24,7 +24,6 @@ class SendMessageService( private val messagePort: MessagePort, private val userPort: UserPort, private val blockedUserPort: BlockedUserPort, - private val eventPublisher: ApplicationEventPublisher ) : SendMessageUseCase { override fun send(sendMessageRequest: SendMessageRequest): SendMessageResponse { @@ -39,14 +38,14 @@ class SendMessageService( val sendMessage = Message.sendMessage( content = sendMessageRequest.content, - receiverId = receiver.id, - senderId = loginUser.id, + receiver = receiver, + sender = loginUser, senderName = sendMessageRequest.senderName, isAnonymous = sendMessageRequest.isAnonymous ) val saveMessage = messagePort.save(sendMessage) - eventPublisher.publishEvent( + EventUtils.publish( MessageLimitEvent( senderId = loginUser.id, messagePort.sendMessageCount(loginUser.id) diff --git a/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt b/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt index 31b8eb67..104ed650 100644 --- a/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt +++ b/core/src/main/kotlin/com/wespot/user/port/out/UserPort.kt @@ -21,7 +21,7 @@ interface UserPort { classNumber: Int ): List - fun findIdsByIdIn(ids: List): List + fun findByIdIn(ids: List): List fun findByEmail(userEmail: String): User? @@ -33,7 +33,8 @@ interface UserPort { cursorSchoolName: String?, cursorSchoolTypeOrder: Int?, cursorId: Long?, - pageable: Pageable + pageable: Pageable, + loginUserId: Long, ): List fun findAll(): List @@ -43,7 +44,8 @@ interface UserPort { cursorName: String?, cursorSchoolName: String?, cursorSchoolTypeOrder: Int?, - cursorId: Long? + cursorId: Long?, + loginUserId: Long, ): Long fun countBySchoolIdAndGradeAndClassNumber( diff --git a/core/src/main/kotlin/com/wespot/user/service/SearchUserService.kt b/core/src/main/kotlin/com/wespot/user/service/SearchUserService.kt index 0e66c51d..afbb31ee 100644 --- a/core/src/main/kotlin/com/wespot/user/service/SearchUserService.kt +++ b/core/src/main/kotlin/com/wespot/user/service/SearchUserService.kt @@ -1,5 +1,6 @@ package com.wespot.user.service +import com.wespot.auth.service.SecurityUtils import com.wespot.exception.CustomException import com.wespot.exception.ExceptionView import com.wespot.school.School @@ -27,10 +28,12 @@ class SearchUserService( keyword: String, cursorId: Long ): UserListResponse { + val loginUser = SecurityUtils.getLoginUser(userPort) + validateLoginUserRegulation(loginUser) val pageable = PageRequest.of(0, 10, Sort.by("id")) if (cursorId == 0L) { - return fetchFirstPage(keyword = keyword, pageable = pageable) + return fetchFirstPage(keyword = keyword, pageable = pageable, loginUserId = loginUser.id) } val cursorData = fetchCursorData(cursorId) @@ -40,7 +43,8 @@ class SearchUserService( cursorSchoolName = cursorData.cursorSchoolName, cursorSchoolTypeOrder = cursorData.cursorSchoolTypeOrder, cursorId = cursorId, - pageable = pageable + pageable = pageable, + loginUserId = loginUser.id ) val totalCount = userPort.countUsersAfterCursor( @@ -48,15 +52,23 @@ class SearchUserService( cursorName = cursorData.cursorName, cursorSchoolName = cursorData.cursorSchoolName, cursorSchoolTypeOrder = cursorData.cursorSchoolTypeOrder, - cursorId = cursorId + cursorId = cursorId, + loginUserId = loginUser.id ) return buildUserListResponse(users = users, pageable = pageable, totalCount = totalCount) } + private fun validateLoginUserRegulation(loginUser: User) { + if (loginUser.isRegulation()) { + throw CustomException(HttpStatus.FORBIDDEN, ExceptionView.TOAST, "규제를 당한 유저는 해당 서비스를 사용할 수 없습니다.") + } + } + private fun fetchFirstPage( keyword: String, - pageable: Pageable + pageable: Pageable, + loginUserId: Long, ): UserListResponse { val users = userPort.searchUsers( name = keyword, @@ -64,7 +76,8 @@ class SearchUserService( cursorSchoolName = null, cursorSchoolTypeOrder = null, cursorId = null, - pageable = pageable + pageable = pageable, + loginUserId = loginUserId ) val totalCount = userPort.countUsersAfterCursor( @@ -72,7 +85,8 @@ class SearchUserService( cursorName = null, cursorSchoolName = null, cursorSchoolTypeOrder = null, - cursorId = null + cursorId = null, + loginUserId = loginUserId ) return buildUserListResponse(users = users, pageable = pageable, totalCount = totalCount) diff --git a/core/src/main/kotlin/com/wespot/vote/dto/response/SaveVoteResponse.kt b/core/src/main/kotlin/com/wespot/vote/dto/response/SavedVoteResponse.kt similarity index 65% rename from core/src/main/kotlin/com/wespot/vote/dto/response/SaveVoteResponse.kt rename to core/src/main/kotlin/com/wespot/vote/dto/response/SavedVoteResponse.kt index d8c7f932..4c7aa4be 100644 --- a/core/src/main/kotlin/com/wespot/vote/dto/response/SaveVoteResponse.kt +++ b/core/src/main/kotlin/com/wespot/vote/dto/response/SavedVoteResponse.kt @@ -1,5 +1,5 @@ package com.wespot.vote.dto.response -data class SaveVoteResponse( +data class SavedVoteResponse( val id: Long ) diff --git a/core/src/main/kotlin/com/wespot/vote/port/in/SavedVoteUseCase.kt b/core/src/main/kotlin/com/wespot/vote/port/in/SavedVoteUseCase.kt index 341ca830..b767fd13 100644 --- a/core/src/main/kotlin/com/wespot/vote/port/in/SavedVoteUseCase.kt +++ b/core/src/main/kotlin/com/wespot/vote/port/in/SavedVoteUseCase.kt @@ -1,13 +1,13 @@ package com.wespot.vote.port.`in` import com.wespot.vote.dto.request.VoteRequests -import com.wespot.vote.dto.response.SaveVoteResponse +import com.wespot.vote.dto.response.SavedVoteResponse import com.wespot.vote.dto.response.VoteItems interface SavedVoteUseCase { fun getVoteOptions(): VoteItems - fun saveVote(requests: VoteRequests): SaveVoteResponse + fun saveVote(requests: VoteRequests): SavedVoteResponse } diff --git a/core/src/main/kotlin/com/wespot/vote/service/CreatedVoteService.kt b/core/src/main/kotlin/com/wespot/vote/service/CreatedVoteService.kt index eba7de6c..8b60fc8f 100644 --- a/core/src/main/kotlin/com/wespot/vote/service/CreatedVoteService.kt +++ b/core/src/main/kotlin/com/wespot/vote/service/CreatedVoteService.kt @@ -1,5 +1,6 @@ package com.wespot.vote.service +import com.wespot.EventUtils import com.wespot.user.User import com.wespot.user.port.out.UserPort import com.wespot.vote.Vote @@ -10,7 +11,6 @@ import com.wespot.vote.port.out.VoteOptionPort import com.wespot.vote.port.out.VotePort import com.wespot.vote.service.helper.VoteServiceHelper import com.wespot.voteoption.VoteOption -import org.springframework.context.ApplicationEventPublisher import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.time.LocalDate @@ -20,14 +20,13 @@ class CreatedVoteService( private val votePort: VotePort, private val userPort: UserPort, private val voteOptionPort: VoteOptionPort, - private val eventPublisher: ApplicationEventPublisher ) : CreatedVoteUseCase { @Transactional override fun createVotes() { val today = LocalDate.now() val allVoteOptions = voteOptionPort.findAll() - eventPublisher.publishEvent(EndVoteEvent()) + EventUtils.publish(EndVoteEvent()) userPort.findAll() .map { VoteIdentifier.of(it, today) } diff --git a/core/src/main/kotlin/com/wespot/vote/service/SavedVoteService.kt b/core/src/main/kotlin/com/wespot/vote/service/SavedVoteService.kt index 87c28e0c..b6e819d1 100644 --- a/core/src/main/kotlin/com/wespot/vote/service/SavedVoteService.kt +++ b/core/src/main/kotlin/com/wespot/vote/service/SavedVoteService.kt @@ -1,5 +1,6 @@ package com.wespot.vote.service +import com.wespot.EventUtils import com.wespot.exception.CustomException import com.wespot.exception.ExceptionView import com.wespot.user.User @@ -7,14 +8,12 @@ import com.wespot.user.port.out.UserPort import com.wespot.vote.Vote import com.wespot.vote.dto.request.VoteRequest import com.wespot.vote.dto.request.VoteRequests -import com.wespot.vote.dto.response.SaveVoteResponse +import com.wespot.vote.dto.response.SavedVoteResponse import com.wespot.vote.dto.response.VoteItems -import com.wespot.vote.event.ReceivedVoteEvent import com.wespot.vote.event.RegisteredVoteEvent import com.wespot.vote.port.`in`.SavedVoteUseCase import com.wespot.vote.port.out.VotePort import com.wespot.vote.service.helper.VoteServiceHelper -import org.springframework.context.ApplicationEventPublisher import org.springframework.http.HttpStatus import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -25,7 +24,6 @@ import java.time.LocalDateTime class SavedVoteService( private val votePort: VotePort, private val userPort: UserPort, - private val eventPublisher: ApplicationEventPublisher, ) : SavedVoteUseCase { @Transactional(readOnly = true) @@ -46,34 +44,32 @@ class SavedVoteService( @Transactional override fun saveVote( requests: VoteRequests - ): SaveVoteResponse { - validateRequestsSize(requests.votes.size) - validateUserIdsInRequests(requests.votes) + ): SavedVoteResponse { val user = VoteServiceHelper.findLoginUser(userPort) + val receivers = getVotedUsers(requests.votes) val voteTime = LocalDateTime.now() val vote: Vote = VoteServiceHelper.findVoteByUser(votePort, user, voteTime.toLocalDate()) requests.votes - .stream() - .forEach { request -> addBallot(request, vote, user, voteTime) } - eventPublisher.publishEvent(RegisteredVoteEvent(user, vote)) + .forEach { request -> + vote.addBallot( + request.voteOptionId, + user, + receivers.find { it.id == request.userId } + ?: throw CustomException(HttpStatus.BAD_REQUEST, ExceptionView.DIALOG, "투표 대상을 찾을 수 없습니다."), + voteTime) + } + EventUtils.publish(RegisteredVoteEvent(user, vote)) - return SaveVoteResponse(votePort.save(vote).id) + return SavedVoteResponse(votePort.save(vote).id) } - private fun addBallot( - request: VoteRequest, - vote: Vote, - user: User, - voteTime: LocalDateTime - ) { - val receiver = VoteServiceHelper.findUser(userPort, request.userId) - eventPublisher.publishEvent(ReceivedVoteEvent(receiver)) - vote.addBallot( - voteOptionId = request.voteOptionId, - sender = user, - receiver = receiver, - voteTime = voteTime - ) + private fun getVotedUsers(requests: List): List { + validateRequestsSize(requests.size) + val userIds: List = requests.stream() + .map { it.userId } + .toList() + + return userPort.findByIdIn(userIds) } private fun validateRequestsSize(requestsSize: Int) { @@ -82,16 +78,4 @@ class SavedVoteService( } } - private fun validateUserIdsInRequests(requests: List) { - val userIds: List = requests.stream() - .map { it.userId } - .toList() - val foundUserIds = userPort.findIdsByIdIn(userIds) - - if (foundUserIds.size == userIds.size) { - return - } - throw CustomException(HttpStatus.BAD_REQUEST, ExceptionView.TOAST, "투표하고자 하는 회원이 존재하지 않습니다.") - } - } diff --git a/domain/src/main/kotlin/com/wespot/message/Message.kt b/domain/src/main/kotlin/com/wespot/message/Message.kt index c8b5af52..3280b8cd 100644 --- a/domain/src/main/kotlin/com/wespot/message/Message.kt +++ b/domain/src/main/kotlin/com/wespot/message/Message.kt @@ -36,6 +36,7 @@ data class Message( receiverId: Long, senderName: String ): Message { + validateRegulationUser(modifier) validateMessageOwner(modifier) require(senderId != receiverId) { throw CustomException( @@ -219,6 +220,7 @@ data class Message( fun sendMessageSoftDelete(loginUser: User): Message { validateDeleteSendMessage(loginUser) + validateRegulationUser(loginUser) return this.copy( isSenderDeleted = true, senderDeletedAt = LocalDateTime.now(), @@ -228,6 +230,7 @@ data class Message( fun receivedMessageSoftDelete(loginUser: User): Message { validateDeleteReceivedMessage(loginUser) + validateRegulationUser(loginUser) return this.copy( isReceiverDeleted = true, receiverDeletedAt = LocalDateTime.now(), @@ -250,19 +253,21 @@ data class Message( fun sendMessage( content: String, - receiverId: Long, - senderId: Long, + receiver: User, + sender: User, senderName: String, isAnonymous: Boolean ): Message { + validateRegulationUser(sender) + validateRegulationUser(receiver) validateMessageSendTime() val message = Message( id = 0L, content = MessageContent.from(content), - senderId = senderId, + senderId = sender.id, senderName = senderName, messageType = MessageType.SENT, - receiverId = receiverId, + receiverId = receiver.id, isAnonymous = isAnonymous, isReceiverRead = false, readAt = null, @@ -309,5 +314,23 @@ data class Message( receiverDeletedAt = null ) } + + private fun validateRegulationUser(user: User) { + if (user.isWithDraw()) { + throw CustomException( + HttpStatus.BAD_REQUEST, + ExceptionView.TOAST, + "탈퇴한 학생은 해당 서비스를 이용할 수 없습니다." + ) + } + if (user.isKeepRestrict()) { + throw CustomException( + HttpStatus.BAD_REQUEST, + ExceptionView.TOAST, + "이용제한을 당한 학생은 해당 서비스를 이용할 수 없습니다." + ) + } + } + } } diff --git a/domain/src/main/kotlin/com/wespot/user/User.kt b/domain/src/main/kotlin/com/wespot/user/User.kt index 9055cb2f..a6d5efe1 100644 --- a/domain/src/main/kotlin/com/wespot/user/User.kt +++ b/domain/src/main/kotlin/com/wespot/user/User.kt @@ -1,6 +1,9 @@ package com.wespot.user +import com.wespot.exception.CustomException +import com.wespot.exception.ExceptionView import com.wespot.user.restriction.Restriction +import org.springframework.http.HttpStatus import java.time.LocalDate import java.time.LocalDateTime @@ -83,33 +86,33 @@ data class User( withdrawalCompleteAt = null ) - fun cancelWithdraw() : User{ - isWithdrawActive() - return User( - id = id, - email = email, - password = password, - name = name, - introduction = introduction, - gender = gender, - role = role, - schoolId = schoolId, - grade = grade, - classNumber = classNumber, - profile = profile, - fcm = fcm, - setting = setting, - social = social, - userConsent = userConsent, - createdAt = createdAt, - restriction = restriction, - updatedAt = LocalDateTime.now(), - withdrawalStatus = WithdrawalStatus.CANCELED, - withdrawalRequestAt = withdrawalRequestAt, - withdrawalCancelAt = LocalDateTime.now(), - withdrawalCompleteAt = null - ) - } + fun cancelWithdraw(): User { + isWithdrawActive() + return User( + id = id, + email = email, + password = password, + name = name, + introduction = introduction, + gender = gender, + role = role, + schoolId = schoolId, + grade = grade, + classNumber = classNumber, + profile = profile, + fcm = fcm, + setting = setting, + social = social, + userConsent = userConsent, + createdAt = createdAt, + restriction = restriction, + updatedAt = LocalDateTime.now(), + withdrawalStatus = WithdrawalStatus.CANCELED, + withdrawalRequestAt = withdrawalRequestAt, + withdrawalCancelAt = LocalDateTime.now(), + withdrawalCompleteAt = null + ) + } fun completeWithdraw( @@ -148,7 +151,8 @@ data class User( companion object { private const val WITHDRAW_USER_NAME = "탈퇴한 유저입니다." - private const val INIT_PROFILE_ICON_URL = "https://wespot-test-data.s3.ap-northeast-2.amazonaws.com/wespot_init_profile.png" + private const val INIT_PROFILE_ICON_URL = + "https://wespot-test-data.s3.ap-northeast-2.amazonaws.com/wespot_init_profile.png" fun create( email: String, @@ -160,33 +164,33 @@ data class User( social: Social, gender: Gender, ) = User( - id = 0L, - email = email, - password = password, - name = name, - introduction = UserIntroduction.emptyUserIntroduction(), - gender = gender, - role = Role.USER, - schoolId = schoolId, - grade = grade, - classNumber = groupNumber, - profile = Profile.createInit(), - fcm = null, - setting = Setting(), - social = social, - userConsent = UserConsent.create( - consentType = ConsentType.MARKETING, - consentedAt = LocalDateTime.now(), - consentValue = false - ), - restriction = Restriction.createInitialState(), - createdAt = LocalDateTime.now(), - updatedAt = LocalDateTime.now(), - withdrawalStatus = WithdrawalStatus.NONE, - withdrawalRequestAt = null, - withdrawalCancelAt = null, - withdrawalCompleteAt = null - ) + id = 0L, + email = email, + password = password, + name = name, + introduction = UserIntroduction.emptyUserIntroduction(), + gender = gender, + role = Role.USER, + schoolId = schoolId, + grade = grade, + classNumber = groupNumber, + profile = Profile.createInit(), + fcm = null, + setting = Setting(), + social = social, + userConsent = UserConsent.create( + consentType = ConsentType.MARKETING, + consentedAt = LocalDateTime.now(), + consentValue = false + ), + restriction = Restriction.createInitialState(), + createdAt = LocalDateTime.now(), + updatedAt = LocalDateTime.now(), + withdrawalStatus = WithdrawalStatus.NONE, + withdrawalRequestAt = null, + withdrawalCancelAt = null, + withdrawalCompleteAt = null + ) fun update( user: User, @@ -222,10 +226,9 @@ data class User( } - private fun isWithdrawActive() { if (withdrawalStatus != WithdrawalStatus.ACTIVE) { - throw IllegalStateException("탈퇴가 진행 중이 아닙니다.") + throw CustomException(HttpStatus.BAD_REQUEST, ExceptionView.TOAST, "탈퇴가 진행 중이 아닙니다.") } } @@ -260,4 +263,16 @@ data class User( && this.grade == otherUser.grade && this.classNumber == otherUser.classNumber + fun isKeepRestrict(): Boolean { + return restriction.isKeepRestriction() + } + + fun isWithDraw(): Boolean { + return withdrawalStatus == WithdrawalStatus.WITHDRAWN + } + + fun isRegulation(): Boolean { + return isWithDraw() || isKeepRestrict() + } + } diff --git a/domain/src/main/kotlin/com/wespot/vote/Vote.kt b/domain/src/main/kotlin/com/wespot/vote/Vote.kt index 42ae43c1..28800ae9 100644 --- a/domain/src/main/kotlin/com/wespot/vote/Vote.kt +++ b/domain/src/main/kotlin/com/wespot/vote/Vote.kt @@ -1,9 +1,12 @@ package com.wespot.vote +import com.wespot.EventUtils import com.wespot.exception.CustomException import com.wespot.exception.ExceptionView import com.wespot.user.User +import com.wespot.vote.event.ReceivedVoteEvent import com.wespot.voteoption.VoteOption +import org.springframework.data.domain.AbstractAggregateRoot import org.springframework.http.HttpStatus import java.time.LocalDate import java.time.LocalDateTime @@ -15,7 +18,7 @@ data class Vote( val voteNumber: Int, val voteOptionsByVoteDate: VoteOptionsByVoteDate, val ballots: Ballots, -) { +) : AbstractAggregateRoot() { companion object { private const val NUMBER_OF_VOTE_USERS = 5 @@ -81,14 +84,14 @@ data class Vote( } } - fun findUsersForVote(classmates: List, user: User): List { - validateClassmate(user) + validateUser(user) classmates.forEach { validateClassmate(it) } val alreadyVotedByUser: List = ballots.findUserIdsVotedByUser(user.id) return classmates.stream() .filter { !alreadyVotedByUser.contains(it.id) && isNotMe(it, user) } + .filter { !it.isRegulation() } .toList() .shuffled() .take(NUMBER_OF_VOTE_USERS) @@ -103,8 +106,9 @@ data class Vote( voteTime: LocalDateTime ) { voteOptionsByVoteDate.validateVoteOption(voteOptionId) - validateClassmate(sender) - validateClassmate(receiver) + validateUser(sender) + validateUser(receiver) + ballots.add( Ballot.of( voteId = this.id, @@ -115,6 +119,26 @@ data class Vote( voteTime = voteTime ) ) + + EventUtils.publish(ReceivedVoteEvent(receiver)) + } + + private fun validateUser(user: User) { + validateClassmate(user) + if (user.isWithDraw()) { + throw CustomException( + HttpStatus.BAD_REQUEST, + ExceptionView.TOAST, + "탈퇴한 학생은 해당 서비스를 이용할 수 없습니다." + ) + } + if (user.isKeepRestrict()) { + throw CustomException( + HttpStatus.BAD_REQUEST, + ExceptionView.TOAST, + "이용제한을 당한 학생은 해당 서비스를 이용할 수 없습니다." + ) + } } private fun validateClassmate(user: User) { @@ -123,7 +147,7 @@ data class Vote( throw CustomException( HttpStatus.BAD_REQUEST, ExceptionView.TOAST, - "다른 반의 학생이(을) 투표할 수 없습니다." + "다른 반 학생과 상호작용 할 수 없습니다." ) } } diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt index 72d915c2..847b70ea 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/adapter/UserPersistenceAdapter.kt @@ -37,7 +37,8 @@ class UserPersistenceAdapter( cursorSchoolName: String?, cursorSchoolTypeOrder: Int?, cursorId: Long?, - pageable: Pageable + pageable: Pageable, + loginUserId: Long, ): List { return userJpaRepository.searchUsers( name = name, @@ -45,7 +46,8 @@ class UserPersistenceAdapter( cursorSchoolName = cursorSchoolName, cursorSchoolTypeOrder = cursorSchoolTypeOrder, cursorId = cursorId, - pageable = pageable + pageable = pageable, + loginUserId = loginUserId ).stream() .map { userJpaEntity -> UserMapper.mapToDomainEntity(userJpaEntity) } .toList() @@ -56,14 +58,16 @@ class UserPersistenceAdapter( cursorName: String?, cursorSchoolName: String?, cursorSchoolTypeOrder: Int?, - cursorId: Long? + cursorId: Long?, + loginUserId: Long, ): Long { return userJpaRepository.countUsersAfterCursor( name = name, cursorName = cursorName, cursorSchoolName = cursorSchoolName, cursorSchoolTypeOrder = cursorSchoolTypeOrder, - cursorId = cursorId + cursorId = cursorId, + loginUserId = loginUserId ) } @@ -102,8 +106,9 @@ class UserPersistenceAdapter( .toList() } - override fun findIdsByIdIn(ids: List): List { - return userJpaRepository.findIdsByIdIn(ids) + override fun findByIdIn(ids: List): List { + return userJpaRepository.findByIdIn(ids) + .map { UserMapper.mapToDomainEntity(it) } } override fun findAll(): List { diff --git a/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt b/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt index d0cb5209..b1fede77 100644 --- a/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt +++ b/infrastructure/mysql/src/main/kotlin/com/wespot/user/repository/UserJpaRepository.kt @@ -12,14 +12,25 @@ interface UserJpaRepository : JpaRepository { fun findByEmail(email: String): UserJpaEntity? + @Query( + """ + SELECT u + FROM UserJpaEntity u + WHERE u.schoolId = :schoolId + AND u.grade = :grade + AND u.classNumber = :classNumber + AND u.withdrawalStatus != 'WITHDRAWN' + AND u.restriction.messageRestrictionType = 'NONE' + AND u.restriction.voteRestrictionType = 'NONE' + """ + ) fun findAllBySchoolIdAndGradeAndClassNumber( schoolId: Long, grade: Int, classNumber: Int ): List - @Query("SELECT u.id FROM UserJpaEntity u WHERE u.id IN :ids") - fun findIdsByIdIn(@Param("ids") ids: List): List + fun findByIdIn(ids: List): List fun existsBySchoolIdAndGradeAndClassNumber( schoolId: Long, @@ -32,6 +43,7 @@ interface UserJpaRepository : JpaRepository { SELECT u FROM UserJpaEntity u LEFT JOIN SchoolJpaEntity s ON u.schoolId = s.id WHERE LOWER(u.name) LIKE LOWER(CONCAT('%', :name, '%')) + AND u.id <> :loginUserId AND ( :cursorId IS NULL OR ( (:cursorName IS NULL OR u.name > :cursorName) OR @@ -48,6 +60,9 @@ interface UserJpaRepository : JpaRepository { END = :cursorSchoolTypeOrder AND u.id > :cursorId) ) ) + AND u.withdrawalStatus != 'WITHDRAWN' + AND u.restriction.messageRestrictionType = 'NONE' + AND u.restriction.voteRestrictionType = 'NONE' ORDER BY u.name ASC, s.name ASC, CASE WHEN s.schoolType = 'MIDDLE' THEN 1 @@ -61,14 +76,15 @@ interface UserJpaRepository : JpaRepository { @Param("cursorSchoolName") cursorSchoolName: String?, @Param("cursorSchoolTypeOrder") cursorSchoolTypeOrder: Int?, @Param("cursorId") cursorId: Long?, + @Param("loginUserId") loginUserId: Long, pageable: Pageable ): List - @Query( """ SELECT COUNT(u) FROM UserJpaEntity u LEFT JOIN SchoolJpaEntity s ON u.schoolId = s.id + AND u.id <> :loginUserId WHERE LOWER(u.name) LIKE LOWER(CONCAT('%', :name, '%')) AND ( :cursorId IS NULL OR ( @@ -86,6 +102,9 @@ interface UserJpaRepository : JpaRepository { END = :cursorSchoolTypeOrder AND u.id > :cursorId) ) ) + AND u.withdrawalStatus != 'WITHDRAWN' + AND u.restriction.messageRestrictionType = 'NONE' + AND u.restriction.voteRestrictionType = 'NONE' """ ) fun countUsersAfterCursor( @@ -93,7 +112,8 @@ interface UserJpaRepository : JpaRepository { @Param("cursorName") cursorName: String?, @Param("cursorSchoolName") cursorSchoolName: String?, @Param("cursorSchoolTypeOrder") cursorSchoolTypeOrder: Int?, - @Param("cursorId") cursorId: Long? + @Param("cursorId") cursorId: Long?, + @Param("loginUserId") loginUserId: Long, ): Long fun countBySchoolIdAndGradeAndClassNumber(