From db5491ae0f52268c89493365be1e38184a411828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 19 Jun 2024 21:46:00 +0900 Subject: [PATCH 01/47] =?UTF-8?q?refactor(Slack):=20=EC=A0=A0=ED=82=A8?= =?UTF-8?q?=EC=8A=A4=20=EB=B9=8C=EB=93=9C=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jenkins/Jenkinsfile | 84 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index f0ce1ac78..1cd3f349e 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -134,13 +134,13 @@ pipeline { post { failure { script { - sendSlackNotification("${env.GIT_CHANGELOG}\n:scream_cat: Deployment failed.", env.SLACK_COLOR_FAILURE) + sendSlackNotification(":scream_cat: Deployment failed.", env.SLACK_COLOR_FAILURE, true) } } success { script { - sendSlackNotification("${env.GIT_CHANGELOG}\n:rocket: Deployment completed successfully.", env.SLACK_COLOR_SUCCESS) + sendSlackNotification(":rocket: Deployment completed successfully", env.SLACK_COLOR_SUCCESS, false) } } } @@ -165,6 +165,77 @@ def sendSlackNotification(message, color) { } } +def sendSlackNotification(String message, String color, boolean isFailure = false) { + def jobUrl = "${env.BUILD_URL}" + def consoleOutputUrl = "${jobUrl}console" + def buildLog = isFailure ? getBuildLog(10) : "" + + def payload = [ + blocks: [ + [ + type: "section", + text: [ + type: "mrkdwn", + text: message + ] + ] + ], + attachments: [ + [ + color: color, + blocks: [ + [ + type: "section", + text: [ + type: "mrkdwn", + text: "*Change Log:*\n${env.GIT_CHANGELOG}" + ] + ], + isFailure ? [ + type: "section", + text: [ + type: "mrkdwn", + text: "*Reason:*\n```${buildLog}```" + ] + ] : null, + [ + type: "actions", + elements: [ + [ + type: "button", + text: [ + type: "plain_text", + text: "Job", + emoji: true + ], + url: jobUrl, + value: "click_job" + ], + [ + type: "button", + text: [ + type: "plain_text", + text: "Console Output", + emoji: true + ], + url: consoleOutputUrl, + value: "click_console_output" + ] + ] + ] + ].findAll { it != null } + ] + ] + ] + + withEnv(["SLACK_WEBHOOK_URL=${env.SLACK_WEBHOOK_URL}"]) { + def payloadJson = groovy.json.JsonOutput.toJson(payload) + sh """ + curl -X POST -H 'Content-type: application/json' --data '${payloadJson}' ${SLACK_WEBHOOK_URL} + """ + } +} + def getChangeLog() { def previousCommit = env.GIT_PREVIOUS_SUCCESSFUL_COMMIT ?: 'HEAD~1' def currentCommit = env.GIT_COMMIT ?: 'HEAD' @@ -182,6 +253,15 @@ def getChangeLog() { return changeLog } +def getBuildLog(lines) { + def log = sh( + script: "tail -n ${lines} ${env.WORKSPACE}/target/build.log", + returnStdout: true + ).trim() + + return log.replaceAll('"', '\\"').replaceAll('\n', '\\\\n') +} + def backupPostgres() { def BACKUP_FILE = "postgres_backup_${new Date().format('yyyy-MM-dd_HH-mm-ss')}.sql" withEnv([ From a815832b99197259aa728b2609eff6c4cfd0e9f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 19 Jun 2024 21:51:50 +0900 Subject: [PATCH 02/47] =?UTF-8?q?fix(Slack):=20=EC=8A=AC=EB=9E=99=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=A0=84=EC=86=A1=20=EB=A9=94?= =?UTF-8?q?=EC=86=8C=EB=93=9C=EB=AA=85=20=EC=A4=91=EB=B3=B5=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jenkins/Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index 1cd3f349e..54b273b14 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -134,13 +134,13 @@ pipeline { post { failure { script { - sendSlackNotification(":scream_cat: Deployment failed.", env.SLACK_COLOR_FAILURE, true) + sendSlackBuildNotification(":scream_cat: Deployment failed.", env.SLACK_COLOR_FAILURE, true) } } success { script { - sendSlackNotification(":rocket: Deployment completed successfully", env.SLACK_COLOR_SUCCESS, false) + sendSlackBuildNotification(":rocket: Deployment completed successfully", env.SLACK_COLOR_SUCCESS, false) } } } @@ -165,7 +165,7 @@ def sendSlackNotification(message, color) { } } -def sendSlackNotification(String message, String color, boolean isFailure = false) { +def sendSlackBuildNotification(String message, String color, boolean isFailure = false) { def jobUrl = "${env.BUILD_URL}" def consoleOutputUrl = "${jobUrl}console" def buildLog = isFailure ? getBuildLog(10) : "" From 7547ef1714b7b76bb6db347b424cfe3706cc9c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 19 Jun 2024 22:00:19 +0900 Subject: [PATCH 03/47] =?UTF-8?q?fix(Slack):=20=EC=8A=AC=EB=9E=99=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=A0=84=EC=86=A1=20=EB=A9=94?= =?UTF-8?q?=EC=86=8C=EB=93=9C=EB=AA=85=20=EC=A4=91=EB=B3=B5=20=EB=B0=8F=20?= =?UTF-8?q?base=20url=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jenkins/Jenkinsfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index 54b273b14..4e9ad44ed 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -2,6 +2,8 @@ pipeline { agent any environment { + JENKINS_DOMAIN = credentials('jenkins_domain') + SLACK_WEBHOOK_URL = credentials('slack_webhook_url') SLACK_COLOR_SUCCESS = credentials('slack_color_success') SLACK_COLOR_FAILURE = credentials('slack_color_failure') @@ -166,8 +168,8 @@ def sendSlackNotification(message, color) { } def sendSlackBuildNotification(String message, String color, boolean isFailure = false) { - def jobUrl = "${env.BUILD_URL}" - def consoleOutputUrl = "${jobUrl}console" + def jobUrl = "${env.JENKINS_DOMAIN}/job/${env.JOB_NAME}" + def consoleOutputUrl = "${jobUrl}/${env.BUILD_NUMBER}/console" def buildLog = isFailure ? getBuildLog(10) : "" def payload = [ From 38d7d2139bfe05d719686fb72104e49ad79bcb10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 19 Jun 2024 22:13:09 +0900 Subject: [PATCH 04/47] =?UTF-8?q?refactor(Jenkins):=20=ED=97=AC=EC=8A=A4?= =?UTF-8?q?=20=EC=B2=B4=ED=81=AC=20=EC=8B=9C=EA=B0=84=204=EB=B6=84->2.5?= =?UTF-8?q?=EB=B6=84=20=EC=B6=95=EC=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jenkins/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index 4e9ad44ed..585256fc9 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -401,7 +401,7 @@ def performHealthCheck() { echo "Public IP address: ${PUBLIC_IP}" def start_time = System.currentTimeMillis() - def timeout = start_time + 240000 // 4 minutes + def timeout = start_time + 150000 // 2.5 minutes while (System.currentTimeMillis() < timeout) { def elapsed = (System.currentTimeMillis() - start_time) / 1000 From 97be3b239f4cc4798bbefb1cf7c26c4f5df4d3e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 19 Jun 2024 23:00:26 +0900 Subject: [PATCH 05/47] =?UTF-8?q?refactor(Slack):=20=EC=A0=A0=ED=82=A8?= =?UTF-8?q?=EC=8A=A4=20=EB=B9=8C=EB=93=9C=20=EB=A1=9C=EA=B7=B8=20=EB=8C=80?= =?UTF-8?q?=EC=8B=A0=20=EC=8B=A4=ED=8C=A8=20=EB=8B=A8=EA=B3=84=EB=A5=BC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jenkins/Jenkinsfile | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index 585256fc9..3846792f1 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -197,7 +197,7 @@ def sendSlackBuildNotification(String message, String color, boolean isFailure = type: "section", text: [ type: "mrkdwn", - text: "*Reason:*\n```${buildLog}```" + text: "*Failed at stage:*\n```${env.CURRENT_STAGE}```" ] ] : null, [ @@ -255,15 +255,6 @@ def getChangeLog() { return changeLog } -def getBuildLog(lines) { - def log = sh( - script: "tail -n ${lines} ${env.WORKSPACE}/target/build.log", - returnStdout: true - ).trim() - - return log.replaceAll('"', '\\"').replaceAll('\n', '\\\\n') -} - def backupPostgres() { def BACKUP_FILE = "postgres_backup_${new Date().format('yyyy-MM-dd_HH-mm-ss')}.sql" withEnv([ From 7689d12be395c8477d96c411d67ddb9351bc851a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 19 Jun 2024 23:23:50 +0900 Subject: [PATCH 06/47] =?UTF-8?q?refactor(Slack):=20=EC=A0=A0=ED=82=A8?= =?UTF-8?q?=EC=8A=A4=20=EB=B9=8C=EB=93=9C=20=EB=A1=9C=EA=B7=B8=20=EB=8C=80?= =?UTF-8?q?=EC=8B=A0=20=EC=8B=A4=ED=8C=A8=20=EB=8B=A8=EA=B3=84=EB=A5=BC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jenkins/Jenkinsfile | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index 3846792f1..82057d28a 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -136,13 +136,13 @@ pipeline { post { failure { script { - sendSlackBuildNotification(":scream_cat: Deployment failed.", env.SLACK_COLOR_FAILURE, true) + sendSlackBuildNotification(":scream_cat: Deployment failed.", env.SLACK_COLOR_FAILURE) } } success { script { - sendSlackBuildNotification(":rocket: Deployment completed successfully", env.SLACK_COLOR_SUCCESS, false) + sendSlackBuildNotification(":rocket: Deployment completed successfully", env.SLACK_COLOR_SUCCESS) } } } @@ -167,10 +167,9 @@ def sendSlackNotification(message, color) { } } -def sendSlackBuildNotification(String message, String color, boolean isFailure = false) { +def sendSlackBuildNotification(String message, String color) { def jobUrl = "${env.JENKINS_DOMAIN}/job/${env.JOB_NAME}" def consoleOutputUrl = "${jobUrl}/${env.BUILD_NUMBER}/console" - def buildLog = isFailure ? getBuildLog(10) : "" def payload = [ blocks: [ @@ -193,13 +192,6 @@ def sendSlackBuildNotification(String message, String color, boolean isFailure = text: "*Change Log:*\n${env.GIT_CHANGELOG}" ] ], - isFailure ? [ - type: "section", - text: [ - type: "mrkdwn", - text: "*Failed at stage:*\n```${env.CURRENT_STAGE}```" - ] - ] : null, [ type: "actions", elements: [ From 75535d5b0fd342a851638fdbd1e80541ed553d6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 19 Jun 2024 23:44:50 +0900 Subject: [PATCH 07/47] =?UTF-8?q?refactor(Slack):=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=EB=A5=BC=20JSON=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=95=EC=9D=98=ED=95=98=EC=97=AC=20=EC=89=BD?= =?UTF-8?q?=EA=B2=8C=20=EB=B3=80=EA=B2=BD=20=EA=B0=80=EB=8A=A5=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jenkins/Jenkinsfile | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index 82057d28a..ffe491337 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -148,25 +148,25 @@ pipeline { } } -def sendSlackNotification(message, color) { - withEnv([ - "SLACK_WEBHOOK_URL=${env.SLACK_WEBHOOK_URL}" - ]) { - def payload = """{ - "attachments": [ - { - "color": "${color}", - "text": "${message.replaceAll('"', '\\"').replaceAll('\n', '\\\\n')}" - } +def sendSlackNotification(String message, String color) { + def payload = [ + attachments: [ + [ + color: color, + text: message.replaceAll('"', '\\"').replaceAll('\n', '\\\\n') ] - }""" + ] + ] + withEnv(["SLACK_WEBHOOK_URL=${env.SLACK_WEBHOOK_URL}"]) { + def payloadJson = groovy.json.JsonOutput.toJson(payload) sh """ - curl -X POST --data-urlencode 'payload=${payload}' ${SLACK_WEBHOOK_URL} + curl -X POST -H 'Content-type: application/json' --data '${payloadJson}' ${SLACK_WEBHOOK_URL} """ } } + def sendSlackBuildNotification(String message, String color) { def jobUrl = "${env.JENKINS_DOMAIN}/job/${env.JOB_NAME}" def consoleOutputUrl = "${jobUrl}/${env.BUILD_NUMBER}/console" From 2288a52c2e1bf351054f6b99fac8077cc925c5e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Thu, 20 Jun 2024 00:55:22 +0900 Subject: [PATCH 08/47] =?UTF-8?q?fix(Jenkins):=20Jenkinsfile=EC=97=90=20?= =?UTF-8?q?=ED=8A=B8=EB=A6=AC=EA=B1=B0=EB=A5=BC=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=98=EC=97=AC=20Github=20Webhook=EC=9D=B4=20=EC=A0=95?= =?UTF-8?q?=EC=83=81=20=EC=9E=91=EB=8F=99=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jenkins/Jenkinsfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index ffe491337..eaee06c49 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -1,6 +1,10 @@ pipeline { agent any + triggers { + githubPush() + } + environment { JENKINS_DOMAIN = credentials('jenkins_domain') From 05be4564450a04dc11b313b4d8fc836bb2a7e31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Thu, 20 Jun 2024 01:02:05 +0900 Subject: [PATCH 09/47] Webhook test --- jenkins/Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index eaee06c49..5ef0b7782 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -5,6 +5,7 @@ pipeline { githubPush() } + environment { JENKINS_DOMAIN = credentials('jenkins_domain') From dc0be0fa3e5d66734791b893c2f4e71fd3c6f649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Thu, 20 Jun 2024 01:13:06 +0900 Subject: [PATCH 10/47] =?UTF-8?q?=EA=B0=9C=ED=96=89=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jenkins/Jenkinsfile | 1 - 1 file changed, 1 deletion(-) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index 5ef0b7782..eaee06c49 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -5,7 +5,6 @@ pipeline { githubPush() } - environment { JENKINS_DOMAIN = credentials('jenkins_domain') From 8a3f65bc018a2e5180e0c3a951a6238082c1758d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <85067003+limehee@users.noreply.github.com> Date: Fri, 21 Jun 2024 16:18:22 +0900 Subject: [PATCH 11/47] =?UTF-8?q?=EC=8A=AC=EB=9E=99=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20?= =?UTF-8?q?=EC=9C=A0=EB=8F=99=EC=A0=81=20=EC=95=8C=EB=A6=BC=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EC=99=84=EB=A3=8C=20(#386)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(Slack): 슬랙 알림을 발행-구독 패턴으로 변경 및 알림을 On/Off 가능한 구조로 변경 * feat(Slack): 슬랙 알림 설정 변경 API 추가 * feat(Slack): 슬랙 알림 조회 API 추가 * refactor(Slack): AlertType 예외 수정 * refactor(Slack): 코드 컨벤션 수정 * feat(Slack): 새 게시글 알림 추가 * refactor(Slack): 새 게시글 알림 이모지 변경 --- .../application/ApplicationService.java | 3 +- .../board/application/BoardService.java | 4 + .../clab/api/domain/board/domain/Board.java | 1 + .../api/NotificationSettingController.java | 46 +++ .../NotificationSettingService.java | 48 +++ .../slack/application/SlackService.java | 254 ++------------- .../slack/application/SlackServiceHelper.java | 293 ++++++++++++++++++ .../dao/NotificationSettingRepository.java | 13 + .../global/common/slack/domain/AlertType.java | 9 + .../slack/domain/AlertTypeConverter.java | 43 +++ .../slack/domain/AlertTypeResolver.java | 23 ++ .../common/slack/domain/GeneralAlertType.java | 19 ++ .../slack/domain/NotificationSetting.java | 43 +++ .../slack/domain/SecurityAlertType.java | 2 +- .../NotificationSettingUpdateRequestDto.java | 20 ++ .../NotificationSettingResponseDto.java | 22 ++ .../common/slack/event/NotificationEvent.java | 24 ++ .../exception/AlertTypeNotFoundException.java | 9 + .../slack/listener/NotificationListener.java | 30 ++ src/main/resources/messages.properties | 2 + 20 files changed, 669 insertions(+), 239 deletions(-) create mode 100644 src/main/java/page/clab/api/global/common/slack/api/NotificationSettingController.java create mode 100644 src/main/java/page/clab/api/global/common/slack/application/NotificationSettingService.java create mode 100644 src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java create mode 100644 src/main/java/page/clab/api/global/common/slack/dao/NotificationSettingRepository.java create mode 100644 src/main/java/page/clab/api/global/common/slack/domain/AlertType.java create mode 100644 src/main/java/page/clab/api/global/common/slack/domain/AlertTypeConverter.java create mode 100644 src/main/java/page/clab/api/global/common/slack/domain/AlertTypeResolver.java create mode 100644 src/main/java/page/clab/api/global/common/slack/domain/GeneralAlertType.java create mode 100644 src/main/java/page/clab/api/global/common/slack/domain/NotificationSetting.java create mode 100644 src/main/java/page/clab/api/global/common/slack/dto/request/NotificationSettingUpdateRequestDto.java create mode 100644 src/main/java/page/clab/api/global/common/slack/dto/response/NotificationSettingResponseDto.java create mode 100644 src/main/java/page/clab/api/global/common/slack/event/NotificationEvent.java create mode 100644 src/main/java/page/clab/api/global/common/slack/exception/AlertTypeNotFoundException.java create mode 100644 src/main/java/page/clab/api/global/common/slack/listener/NotificationListener.java diff --git a/src/main/java/page/clab/api/domain/application/application/ApplicationService.java b/src/main/java/page/clab/api/domain/application/application/ApplicationService.java index 81fa9b55d..9fbabd6e2 100644 --- a/src/main/java/page/clab/api/domain/application/application/ApplicationService.java +++ b/src/main/java/page/clab/api/domain/application/application/ApplicationService.java @@ -1,6 +1,5 @@ package page.clab.api.domain.application.application; -import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -44,7 +43,7 @@ public String createApplication(ApplicationRequestDto requestDto) { notificationService.sendNotificationToAdmins(requestDto.getStudentId() + " " + requestDto.getName() + "님이 동아리에 지원하였습니다."); - slackService.sendApplicationNotification(requestDto); + slackService.sendNewApplicationNotification(requestDto); return applicationRepository.save(application).getStudentId(); } diff --git a/src/main/java/page/clab/api/domain/board/application/BoardService.java b/src/main/java/page/clab/api/domain/board/application/BoardService.java index 5462632f4..4c9427fda 100644 --- a/src/main/java/page/clab/api/domain/board/application/BoardService.java +++ b/src/main/java/page/clab/api/domain/board/application/BoardService.java @@ -24,6 +24,7 @@ import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.common.file.application.UploadedFileService; import page.clab.api.global.common.file.domain.UploadedFile; +import page.clab.api.global.common.slack.application.SlackService; import page.clab.api.global.exception.NotFoundException; import page.clab.api.global.exception.PermissionDeniedException; import page.clab.api.global.validation.ValidationService; @@ -43,6 +44,8 @@ public class BoardService { private final ValidationService validationService; + private final SlackService slackService; + private final BoardRepository boardRepository; private final BoardLikeRepository boardLikeRepository; @@ -59,6 +62,7 @@ public String createBoard(BoardRequestDto requestDto) throws PermissionDeniedExc if (board.shouldNotifyForNewBoard()) { notificationService.sendNotificationToMember(currentMember, "[" + board.getTitle() + "] 새로운 공지사항이 등록되었습니다."); } + slackService.sendNewBoardNotification(board); return boardRepository.save(board).getCategory().getKey(); } diff --git a/src/main/java/page/clab/api/domain/board/domain/Board.java b/src/main/java/page/clab/api/domain/board/domain/Board.java index 99847c588..44db8437b 100644 --- a/src/main/java/page/clab/api/domain/board/domain/Board.java +++ b/src/main/java/page/clab/api/domain/board/domain/Board.java @@ -69,6 +69,7 @@ public class Board extends BaseEntity { private String imageUrl; + @Getter @Column(nullable = false) private boolean wantAnonymous; diff --git a/src/main/java/page/clab/api/global/common/slack/api/NotificationSettingController.java b/src/main/java/page/clab/api/global/common/slack/api/NotificationSettingController.java new file mode 100644 index 000000000..e9757bb3d --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/api/NotificationSettingController.java @@ -0,0 +1,46 @@ +package page.clab.api.global.common.slack.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import page.clab.api.global.common.dto.ApiResponse; +import page.clab.api.global.common.slack.application.NotificationSettingService; +import page.clab.api.global.common.slack.dto.request.NotificationSettingUpdateRequestDto; +import page.clab.api.global.common.slack.dto.response.NotificationSettingResponseDto; + +import java.util.List; + +@RestController +@RequestMapping("/api/v1/notification-settings") +@RequiredArgsConstructor +@Tag(name = "Notification Setting", description = "알림 설정") +public class NotificationSettingController { + + private final NotificationSettingService notificationSettingService; + + @Operation(summary = "[S] 슬랙 알림 조회", description = "ROLE_SUPER 이상의 권한이 필요함") + @Secured({"ROLE_SUPER"}) + @GetMapping("") + public ApiResponse<Object> getNotificationSettings() { + List<NotificationSettingResponseDto> notificationSettings = notificationSettingService.getNotificationSettings(); + return ApiResponse.success(notificationSettings); + } + + @Operation(summary = "[S] 슬랙 알림 설정 변경", description = "ROLE_SUPER 이상의 권한이 필요함") + @Secured({"ROLE_SUPER"}) + @PutMapping("") + public ApiResponse<Object> updateNotificationSetting( + @Valid @RequestBody NotificationSettingUpdateRequestDto requestDto + ) { + notificationSettingService.updateNotificationSetting(requestDto.getAlertType(), requestDto.isEnabled()); + return ApiResponse.success(); + } + +} diff --git a/src/main/java/page/clab/api/global/common/slack/application/NotificationSettingService.java b/src/main/java/page/clab/api/global/common/slack/application/NotificationSettingService.java new file mode 100644 index 000000000..16aad7c4d --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/application/NotificationSettingService.java @@ -0,0 +1,48 @@ +package page.clab.api.global.common.slack.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import page.clab.api.global.common.slack.dao.NotificationSettingRepository; +import page.clab.api.global.common.slack.domain.AlertType; +import page.clab.api.global.common.slack.domain.AlertTypeResolver; +import page.clab.api.global.common.slack.domain.NotificationSetting; +import page.clab.api.global.common.slack.dto.response.NotificationSettingResponseDto; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class NotificationSettingService { + + private final AlertTypeResolver alertTypeResolver; + + private final NotificationSettingRepository settingRepository; + + @Transactional(readOnly = true) + public List<NotificationSettingResponseDto> getNotificationSettings() { + return settingRepository.findAll().stream() + .map(NotificationSettingResponseDto::toDto) + .toList(); + } + + @Transactional + public void updateNotificationSetting(String alertTypeName, boolean enabled) { + AlertType alertType = alertTypeResolver.resolve(alertTypeName); + NotificationSetting setting = getOrCreateDefaultSetting(alertType); + setting.updateEnabled(enabled); + settingRepository.save(setting); + } + + @Transactional + public NotificationSetting getOrCreateDefaultSetting(AlertType alertType) { + return settingRepository.findByAlertType(alertType) + .orElseGet(() -> createAndSaveDefaultSetting(alertType)); + } + + private NotificationSetting createAndSaveDefaultSetting(AlertType alertType) { + NotificationSetting defaultSetting = NotificationSetting.createDefault(alertType); + return settingRepository.save(defaultSetting); + } + +} diff --git a/src/main/java/page/clab/api/global/common/slack/application/SlackService.java b/src/main/java/page/clab/api/global/common/slack/application/SlackService.java index 48c76eeb3..8963b6f54 100644 --- a/src/main/java/page/clab/api/global/common/slack/application/SlackService.java +++ b/src/main/java/page/clab/api/global/common/slack/application/SlackService.java @@ -1,267 +1,49 @@ package page.clab.api.global.common.slack.application; -import com.slack.api.Slack; -import com.slack.api.model.Attachment; -import static com.slack.api.model.block.Blocks.actions; -import static com.slack.api.model.block.Blocks.section; -import com.slack.api.model.block.LayoutBlock; -import static com.slack.api.model.block.composition.BlockCompositions.markdownText; -import static com.slack.api.model.block.composition.BlockCompositions.plainText; -import static com.slack.api.model.block.element.BlockElements.asElements; -import static com.slack.api.model.block.element.BlockElements.button; -import com.slack.api.webhook.Payload; -import com.slack.api.webhook.WebhookResponse; -import io.ipinfo.api.model.IPResponse; -import io.ipinfo.spring.strategies.attribute.AttributeStrategy; import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.NotNull; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; -import org.springframework.core.env.Environment; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import page.clab.api.domain.application.dto.request.ApplicationRequestDto; +import page.clab.api.domain.board.domain.Board; import page.clab.api.domain.member.domain.Member; +import page.clab.api.global.common.slack.domain.GeneralAlertType; import page.clab.api.global.common.slack.domain.SecurityAlertType; -import page.clab.api.global.config.SlackConfig; -import page.clab.api.global.util.HttpReqResUtil; +import page.clab.api.global.common.slack.event.NotificationEvent; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryMXBean; -import java.lang.management.MemoryUsage; -import java.lang.management.OperatingSystemMXBean; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; - -@Service @Slf4j +@Service +@RequiredArgsConstructor public class SlackService { - private final Slack slack; - - private final String webhookUrl; - - private final String webUrl; - - private final String apiUrl; - - private final String color; - - private final Environment environment; - - private final AttributeStrategy attributeStrategy; - - public SlackService(SlackConfig slackConfig, Environment environment, AttributeStrategy attributeStrategy) { - this.slack = slackConfig.slack(); - this.webhookUrl = slackConfig.getWebhookUrl(); - this.webUrl = slackConfig.getWebUrl(); - this.apiUrl = slackConfig.getApiUrl(); - this.color = slackConfig.getColor(); - this.environment = environment; - this.attributeStrategy = attributeStrategy; - } + private final ApplicationEventPublisher eventPublisher; public void sendServerErrorNotification(HttpServletRequest request, Exception e) { - List<LayoutBlock> blocks = createErrorBlocks(request, e); - sendSlackMessageWithBlocks(blocks); + eventPublisher.publishEvent(new NotificationEvent(this, GeneralAlertType.SERVER_ERROR, request, e)); } public void sendSecurityAlertNotification(HttpServletRequest request, SecurityAlertType alertType, String additionalMessage) { - List<LayoutBlock> blocks = createSecurityAlertBlocks(request, alertType, additionalMessage); - sendSlackMessageWithBlocks(blocks); + eventPublisher.publishEvent(new NotificationEvent(this, alertType, request, additionalMessage)); } public void sendAdminLoginNotification(HttpServletRequest request, Member loginMember) { - List<LayoutBlock> blocks = createAdminLoginBlocks(request, loginMember); - sendSlackMessageWithBlocks(blocks); + eventPublisher.publishEvent(new NotificationEvent(this, GeneralAlertType.ADMIN_LOGIN, request, loginMember)); } - public void sendApplicationNotification(ApplicationRequestDto applicationRequestDto) { - List<LayoutBlock> blocks = createApplicationBlocks(applicationRequestDto); - sendSlackMessageWithBlocks(blocks); + public void sendNewApplicationNotification(ApplicationRequestDto applicationRequestDto) { + eventPublisher.publishEvent(new NotificationEvent(this, GeneralAlertType.APPLICATION_CREATED, null, applicationRequestDto)); } - @EventListener(ContextRefreshedEvent.class) - public void sendServerStartNotification() { - List<LayoutBlock> blocks = createServerStartBlocks(); - sendSlackMessageWithBlocks(blocks); - } - - private CompletableFuture<Boolean> sendSlackMessageWithBlocks(List<LayoutBlock> blocks) { - return CompletableFuture.supplyAsync(() -> { - Payload payload = Payload.builder() - .blocks(List.of(blocks.getFirst())) - .attachments(Collections.singletonList( - Attachment.builder() - .color(color) - .blocks(blocks.subList(1, blocks.size())) - .build() - )).build(); - try { - WebhookResponse response = slack.send(webhookUrl, payload); - if (response.getCode() == 200) { - return true; - } else { - log.error("Slack notification failed: {}", response.getMessage()); - return false; - } - } catch (IOException e) { - log.error("Failed to send Slack message: {}", e.getMessage(), e); - return false; - } - }); - } - - private List<LayoutBlock> createErrorBlocks(HttpServletRequest request, Exception e) { - String httpMethod = request.getMethod(); - String requestUrl = request.getRequestURI(); - String username = getUsername(); - - String errorMessage = e.getMessage() == null ? "No error message provided" : e.getMessage(); - String detailedMessage = extractMessageAfterException(errorMessage); - log.error("Server Error: {}", detailedMessage); - return Arrays.asList( - section(section -> section.text(markdownText(":firecracker: *Server Error*"))), - section(section -> section.fields(Arrays.asList( - markdownText("*User:*\n" + username), - markdownText("*Endpoint:*\n[" + httpMethod + "] " + requestUrl) - ))), - section(section -> section.text(markdownText("*Error Message:*\n" + detailedMessage))), - section(section -> section.text(markdownText("*Stack Trace:*\n```" + getStackTraceSummary(e) + "```"))) - ); + public void sendNewBoardNotification(Board board) { + eventPublisher.publishEvent(new NotificationEvent(this, GeneralAlertType.BOARD_CREATED, null, board)); } - private List<LayoutBlock> createSecurityAlertBlocks(HttpServletRequest request, SecurityAlertType alertType, String additionalMessage) { - String clientIpAddress = HttpReqResUtil.getClientIpAddressIfServletRequestExist(); - String requestUrl = request.getRequestURI(); - String username = getUsername(request); - String location = getLocation(request); - - return Arrays.asList( - section(section -> section.text(markdownText(String.format(":imp: *%s*", alertType.getTitle())))), - section(section -> section.fields(Arrays.asList( - markdownText("*User:*\n" + username), - markdownText("*IP Address:*\n" + clientIpAddress), - markdownText("*Location:*\n" + location), - markdownText("*Endpoint:*\n" + requestUrl) - ))), - section(section -> section.text(markdownText("*Details:*\n" + alertType.getDefaultMessage() + "\n" + additionalMessage))) - ); - } - - private List<LayoutBlock> createAdminLoginBlocks(HttpServletRequest request, Member loginMember) { - String clientIpAddress = HttpReqResUtil.getClientIpAddressIfServletRequestExist(); - String location = getLocation(request); - - return Arrays.asList( - section(section -> section.text(markdownText(String.format(":mechanic: *%s Login*", loginMember.getRole().getDescription())))), - section(section -> section.fields(Arrays.asList( - markdownText("*User:*\n" + loginMember.getId() + " " + loginMember.getName()), - markdownText("*IP Address:*\n" + clientIpAddress), - markdownText("*Location:*\n" + location) - ))) - ); - } - - private List<LayoutBlock> createApplicationBlocks(ApplicationRequestDto requestDto) { - List<LayoutBlock> blocks = new ArrayList<>(); - - blocks.add(section(section -> section.text(markdownText(":sparkles: *New Application*")))); - blocks.add(section(section -> section.fields(Arrays.asList( - markdownText("*Type:*\n" + requestDto.getApplicationType().getDescription()), - markdownText("*Student ID:*\n" + requestDto.getStudentId()), - markdownText("*Name:*\n" + requestDto.getName()), - markdownText("*Grade:*\n" + requestDto.getGrade() + "학년"), - markdownText("*Interests:*\n" + requestDto.getInterests()) - )))); - - if (requestDto.getGithubUrl() != null && !requestDto.getGithubUrl().isEmpty()) { - blocks.add(actions(actions -> actions.elements(asElements( - button(b -> b.text(plainText(pt -> pt.emoji(true).text("Github"))) - .url(requestDto.getGithubUrl()) - .actionId("click_github")) - )))); - } - return blocks; - } - - private List<LayoutBlock> createServerStartBlocks() { - String osInfo = System.getProperty("os.name") + " " + System.getProperty("os.version"); - String jdkVersion = System.getProperty("java.version"); - - OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); - int availableProcessors = osBean.getAvailableProcessors(); - double systemLoadAverage = osBean.getSystemLoadAverage(); - double cpuUsage = ((systemLoadAverage / availableProcessors) * 100); - - MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); - MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage(); - String memoryInfo = formatMemoryUsage(heapMemoryUsage); - - return Arrays.asList( - section(section -> section.text(markdownText("*:battery: Server Started*"))), - section(section -> section.fields(Arrays.asList( - markdownText("*Environment:* \n" + environment.getProperty("spring.profiles.active")), - markdownText("*OS:* \n" + osInfo), - markdownText("*JDK Version:* \n" + jdkVersion), - markdownText("*CPU Usage:* \n" + String.format("%.2f%%", cpuUsage)), - markdownText("*Memory Usage:* \n" + memoryInfo) - ))), - actions(actions -> actions.elements(asElements( - button(b -> b.text(plainText(pt -> pt.emoji(true).text("Web"))) - .url(webUrl) - .value("click_web")), - button(b -> b.text(plainText(pt -> pt.emoji(true).text("Swagger"))) - .url(apiUrl) - .value("click_swagger")) - ))) - ); - } - - private String extractMessageAfterException(String message) { - String exceptionIndicator = "Exception:"; - int exceptionIndex = message.indexOf(exceptionIndicator); - return exceptionIndex == -1 ? message : message.substring(exceptionIndex + exceptionIndicator.length()).trim(); - } - - private String getStackTraceSummary(Exception e) { - return Arrays.stream(e.getStackTrace()) - .limit(10) - .map(StackTraceElement::toString) - .collect(Collectors.joining("\n")); - } - - private String formatMemoryUsage(MemoryUsage memoryUsage) { - long usedMemory = memoryUsage.getUsed() / (1024 * 1024); - long maxMemory = memoryUsage.getMax() / (1024 * 1024); - return String.format("%dMB / %dMB (%.2f%%)", usedMemory, maxMemory, ((double) usedMemory / maxMemory) * 100); - } - - private static String getUsername() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - return (authentication == null || authentication.getName() == null) ? "anonymous" : authentication.getName(); - } - - private @NotNull String getUsername(HttpServletRequest request) { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - return Optional.ofNullable(request.getAttribute("member")) - .map(Object::toString) - .orElseGet(() -> Optional.ofNullable(authentication) - .map(Authentication::getName) - .orElse("anonymous")); - } - - private @NotNull String getLocation(HttpServletRequest request) { - IPResponse ipResponse = attributeStrategy.getAttribute(request); - return ipResponse == null ? "Unknown" : ipResponse.getCountryName() + ", " + ipResponse.getCity(); + @EventListener(ContextRefreshedEvent.class) + public void sendServerStartNotification() { + eventPublisher.publishEvent(new NotificationEvent(this, GeneralAlertType.SERVER_START, null, null)); } } diff --git a/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java b/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java new file mode 100644 index 000000000..3bd9c0e6d --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java @@ -0,0 +1,293 @@ +package page.clab.api.global.common.slack.application; + +import com.slack.api.Slack; +import com.slack.api.model.Attachment; +import static com.slack.api.model.block.Blocks.actions; +import static com.slack.api.model.block.Blocks.section; +import com.slack.api.model.block.LayoutBlock; +import static com.slack.api.model.block.composition.BlockCompositions.markdownText; +import static com.slack.api.model.block.composition.BlockCompositions.plainText; +import static com.slack.api.model.block.element.BlockElements.asElements; +import static com.slack.api.model.block.element.BlockElements.button; +import com.slack.api.webhook.Payload; +import com.slack.api.webhook.WebhookResponse; +import io.ipinfo.api.model.IPResponse; +import io.ipinfo.spring.strategies.attribute.AttributeStrategy; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.springframework.core.env.Environment; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import page.clab.api.domain.application.dto.request.ApplicationRequestDto; +import page.clab.api.domain.board.domain.Board; +import page.clab.api.domain.member.domain.Member; +import page.clab.api.global.common.slack.domain.AlertType; +import page.clab.api.global.common.slack.domain.GeneralAlertType; +import page.clab.api.global.common.slack.domain.SecurityAlertType; +import page.clab.api.global.config.SlackConfig; +import page.clab.api.global.util.HttpReqResUtil; + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; +import java.lang.management.OperatingSystemMXBean; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class SlackServiceHelper { + + private final Slack slack; + + private final String webhookUrl; + + private final String webUrl; + + private final String apiUrl; + + private final String color; + + private final Environment environment; + + private final AttributeStrategy attributeStrategy; + + public SlackServiceHelper(SlackConfig slackConfig, Environment environment, AttributeStrategy attributeStrategy) { + this.slack = slackConfig.slack(); + this.webhookUrl = slackConfig.getWebhookUrl(); + this.webUrl = slackConfig.getWebUrl(); + this.apiUrl = slackConfig.getApiUrl(); + this.color = slackConfig.getColor(); + this.environment = environment; + this.attributeStrategy = attributeStrategy; + } + + public CompletableFuture<Boolean> sendSlackMessage(AlertType alertType, HttpServletRequest request, Object additionalData) { + List<LayoutBlock> blocks = createBlocks(alertType, request, additionalData); + + return CompletableFuture.supplyAsync(() -> { + Payload payload = Payload.builder() + .blocks(List.of(blocks.getFirst())) + .attachments(Collections.singletonList( + Attachment.builder() + .color(color) + .blocks(blocks.subList(1, blocks.size())) + .build() + )).build(); + try { + WebhookResponse response = slack.send(webhookUrl, payload); + if (response.getCode() == 200) { + return true; + } else { + log.error("Slack notification failed: {}", response.getMessage()); + return false; + } + } catch (IOException e) { + log.error("Failed to send Slack message: {}", e.getMessage(), e); + return false; + } + }); + } + + public List<LayoutBlock> createBlocks(AlertType alertType, HttpServletRequest request, Object additionalData) { + if (alertType instanceof SecurityAlertType) { + return createSecurityAlertBlocks(request, alertType, additionalData.toString()); + } else if (alertType instanceof GeneralAlertType) { + switch ((GeneralAlertType) alertType) { + case ADMIN_LOGIN: + if (additionalData instanceof Member) { + return createAdminLoginBlocks(request, (Member) additionalData); + } + break; + case APPLICATION_CREATED: + if (additionalData instanceof ApplicationRequestDto) { + return createApplicationBlocks((ApplicationRequestDto) additionalData); + } + break; + case BOARD_CREATED: + if (additionalData instanceof Board) { + return createBoardBlocks((Board) additionalData); + } + break; + case SERVER_START: + return createServerStartBlocks(); + case SERVER_ERROR: + if (additionalData instanceof Exception) { + return createErrorBlocks(request, (Exception) additionalData); + } + break; + default: + log.error("Unknown alert type: {}", alertType); + return List.of(); + } + } + return List.of(); + } + + private List<LayoutBlock> createErrorBlocks(HttpServletRequest request, Exception e) { + String httpMethod = request.getMethod(); + String requestUrl = request.getRequestURI(); + String username = getUsername(); + + String errorMessage = e.getMessage() == null ? "No error message provided" : e.getMessage(); + String detailedMessage = extractMessageAfterException(errorMessage); + log.error("Server Error: {}", detailedMessage); + return Arrays.asList( + section(section -> section.text(markdownText(":firecracker: *Server Error*"))), + section(section -> section.fields(Arrays.asList( + markdownText("*User:*\n" + username), + markdownText("*Endpoint:*\n[" + httpMethod + "] " + requestUrl) + ))), + section(section -> section.text(markdownText("*Error Message:*\n" + detailedMessage))), + section(section -> section.text(markdownText("*Stack Trace:*\n```" + getStackTraceSummary(e) + "```"))) + ); + } + + private List<LayoutBlock> createSecurityAlertBlocks(HttpServletRequest request, AlertType alertType, String additionalMessage) { + String clientIpAddress = HttpReqResUtil.getClientIpAddressIfServletRequestExist(); + String requestUrl = request.getRequestURI(); + String username = getUsername(request); + String location = getLocation(request); + + return Arrays.asList( + section(section -> section.text(markdownText(String.format(":imp: *%s*", alertType.getTitle())))), + section(section -> section.fields(Arrays.asList( + markdownText("*User:*\n" + username), + markdownText("*IP Address:*\n" + clientIpAddress), + markdownText("*Location:*\n" + location), + markdownText("*Endpoint:*\n" + requestUrl) + ))), + section(section -> section.text(markdownText("*Details:*\n" + alertType.getDefaultMessage() + "\n" + additionalMessage))) + ); + } + + private List<LayoutBlock> createAdminLoginBlocks(HttpServletRequest request, Member loginMember) { + String clientIpAddress = HttpReqResUtil.getClientIpAddressIfServletRequestExist(); + String location = getLocation(request); + + return Arrays.asList( + section(section -> section.text(markdownText(String.format(":mechanic: *%s Login*", loginMember.getRole().getDescription())))), + section(section -> section.fields(Arrays.asList( + markdownText("*User:*\n" + loginMember.getId() + " " + loginMember.getName()), + markdownText("*IP Address:*\n" + clientIpAddress), + markdownText("*Location:*\n" + location) + ))) + ); + } + + private List<LayoutBlock> createApplicationBlocks(ApplicationRequestDto requestDto) { + List<LayoutBlock> blocks = new ArrayList<>(); + + blocks.add(section(section -> section.text(markdownText(":sparkles: *New Application*")))); + blocks.add(section(section -> section.fields(Arrays.asList( + markdownText("*Type:*\n" + requestDto.getApplicationType().getDescription()), + markdownText("*Student ID:*\n" + requestDto.getStudentId()), + markdownText("*Name:*\n" + requestDto.getName()), + markdownText("*Grade:*\n" + requestDto.getGrade() + "학년"), + markdownText("*Interests:*\n" + requestDto.getInterests()) + )))); + + if (requestDto.getGithubUrl() != null && !requestDto.getGithubUrl().isEmpty()) { + blocks.add(actions(actions -> actions.elements(asElements( + button(b -> b.text(plainText(pt -> pt.emoji(true).text("Github"))) + .url(requestDto.getGithubUrl()) + .actionId("click_github")) + )))); + } + return blocks; + } + + private List<LayoutBlock> createBoardBlocks(Board board) { + List<LayoutBlock> blocks = new ArrayList<>(); + String username = board.isWantAnonymous() ? + board.getNickname() : board.getMember().getId() + " " + board.getMember().getName(); + + blocks.add(section(section -> section.text(markdownText(":writing_hand: *New Board*")))); + blocks.add(section(section -> section.fields(Arrays.asList( + markdownText("*Title:*\n" + board.getTitle()), + markdownText("*Category:*\n" + board.getCategory().getDescription()), + markdownText("*User:*\n" + username) + )))); + return blocks; + } + + private List<LayoutBlock> createServerStartBlocks() { + String osInfo = System.getProperty("os.name") + " " + System.getProperty("os.version"); + String jdkVersion = System.getProperty("java.version"); + + OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); + int availableProcessors = osBean.getAvailableProcessors(); + double systemLoadAverage = osBean.getSystemLoadAverage(); + double cpuUsage = ((systemLoadAverage / availableProcessors) * 100); + + MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); + MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage(); + String memoryInfo = formatMemoryUsage(heapMemoryUsage); + + return Arrays.asList( + section(section -> section.text(markdownText("*:battery: Server Started*"))), + section(section -> section.fields(Arrays.asList( + markdownText("*Environment:* \n" + environment.getProperty("spring.profiles.active")), + markdownText("*OS:* \n" + osInfo), + markdownText("*JDK Version:* \n" + jdkVersion), + markdownText("*CPU Usage:* \n" + String.format("%.2f%%", cpuUsage)), + markdownText("*Memory Usage:* \n" + memoryInfo) + ))), + actions(actions -> actions.elements(asElements( + button(b -> b.text(plainText(pt -> pt.emoji(true).text("Web"))) + .url(webUrl) + .value("click_web")), + button(b -> b.text(plainText(pt -> pt.emoji(true).text("Swagger"))) + .url(apiUrl) + .value("click_swagger")) + ))) + ); + } + + private String extractMessageAfterException(String message) { + String exceptionIndicator = "Exception:"; + int exceptionIndex = message.indexOf(exceptionIndicator); + return exceptionIndex == -1 ? message : message.substring(exceptionIndex + exceptionIndicator.length()).trim(); + } + + private String getStackTraceSummary(Exception e) { + return Arrays.stream(e.getStackTrace()) + .limit(10) + .map(StackTraceElement::toString) + .collect(Collectors.joining("\n")); + } + + private String formatMemoryUsage(MemoryUsage memoryUsage) { + long usedMemory = memoryUsage.getUsed() / (1024 * 1024); + long maxMemory = memoryUsage.getMax() / (1024 * 1024); + return String.format("%dMB / %dMB (%.2f%%)", usedMemory, maxMemory, ((double) usedMemory / maxMemory) * 100); + } + + private static String getUsername() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + return (authentication == null || authentication.getName() == null) ? "anonymous" : authentication.getName(); + } + + private @NotNull String getUsername(HttpServletRequest request) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + return Optional.ofNullable(request.getAttribute("member")) + .map(Object::toString) + .orElseGet(() -> Optional.ofNullable(authentication) + .map(Authentication::getName) + .orElse("anonymous")); + } + + private @NotNull String getLocation(HttpServletRequest request) { + IPResponse ipResponse = attributeStrategy.getAttribute(request); + return ipResponse == null ? "Unknown" : ipResponse.getCountryName() + ", " + ipResponse.getCity(); + } + +} \ No newline at end of file diff --git a/src/main/java/page/clab/api/global/common/slack/dao/NotificationSettingRepository.java b/src/main/java/page/clab/api/global/common/slack/dao/NotificationSettingRepository.java new file mode 100644 index 000000000..a66b8d5cd --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/dao/NotificationSettingRepository.java @@ -0,0 +1,13 @@ +package page.clab.api.global.common.slack.dao; + +import org.springframework.data.jpa.repository.JpaRepository; +import page.clab.api.global.common.slack.domain.AlertType; +import page.clab.api.global.common.slack.domain.NotificationSetting; + +import java.util.Optional; + +public interface NotificationSettingRepository extends JpaRepository<NotificationSetting, Long> { + + Optional<NotificationSetting> findByAlertType(AlertType alertType); + +} diff --git a/src/main/java/page/clab/api/global/common/slack/domain/AlertType.java b/src/main/java/page/clab/api/global/common/slack/domain/AlertType.java new file mode 100644 index 000000000..971d10449 --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/domain/AlertType.java @@ -0,0 +1,9 @@ +package page.clab.api.global.common.slack.domain; + +public interface AlertType { + + String getTitle(); + + String getDefaultMessage(); + +} \ No newline at end of file diff --git a/src/main/java/page/clab/api/global/common/slack/domain/AlertTypeConverter.java b/src/main/java/page/clab/api/global/common/slack/domain/AlertTypeConverter.java new file mode 100644 index 000000000..c96092da1 --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/domain/AlertTypeConverter.java @@ -0,0 +1,43 @@ +package page.clab.api.global.common.slack.domain; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +import page.clab.api.global.common.slack.exception.AlertTypeNotFoundException; + +import java.util.HashMap; +import java.util.Map; + +@Converter(autoApply = true) +public class AlertTypeConverter implements AttributeConverter<AlertType, String> { + + private static final Map<String, AlertType> CACHE = new HashMap<>(); + + static { + for (GeneralAlertType type : GeneralAlertType.values()) { + CACHE.put(type.getTitle(), type); + } + for (SecurityAlertType type : SecurityAlertType.values()) { + CACHE.put(type.getTitle(), type); + } + } + + @Override + public String convertToDatabaseColumn(AlertType alertType) { + if (alertType == null) { + return null; + } + return alertType.getTitle(); + } + + @Override + public AlertType convertToEntityAttribute(String dbData) { + if (dbData == null || dbData.isEmpty()) { + return null; + } + AlertType alertType = CACHE.get(dbData); + if (alertType == null) { + throw new AlertTypeNotFoundException(dbData); + } + return alertType; + } +} diff --git a/src/main/java/page/clab/api/global/common/slack/domain/AlertTypeResolver.java b/src/main/java/page/clab/api/global/common/slack/domain/AlertTypeResolver.java new file mode 100644 index 000000000..a0c8d101d --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/domain/AlertTypeResolver.java @@ -0,0 +1,23 @@ +package page.clab.api.global.common.slack.domain; + +import org.springframework.stereotype.Service; +import page.clab.api.global.common.slack.exception.AlertTypeNotFoundException; + +@Service +public class AlertTypeResolver { + + public AlertType resolve(String alertTypeName) { + for (GeneralAlertType type : GeneralAlertType.values()) { + if (type.getTitle().equals(alertTypeName)) { + return type; + } + } + for (SecurityAlertType type : SecurityAlertType.values()) { + if (type.getTitle().equals(alertTypeName)) { + return type; + } + } + throw new AlertTypeNotFoundException(alertTypeName); + } + +} \ No newline at end of file diff --git a/src/main/java/page/clab/api/global/common/slack/domain/GeneralAlertType.java b/src/main/java/page/clab/api/global/common/slack/domain/GeneralAlertType.java new file mode 100644 index 000000000..42444236e --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/domain/GeneralAlertType.java @@ -0,0 +1,19 @@ +package page.clab.api.global.common.slack.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum GeneralAlertType implements AlertType { + + ADMIN_LOGIN("관리자 로그인", "Admin login."), + APPLICATION_CREATED("새 지원서", "New application has been submitted."), + BOARD_CREATED("새 게시글", "New board has been created."), + SERVER_START("서버 시작", "Server has been started."), + SERVER_ERROR("서버 에러", "Server error occurred."); + + private final String title; + private final String defaultMessage; + +} \ No newline at end of file diff --git a/src/main/java/page/clab/api/global/common/slack/domain/NotificationSetting.java b/src/main/java/page/clab/api/global/common/slack/domain/NotificationSetting.java new file mode 100644 index 000000000..a6b8ff8da --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/domain/NotificationSetting.java @@ -0,0 +1,43 @@ +package page.clab.api.global.common.slack.domain; + +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Entity +public class NotificationSetting { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Convert(converter = AlertTypeConverter.class) + private AlertType alertType; + + private boolean enabled; + + public static NotificationSetting createDefault(AlertType alertType) { + return NotificationSetting.builder() + .alertType(alertType) + .enabled(true) + .build(); + } + + public void updateEnabled(boolean enabled) { + this.enabled = enabled; + } + +} \ No newline at end of file diff --git a/src/main/java/page/clab/api/global/common/slack/domain/SecurityAlertType.java b/src/main/java/page/clab/api/global/common/slack/domain/SecurityAlertType.java index 587de828d..a0921ba64 100644 --- a/src/main/java/page/clab/api/global/common/slack/domain/SecurityAlertType.java +++ b/src/main/java/page/clab/api/global/common/slack/domain/SecurityAlertType.java @@ -5,7 +5,7 @@ @Getter @AllArgsConstructor -public enum SecurityAlertType { +public enum SecurityAlertType implements AlertType { ABNORMAL_ACCESS("비정상적인 접근", "Unexpected access pattern detected."), REPEATED_LOGIN_FAILURES("지속된 로그인 실패", "Multiple consecutive failed login attempts."), diff --git a/src/main/java/page/clab/api/global/common/slack/dto/request/NotificationSettingUpdateRequestDto.java b/src/main/java/page/clab/api/global/common/slack/dto/request/NotificationSettingUpdateRequestDto.java new file mode 100644 index 000000000..ed1343b02 --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/dto/request/NotificationSettingUpdateRequestDto.java @@ -0,0 +1,20 @@ +package page.clab.api.global.common.slack.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class NotificationSettingUpdateRequestDto { + + @NotNull(message = "{notNull.notificationSetting.alertType}") + @Schema(description = "알림 타입", example = "서버 시작") + private String alertType; + + @NotNull(message = "{notNull.notificationSetting.enabled}") + @Schema(description = "알림 활성화 여부", example = "true") + private boolean enabled; + +} diff --git a/src/main/java/page/clab/api/global/common/slack/dto/response/NotificationSettingResponseDto.java b/src/main/java/page/clab/api/global/common/slack/dto/response/NotificationSettingResponseDto.java new file mode 100644 index 000000000..25bb27b3f --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/dto/response/NotificationSettingResponseDto.java @@ -0,0 +1,22 @@ +package page.clab.api.global.common.slack.dto.response; + +import lombok.Builder; +import lombok.Getter; +import page.clab.api.global.common.slack.domain.NotificationSetting; + +@Getter +@Builder +public class NotificationSettingResponseDto { + + private String alertType; + + private boolean enabled; + + public static NotificationSettingResponseDto toDto(NotificationSetting setting) { + return NotificationSettingResponseDto.builder() + .alertType(setting.getAlertType().getTitle()) + .enabled(setting.isEnabled()) + .build(); + } + +} diff --git a/src/main/java/page/clab/api/global/common/slack/event/NotificationEvent.java b/src/main/java/page/clab/api/global/common/slack/event/NotificationEvent.java new file mode 100644 index 000000000..5ac93ee69 --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/event/NotificationEvent.java @@ -0,0 +1,24 @@ +package page.clab.api.global.common.slack.event; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.Getter; +import org.springframework.context.ApplicationEvent; +import page.clab.api.global.common.slack.domain.AlertType; + +@Getter +public class NotificationEvent extends ApplicationEvent { + + private final AlertType alertType; + + private final HttpServletRequest request; + + private final Object additionalData; + + public NotificationEvent(Object source, AlertType alertType, HttpServletRequest request, Object additionalData) { + super(source); + this.alertType = alertType; + this.request = request; + this.additionalData = additionalData; + } + +} diff --git a/src/main/java/page/clab/api/global/common/slack/exception/AlertTypeNotFoundException.java b/src/main/java/page/clab/api/global/common/slack/exception/AlertTypeNotFoundException.java new file mode 100644 index 000000000..e7ea55bf6 --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/exception/AlertTypeNotFoundException.java @@ -0,0 +1,9 @@ +package page.clab.api.global.common.slack.exception; + +public class AlertTypeNotFoundException extends RuntimeException { + + public AlertTypeNotFoundException(String alertTypeName) { + super("Unknown alert type: " + alertTypeName); + } + +} \ No newline at end of file diff --git a/src/main/java/page/clab/api/global/common/slack/listener/NotificationListener.java b/src/main/java/page/clab/api/global/common/slack/listener/NotificationListener.java new file mode 100644 index 000000000..9dac2e8fe --- /dev/null +++ b/src/main/java/page/clab/api/global/common/slack/listener/NotificationListener.java @@ -0,0 +1,30 @@ +package page.clab.api.global.common.slack.listener; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; +import page.clab.api.global.common.slack.application.NotificationSettingService; +import page.clab.api.global.common.slack.application.SlackServiceHelper; +import page.clab.api.global.common.slack.domain.AlertType; +import page.clab.api.global.common.slack.domain.NotificationSetting; +import page.clab.api.global.common.slack.event.NotificationEvent; + +@Component +@RequiredArgsConstructor +public class NotificationListener { + + private final NotificationSettingService settingService; + + private final SlackServiceHelper slackServiceHelper; + + @EventListener + public void handleNotificationEvent(NotificationEvent event) { + AlertType alertType = event.getAlertType(); + NotificationSetting setting = settingService.getOrCreateDefaultSetting(alertType); + + if (setting.isEnabled()) { + slackServiceHelper.sendSlackMessage(alertType, event.getRequest(), event.getAdditionalData()); + } + } + +} \ No newline at end of file diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index d42cc8b92..6970588fd 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -157,6 +157,8 @@ notNull.news.source=출처는 필수 입력 항목입니다. notNull.news.date=날짜는 필수 입력 항목입니다. notNull.notification.memberId=학번은 필수 입력 항목입니다. notNull.notification.content=내용은 필수 입력 항목입니다. +notNull.notificationSetting.alertType=알림 타입은 필수 입력 항목입니다. +notNull.notificationSetting.enabled=알림 활성화 여부는 필수 입력 항목입니다. notNull.product.name=제품명은 필수 입력 항목입니다. notNull.product.description=설명은 필수 입력 항목입니다. notNull.recruitment.startDate=시작 날짜는 필수 입력 항목입니다. From 2725396882401572b04bb848bc5a547e8f6c5bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=A1=EC=9E=AC=ED=9B=88?= <128021502+SongJaeHoonn@users.noreply.github.com> Date: Tue, 25 Jun 2024 23:42:54 +0900 Subject: [PATCH 12/47] =?UTF-8?q?=EB=AA=A8=EC=A7=91=EA=B3=B5=EA=B3=A0=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EC=9E=90=EB=8F=99=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1=20=EC=99=84=EB=A3=8C=20?= =?UTF-8?q?(#389)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 모집공고 상태 나타내는 enum 도입 #353 * feat: 모집 기간에 따라 자동으로 모집 상태 변경하는 로직 작성 #353 * refactor: 모집 상태 구현 로직 변경에 따른 DTO 수정 #353 * feat: 트랜잭션을 추상화한 인터페이스 빈으로 등록 #353 * refactor: 모집 상태 문자열 사이즈 관련 message 삭제 #353 * refactor: 모집 공고 수정 시에도 즉각적으로 상태 반영되도록 수정 #353 * refactor: 띄어쓰기 수정 #353 * refactor(Recruitment): 띄어쓰기 수정 --------- Co-authored-by: 한관희 <noop103@naver.com> --- .../application/RecruitmentService.java | 35 +++++++++++++++++++ .../recruitment/domain/Recruitment.java | 7 ++-- .../recruitment/domain/RecruitmentStatus.java | 17 +++++++++ .../dto/request/RecruitmentRequestDto.java | 5 --- .../request/RecruitmentUpdateRequestDto.java | 3 -- .../dto/response/RecruitmentResponseDto.java | 3 +- .../api/global/config/TransactionConfig.java | 16 +++++++++ src/main/resources/messages.properties | 1 - 8 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/recruitment/domain/RecruitmentStatus.java create mode 100644 src/main/java/page/clab/api/global/config/TransactionConfig.java diff --git a/src/main/java/page/clab/api/domain/recruitment/application/RecruitmentService.java b/src/main/java/page/clab/api/domain/recruitment/application/RecruitmentService.java index a6275550c..c4c01507d 100644 --- a/src/main/java/page/clab/api/domain/recruitment/application/RecruitmentService.java +++ b/src/main/java/page/clab/api/domain/recruitment/application/RecruitmentService.java @@ -1,13 +1,19 @@ package page.clab.api.domain.recruitment.application; +import jakarta.persistence.EntityManager; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.domain.recruitment.dao.RecruitmentRepository; import page.clab.api.domain.recruitment.domain.Recruitment; +import page.clab.api.domain.recruitment.domain.RecruitmentStatus; import page.clab.api.domain.recruitment.dto.request.RecruitmentRequestDto; import page.clab.api.domain.recruitment.dto.request.RecruitmentUpdateRequestDto; import page.clab.api.domain.recruitment.dto.response.RecruitmentResponseDto; @@ -15,6 +21,7 @@ import page.clab.api.global.exception.NotFoundException; import page.clab.api.global.validation.ValidationService; +import java.time.LocalDateTime; import java.util.List; @Service @@ -27,9 +34,16 @@ public class RecruitmentService { private final RecruitmentRepository recruitmentRepository; + private final PlatformTransactionManager transactionManager; + + private final EntityManager entityManager; + + private final TransactionDefinition transactionDefinition; + @Transactional public Long createRecruitment(RecruitmentRequestDto requestDto) { Recruitment recruitment = RecruitmentRequestDto.toEntity(requestDto); + updateRecruitmentStatusByRecruitment(recruitment); validationService.checkValid(recruitment); notificationService.sendNotificationToAllMembers("새로운 모집 공고가 등록되었습니다."); return recruitmentRepository.save(recruitment).getId(); @@ -55,6 +69,7 @@ public Long updateRecruitment(Long recruitmentId, RecruitmentUpdateRequestDto re Recruitment recruitment = getRecruitmentByIdOrThrow(recruitmentId); recruitment.update(requestDto); validationService.checkValid(recruitment); + updateRecruitmentStatusByRecruitment(recruitment); return recruitmentRepository.save(recruitment).getId(); } @@ -69,4 +84,24 @@ public Recruitment getRecruitmentByIdOrThrow(Long recruitmentId) { .orElseThrow(() -> new NotFoundException("해당 모집 공고가 존재하지 않습니다.")); } + @Scheduled(cron = "0 * * * * *") + public void updateRecruitmentStatus(){ + List<Recruitment> recruitments = recruitmentRepository.findAll(); + recruitments.forEach(this::updateRecruitmentStatusByRecruitment); + } + + public void updateRecruitmentStatusByRecruitment(Recruitment recruitment){ + TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition); + LocalDateTime now = LocalDateTime.now(); + RecruitmentStatus newStatus = RecruitmentStatus.OPEN; + if (now.isBefore(recruitment.getStartDate())) { + newStatus = RecruitmentStatus.UPCOMING; + } else if(now.isAfter(recruitment.getEndDate())) { + newStatus = RecruitmentStatus.CLOSED; + } + recruitment.updateStatus(newStatus); + entityManager.merge(recruitment); + transactionManager.commit(transactionStatus); + } + } diff --git a/src/main/java/page/clab/api/domain/recruitment/domain/Recruitment.java b/src/main/java/page/clab/api/domain/recruitment/domain/Recruitment.java index 7f689027c..a114029e6 100644 --- a/src/main/java/page/clab/api/domain/recruitment/domain/Recruitment.java +++ b/src/main/java/page/clab/api/domain/recruitment/domain/Recruitment.java @@ -52,15 +52,16 @@ public class Recruitment extends BaseEntity { private String target; @Column(nullable = false) - @Size(min = 1, message = "{size.recruitment.status}") - private String status; + @Enumerated(EnumType.STRING) + private RecruitmentStatus status; public void update(RecruitmentUpdateRequestDto recruitmentUpdateRequestDto) { Optional.ofNullable(recruitmentUpdateRequestDto.getStartDate()).ifPresent(this::setStartDate); Optional.ofNullable(recruitmentUpdateRequestDto.getEndDate()).ifPresent(this::setEndDate); Optional.ofNullable(recruitmentUpdateRequestDto.getApplicationType()).ifPresent(this::setApplicationType); Optional.ofNullable(recruitmentUpdateRequestDto.getTarget()).ifPresent(this::setTarget); - Optional.ofNullable(recruitmentUpdateRequestDto.getStatus()).ifPresent(this::setStatus); } + public void updateStatus(RecruitmentStatus status) { this.status = status; } + } diff --git a/src/main/java/page/clab/api/domain/recruitment/domain/RecruitmentStatus.java b/src/main/java/page/clab/api/domain/recruitment/domain/RecruitmentStatus.java new file mode 100644 index 000000000..bd77d7f86 --- /dev/null +++ b/src/main/java/page/clab/api/domain/recruitment/domain/RecruitmentStatus.java @@ -0,0 +1,17 @@ +package page.clab.api.domain.recruitment.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum RecruitmentStatus { + + UPCOMING("UPCOMING", "모집 예정"), + OPEN("OPEN", "모집중"), + CLOSED("CLOSED", "모집 종료"); + + private String key; + private String description; + +} diff --git a/src/main/java/page/clab/api/domain/recruitment/dto/request/RecruitmentRequestDto.java b/src/main/java/page/clab/api/domain/recruitment/dto/request/RecruitmentRequestDto.java index 7cbf3eff6..3dbe53273 100644 --- a/src/main/java/page/clab/api/domain/recruitment/dto/request/RecruitmentRequestDto.java +++ b/src/main/java/page/clab/api/domain/recruitment/dto/request/RecruitmentRequestDto.java @@ -29,17 +29,12 @@ public class RecruitmentRequestDto { @Schema(description = "대상", example = "2~3학년", required = true) private String target; - @NotNull(message = "{notNull.recruitment.status}") - @Schema(description = "상태", example = "종료", required = true) - private String status; - public static Recruitment toEntity(RecruitmentRequestDto requestDto) { return Recruitment.builder() .startDate(requestDto.getStartDate()) .endDate(requestDto.getEndDate()) .applicationType(requestDto.getApplicationType()) .target(requestDto.getTarget()) - .status(requestDto.getStatus()) .build(); } diff --git a/src/main/java/page/clab/api/domain/recruitment/dto/request/RecruitmentUpdateRequestDto.java b/src/main/java/page/clab/api/domain/recruitment/dto/request/RecruitmentUpdateRequestDto.java index 0a41652e8..a7579a794 100644 --- a/src/main/java/page/clab/api/domain/recruitment/dto/request/RecruitmentUpdateRequestDto.java +++ b/src/main/java/page/clab/api/domain/recruitment/dto/request/RecruitmentUpdateRequestDto.java @@ -23,7 +23,4 @@ public class RecruitmentUpdateRequestDto { @Schema(description = "대상", example = "2~3학년") private String target; - @Schema(description = "상태", example = "종료") - private String status; - } diff --git a/src/main/java/page/clab/api/domain/recruitment/dto/response/RecruitmentResponseDto.java b/src/main/java/page/clab/api/domain/recruitment/dto/response/RecruitmentResponseDto.java index f619b6b93..18f42adc6 100644 --- a/src/main/java/page/clab/api/domain/recruitment/dto/response/RecruitmentResponseDto.java +++ b/src/main/java/page/clab/api/domain/recruitment/dto/response/RecruitmentResponseDto.java @@ -4,6 +4,7 @@ import lombok.Getter; import page.clab.api.domain.application.domain.ApplicationType; import page.clab.api.domain.recruitment.domain.Recruitment; +import page.clab.api.domain.recruitment.domain.RecruitmentStatus; import java.time.LocalDateTime; @@ -21,7 +22,7 @@ public class RecruitmentResponseDto { private String target; - private String status; + private RecruitmentStatus status; private LocalDateTime updatedAt; diff --git a/src/main/java/page/clab/api/global/config/TransactionConfig.java b/src/main/java/page/clab/api/global/config/TransactionConfig.java new file mode 100644 index 000000000..74753ce61 --- /dev/null +++ b/src/main/java/page/clab/api/global/config/TransactionConfig.java @@ -0,0 +1,16 @@ +package page.clab.api.global.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.support.DefaultTransactionDefinition; + +@Configuration +public class TransactionConfig { + + @Bean + public TransactionDefinition transactionDefinition() { + return new DefaultTransactionDefinition(); + } + +} diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 6970588fd..5d1a5a4ad 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -44,7 +44,6 @@ size.product.name=서비스명은 최소 {min}글자 이상이어야 합니다. size.product.description=설명은 최소 {min}글자에서 {max}글자 사이어야 합니다. size.recruitment.applicationType=신청 유형은 최소 {min}자 이상이어야 합니다. size.recruitment.target=대상은 최소 {min}자 이상이어야 합니다. -size.recruitment.status=상태는 최소 {min}자 이상이어야 합니다. size.review.content=내용은 {min}자 이상 {max}자 이하여야 합니다. size.sharedAccount.username=유저명은 {min}자 이상이어야 합니다. size.sharedAccount.password=비밀번호는 {min}자 이상이어야 합니다. From 3d206acf6cf0f99d79b4621868d249c46757791d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Sun, 23 Jun 2024 04:36:03 +0900 Subject: [PATCH 13/47] =?UTF-8?q?refactor(Member):=20MemberLookupService?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accuse/application/AccuseService.java | 8 +- .../ActivityGroupAdminService.java | 18 ++--- .../ActivityGroupBoardService.java | 16 ++-- .../ActivityGroupMemberService.java | 10 +-- .../ActivityGroupReportService.java | 10 +-- .../application/AttendanceService.java | 16 ++-- .../award/application/AwardService.java | 12 +-- .../domain/blog/application/BlogService.java | 14 ++-- .../board/application/BoardService.java | 16 ++-- .../application/BookLoanRecordService.java | 12 +-- .../comment/application/CommentService.java | 20 ++--- .../donation/application/DonationService.java | 12 +-- .../application/AccountLockInfoService.java | 15 ++-- .../login/application/LoginService.java | 12 +-- .../application/MemberLookupService.java | 28 +++++++ .../application/MemberLookupServiceImpl.java | 78 ++++++++++++++++++ .../member/application/MemberService.java | 81 +++---------------- .../domain/member/dao/MemberRepository.java | 2 +- .../application/MembershipFeeService.java | 14 ++-- .../application/NotificationService.java | 25 +++--- .../position/application/PositionService.java | 8 +- .../review/application/ReviewService.java | 16 ++-- .../schedule/application/ScheduleService.java | 12 +-- .../SharedAccountUsageService.java | 8 +- .../application/WorkExperienceService.java | 14 ++-- .../email/application/EmailService.java | 8 +- .../common/file/application/FileService.java | 14 ++-- 27 files changed, 268 insertions(+), 231 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/member/application/MemberLookupService.java create mode 100644 src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java index ee3454436..668bf358c 100644 --- a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java @@ -23,7 +23,7 @@ import page.clab.api.domain.board.domain.Board; import page.clab.api.domain.comment.application.CommentService; import page.clab.api.domain.comment.domain.Comment; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.domain.review.application.ReviewService; @@ -39,7 +39,7 @@ @Slf4j public class AccuseService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final BoardService boardService; @@ -59,7 +59,7 @@ public class AccuseService { public Long createAccuse(AccuseRequestDto requestDto) { TargetType type = requestDto.getTargetType(); Long targetId = requestDto.getTargetId(); - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); validateAccuseRequest(type, targetId, currentMember); @@ -84,7 +84,7 @@ public PagedResponseDto<AccuseResponseDto> getAccusesByConditions(TargetType typ @Transactional(readOnly = true) public PagedResponseDto<AccuseMyResponseDto> getMyAccuses(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Accuse> accuses = accuseRepository.findByMember(currentMember, pageable); return new PagedResponseDto<>(accuses.map(AccuseMyResponseDto::toDto)); } diff --git a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupAdminService.java b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupAdminService.java index 1c716c78b..6a9182b35 100644 --- a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupAdminService.java +++ b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupAdminService.java @@ -21,7 +21,7 @@ import page.clab.api.domain.activityGroup.dto.request.ActivityGroupUpdateRequestDto; import page.clab.api.domain.activityGroup.dto.response.ActivityGroupMemberWithApplyReasonResponseDto; import page.clab.api.domain.activityGroup.dto.response.ActivityGroupResponseDto; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.global.common.dto.PagedResponseDto; @@ -37,7 +37,7 @@ @RequiredArgsConstructor public class ActivityGroupAdminService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final ActivityGroupMemberService activityGroupMemberService; @@ -53,7 +53,7 @@ public class ActivityGroupAdminService { @Transactional public Long createActivityGroup(ActivityGroupRequestDto requestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = ActivityGroupRequestDto.toEntity(requestDto); validationService.checkValid(activityGroup); activityGroupRepository.save(activityGroup); @@ -68,7 +68,7 @@ public Long createActivityGroup(ActivityGroupRequestDto requestDto) { @Transactional public Long updateActivityGroup(Long activityGroupId, ActivityGroupUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = getActivityGroupByIdOrThrow(activityGroupId); if (!isMemberGroupLeaderRole(activityGroup, currentMember)) { throw new PermissionDeniedException("해당 활동을 수정할 권한이 없습니다."); @@ -117,7 +117,7 @@ public Long deleteActivityGroup(Long activityGroupId) { @Transactional public Long updateProjectProgress(Long activityGroupId, Long progress) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = getActivityGroupByIdOrThrow(activityGroupId); if (!isMemberGroupLeaderRole(activityGroup, currentMember)) { throw new PermissionDeniedException("해당 활동을 수정할 권한이 없습니다."); @@ -129,7 +129,7 @@ public Long updateProjectProgress(Long activityGroupId, Long progress) throws Pe @Transactional public Long addSchedule(Long activityGroupId, List<GroupScheduleDto> scheduleDtos) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = getActivityGroupByIdOrThrow(activityGroupId); if (!isMemberGroupLeaderRole(activityGroup, currentMember)) { throw new PermissionDeniedException("해당 일정을 등록할 권한이 없습니다."); @@ -143,7 +143,7 @@ public Long addSchedule(Long activityGroupId, List<GroupScheduleDto> scheduleDto @Transactional(readOnly = true) public PagedResponseDto<ActivityGroupMemberWithApplyReasonResponseDto> getGroupMembersWithApplyReason(Long activityGroupId, Pageable pageable) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = getActivityGroupByIdOrThrow(activityGroupId); if (!(isMemberGroupLeaderRole(activityGroup, currentMember) || currentMember.isAdminRole())) { throw new PermissionDeniedException("해당 활동의 멤버를 조회할 권한이 없습니다."); @@ -168,13 +168,13 @@ public PagedResponseDto<ActivityGroupMemberWithApplyReasonResponseDto> getGroupM @Transactional public String manageGroupMemberStatus(Long activityGroupId, String memberId, GroupMemberStatus status) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = getActivityGroupByIdOrThrow(activityGroupId); if (!isMemberGroupLeaderRole(activityGroup, currentMember)) { throw new PermissionDeniedException("해당 활동의 신청 멤버를 조회할 권한이 없습니다."); } - Member member = memberService.getMemberByIdOrThrow(memberId); + Member member = memberLookupService.getMemberByIdOrThrow(memberId); GroupMember groupMember = activityGroupMemberService.getGroupMemberByActivityGroupAndMemberOrThrow(activityGroup, member); groupMember.validateAccessPermission(); groupMember.updateStatus(status); diff --git a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupBoardService.java b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupBoardService.java index c5f6ca403..e855dfcd9 100644 --- a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupBoardService.java +++ b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupBoardService.java @@ -21,9 +21,7 @@ import page.clab.api.domain.activityGroup.dto.response.AssignmentSubmissionWithFeedbackResponseDto; import page.clab.api.domain.activityGroup.dto.response.FeedbackResponseDto; import page.clab.api.domain.activityGroup.exception.InvalidParentBoardException; -import page.clab.api.domain.award.domain.Award; -import page.clab.api.domain.award.dto.response.AwardResponseDto; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.global.common.dto.PagedResponseDto; @@ -43,7 +41,7 @@ public class ActivityGroupBoardService { private final ActivityGroupBoardRepository activityGroupBoardRepository; - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final ActivityGroupAdminService activityGroupAdminService; @@ -57,7 +55,7 @@ public class ActivityGroupBoardService { @Transactional public Long createActivityGroupBoard(Long parentId, Long activityGroupId, ActivityGroupBoardRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = activityGroupAdminService.getActivityGroupByIdOrThrow(activityGroupId); if (!activityGroupMemberService.isGroupMember(activityGroup, currentMember)) { throw new PermissionDeniedException("활동 그룹 멤버만 게시글을 등록할 수 있습니다."); @@ -99,7 +97,7 @@ public PagedResponseDto<ActivityGroupBoardResponseDto> getActivityGroupBoardByCa @Transactional(readOnly = true) public PagedResponseDto<ActivityGroupBoardChildResponseDto> getActivityGroupBoardByParent(Long parentId, Pageable pageable) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroupBoard parentBoard = getActivityGroupBoardByIdOrThrow(parentId); Long activityGroupId = parentBoard.getActivityGroup().getId(); @@ -113,7 +111,7 @@ public PagedResponseDto<ActivityGroupBoardChildResponseDto> getActivityGroupBoar @Transactional(readOnly = true) public List<AssignmentSubmissionWithFeedbackResponseDto> getMyAssignmentsWithFeedbacks(Long parentId) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroupBoard parentBoard = getActivityGroupBoardByIdOrThrow(parentId); List<ActivityGroupBoard> mySubmissions = activityGroupBoardRepository.findMySubmissionsWithFeedbacks(parentId, currentMember.getId()); return mySubmissions.stream() @@ -129,7 +127,7 @@ public List<AssignmentSubmissionWithFeedbackResponseDto> getMyAssignmentsWithFee @Transactional public ActivityGroupBoardUpdateResponseDto updateActivityGroupBoard(Long activityGroupBoardId, ActivityGroupBoardUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroupBoard board = getActivityGroupBoardByIdOrThrow(activityGroupBoardId); board.validateAccessPermission(currentMember); @@ -140,7 +138,7 @@ public ActivityGroupBoardUpdateResponseDto updateActivityGroupBoard(Long activit } public Long deleteActivityGroupBoard(Long activityGroupBoardId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroupBoard board = getActivityGroupBoardByIdOrThrow(activityGroupBoardId); board.validateAccessPermission(currentMember); activityGroupBoardRepository.delete(board); diff --git a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupMemberService.java b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupMemberService.java index 9def6f236..1a29b50c0 100644 --- a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupMemberService.java +++ b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupMemberService.java @@ -31,7 +31,7 @@ import page.clab.api.domain.activityGroup.dto.response.GroupMemberResponseDto; import page.clab.api.domain.activityGroup.exception.AlreadyAppliedException; import page.clab.api.domain.activityGroup.exception.InvalidCategoryException; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.global.common.dto.PagedResponseDto; @@ -44,7 +44,7 @@ @Slf4j public class ActivityGroupMemberService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final NotificationService notificationService; @@ -69,7 +69,7 @@ public PagedResponseDto<ActivityGroupResponseDto> getActivityGroups(Pageable pag @Transactional(readOnly = true) public Object getActivityGroup(Long activityGroupId) { ActivityGroupDetails details = activityGroupDetailsRepository.fetchActivityGroupDetails(activityGroupId); - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); boolean isOwner = details.getGroupMembers().stream() .anyMatch(groupMember -> groupMember.isOwnerAndLeader(currentMember)); @@ -85,7 +85,7 @@ public Object getActivityGroup(Long activityGroupId) { @Transactional(readOnly = true) public PagedResponseDto<ActivityGroupResponseDto> getMyActivityGroups(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); List<GroupMember> groupMembers = getGroupMemberByMember(currentMember); List<ActivityGroupResponseDto> activityGroups = groupMembers.stream() @@ -134,7 +134,7 @@ public PagedResponseDto<GroupMemberResponseDto> getActivityGroupMembers(Long act @Transactional public Long applyActivityGroup(Long activityGroupId, ApplyFormRequestDto formRequestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = getActivityGroupByIdOrThrow(activityGroupId); activityGroup.validateForApplication(); if (isGroupMember(activityGroup, currentMember)) { diff --git a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupReportService.java b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupReportService.java index d8cf467e3..95f21cce5 100644 --- a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupReportService.java +++ b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupReportService.java @@ -14,7 +14,7 @@ import page.clab.api.domain.activityGroup.dto.request.ActivityGroupReportUpdateRequestDto; import page.clab.api.domain.activityGroup.dto.response.ActivityGroupReportResponseDto; import page.clab.api.domain.activityGroup.exception.DuplicateReportException; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; @@ -27,7 +27,7 @@ public class ActivityGroupReportService { private final ActivityGroupAdminService activityGroupAdminService; - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final ValidationService validationService; @@ -35,7 +35,7 @@ public class ActivityGroupReportService { @Transactional public Long writeReport(ActivityGroupReportRequestDto requestDto) throws PermissionDeniedException, IllegalAccessException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Long activityGroupId = requestDto.getActivityGroupId(); ActivityGroup activityGroup = activityGroupAdminService.validateAndGetActivityGroupForReporting(activityGroupId, currentMember); ActivityGroupReport report = validateReportCreationPermission(requestDto, activityGroup); @@ -59,7 +59,7 @@ public ActivityGroupReportResponseDto searchReport(Long activityGroupId, Long tu @Transactional public Long updateReport(Long reportId, Long activityGroupId, ActivityGroupReportUpdateRequestDto requestDto) throws PermissionDeniedException, IllegalAccessException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = activityGroupAdminService.getActivityGroupByIdOrThrow(activityGroupId); validateReportUpdatePermission(activityGroupId, currentMember, activityGroup); ActivityGroupReport report = getReportByIdOrThrow(reportId); @@ -69,7 +69,7 @@ public Long updateReport(Long reportId, Long activityGroupId, ActivityGroupRepor } public Long deleteReport(Long reportId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroupReport report = validateReportDeletionPermission(reportId, currentMember); activityGroupReportRepository.delete(report); return report.getId(); diff --git a/src/main/java/page/clab/api/domain/activityGroup/application/AttendanceService.java b/src/main/java/page/clab/api/domain/activityGroup/application/AttendanceService.java index bda17cced..02698ce0d 100644 --- a/src/main/java/page/clab/api/domain/activityGroup/application/AttendanceService.java +++ b/src/main/java/page/clab/api/domain/activityGroup/application/AttendanceService.java @@ -23,7 +23,7 @@ import page.clab.api.domain.activityGroup.exception.DuplicateAttendanceException; import page.clab.api.domain.login.dao.RedisQRKeyRepository; import page.clab.api.domain.login.domain.RedisQRKey; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.common.file.application.FileService; @@ -43,7 +43,7 @@ @Slf4j public class AttendanceService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final FileService fileService; @@ -63,7 +63,7 @@ public class AttendanceService { @Transactional public String generateAttendanceQRCode(Long activityGroupId) throws IOException, WriterException, PermissionDeniedException, IllegalAccessException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = validateAttendanceQRCodeGeneration(activityGroupId, currentMember); String nowDateTime = LocalDateTime.now().format(dateTimeFormatter); @@ -82,7 +82,7 @@ public String generateAttendanceQRCode(Long activityGroupId) throws IOException, @Transactional public Long checkMemberAttendance(AttendanceRequestDto requestDto) throws IllegalAccessException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = validateMemberForAttendance(currentMember, requestDto.getActivityGroupId()); validateQRCodeData(requestDto.getQRCodeSecretKey()); Attendance attendance = Attendance.create(currentMember, activityGroup, LocalDate.now()); @@ -91,7 +91,7 @@ public Long checkMemberAttendance(AttendanceRequestDto requestDto) throws Illega @Transactional(readOnly = true) public PagedResponseDto<AttendanceResponseDto> getMyAttendances(Long activityGroupId, Pageable pageable) throws IllegalAccessException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = validateGroupAndMemberForAttendance(activityGroupId, currentMember); Page<Attendance> attendances = getAttendanceByMember(activityGroup, currentMember, pageable); return new PagedResponseDto<>(attendances.map(AttendanceResponseDto::toDto)); @@ -99,7 +99,7 @@ public PagedResponseDto<AttendanceResponseDto> getMyAttendances(Long activityGro @Transactional(readOnly = true) public PagedResponseDto<AttendanceResponseDto> getGroupAttendances(Long activityGroupId, Pageable pageable) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = getActivityGroupWithValidPermissions(activityGroupId, currentMember); Page<Attendance> attendances = getAttendanceByActivityGroup(activityGroup, pageable); return new PagedResponseDto<>(attendances.map(AttendanceResponseDto::toDto)); @@ -107,7 +107,7 @@ public PagedResponseDto<AttendanceResponseDto> getGroupAttendances(Long activity @Transactional public Long writeAbsentExcuse(AbsentRequestDto requestDto) throws IllegalAccessException, DuplicateAbsentExcuseException { - Member absentee = memberService.getMemberByIdOrThrow(requestDto.getAbsenteeId()); + Member absentee = memberLookupService.getMemberByIdOrThrow(requestDto.getAbsenteeId()); ActivityGroup activityGroup = getValidActivityGroup(requestDto.getActivityGroupId()); validateAbsentExcuseConditions(absentee, activityGroup, requestDto.getAbsentDate()); Absent absent = AbsentRequestDto.toEntity(requestDto, absentee, activityGroup); @@ -116,7 +116,7 @@ public Long writeAbsentExcuse(AbsentRequestDto requestDto) throws IllegalAccessE @Transactional(readOnly = true) public PagedResponseDto<AbsentResponseDto> getActivityGroupAbsentExcuses(Long activityGroupId, Pageable pageable) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = getActivityGroupWithPermissionCheck(activityGroupId, currentMember); Page<Absent> absents = absentRepository.findAllByActivityGroup(activityGroup, pageable); return new PagedResponseDto<>(absents.map(AbsentResponseDto::toDto)); diff --git a/src/main/java/page/clab/api/domain/award/application/AwardService.java b/src/main/java/page/clab/api/domain/award/application/AwardService.java index fadd17df8..cfa5a2260 100644 --- a/src/main/java/page/clab/api/domain/award/application/AwardService.java +++ b/src/main/java/page/clab/api/domain/award/application/AwardService.java @@ -10,7 +10,7 @@ import page.clab.api.domain.award.dto.request.AwardRequestDto; import page.clab.api.domain.award.dto.request.AwardUpdateRequestDto; import page.clab.api.domain.award.dto.response.AwardResponseDto; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; @@ -21,7 +21,7 @@ @RequiredArgsConstructor public class AwardService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final ValidationService validationService; @@ -29,7 +29,7 @@ public class AwardService { @Transactional public Long createAward(AwardRequestDto requestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Award award = AwardRequestDto.toEntity(requestDto, currentMember); validationService.checkValid(award); return awardRepository.save(award).getId(); @@ -43,14 +43,14 @@ public PagedResponseDto<AwardResponseDto> getAwardsByConditions(String memberId, @Transactional(readOnly = true) public PagedResponseDto<AwardResponseDto> getMyAwards(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Award> awards = getAwardByMember(pageable, currentMember); return new PagedResponseDto<>(awards.map(AwardResponseDto::toDto)); } @Transactional public Long updateAward(Long awardId, AwardUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Award award = getAwardByIdOrThrow(awardId); award.validateAccessPermission(currentMember); award.update(requestDto); @@ -59,7 +59,7 @@ public Long updateAward(Long awardId, AwardUpdateRequestDto requestDto) throws P } public Long deleteAward(Long awardId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Award award = getAwardByIdOrThrow(awardId); award.validateAccessPermission(currentMember); awardRepository.delete(award); diff --git a/src/main/java/page/clab/api/domain/blog/application/BlogService.java b/src/main/java/page/clab/api/domain/blog/application/BlogService.java index 0abc22dac..1119a5c6d 100644 --- a/src/main/java/page/clab/api/domain/blog/application/BlogService.java +++ b/src/main/java/page/clab/api/domain/blog/application/BlogService.java @@ -11,7 +11,7 @@ import page.clab.api.domain.blog.dto.request.BlogUpdateRequestDto; import page.clab.api.domain.blog.dto.response.BlogDetailsResponseDto; import page.clab.api.domain.blog.dto.response.BlogResponseDto; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; @@ -22,7 +22,7 @@ @RequiredArgsConstructor public class BlogService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final ValidationService validationService; @@ -30,7 +30,7 @@ public class BlogService { @Transactional public Long createBlog(BlogRequestDto requestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Blog blog = BlogRequestDto.toEntity(requestDto, currentMember); validationService.checkValid(blog); return blogRepository.save(blog).getId(); @@ -44,7 +44,7 @@ public PagedResponseDto<BlogResponseDto> getBlogsByConditions(String title, Stri @Transactional(readOnly = true) public BlogDetailsResponseDto getBlogDetails(Long blogId) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Blog blog = getBlogByIdOrThrow(blogId); boolean isOwner = blog.isOwner(currentMember); return BlogDetailsResponseDto.toDto(blog, isOwner); @@ -52,7 +52,7 @@ public BlogDetailsResponseDto getBlogDetails(Long blogId) { @Transactional(readOnly = true) public PagedResponseDto<BlogDetailsResponseDto> getDeletedBlogs(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Blog> blogs = blogRepository.findAllByIsDeletedTrue(pageable); return new PagedResponseDto<>(blogs .map(blog -> BlogDetailsResponseDto.toDto(blog, blog.isOwner(currentMember)))); @@ -60,7 +60,7 @@ public PagedResponseDto<BlogDetailsResponseDto> getDeletedBlogs(Pageable pageabl @Transactional public Long updateBlog(Long blogId, BlogUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Blog blog = getBlogByIdOrThrow(blogId); blog.validateAccessPermission(currentMember); blog.update(requestDto); @@ -69,7 +69,7 @@ public Long updateBlog(Long blogId, BlogUpdateRequestDto requestDto) throws Perm } public Long deleteBlog(Long blogId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Blog blog = getBlogByIdOrThrow(blogId); blog.validateAccessPermission(currentMember); blogRepository.delete(blog); diff --git a/src/main/java/page/clab/api/domain/board/application/BoardService.java b/src/main/java/page/clab/api/domain/board/application/BoardService.java index 4c9427fda..8d4b27eaf 100644 --- a/src/main/java/page/clab/api/domain/board/application/BoardService.java +++ b/src/main/java/page/clab/api/domain/board/application/BoardService.java @@ -18,7 +18,7 @@ import page.clab.api.domain.board.dto.response.BoardListResponseDto; import page.clab.api.domain.board.dto.response.BoardMyResponseDto; import page.clab.api.domain.comment.dao.CommentRepository; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.global.common.dto.PagedResponseDto; @@ -36,7 +36,7 @@ @RequiredArgsConstructor public class BoardService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final NotificationService notificationService; @@ -54,7 +54,7 @@ public class BoardService { @Transactional public String createBoard(BoardRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); List<UploadedFile> uploadedFiles = uploadedFileService.getUploadedFilesByUrls(requestDto.getFileUrlList()); Board board = BoardRequestDto.toEntity(requestDto, currentMember, uploadedFiles); board.validateAccessPermissionForCreation(currentMember); @@ -74,7 +74,7 @@ public PagedResponseDto<BoardListResponseDto> getBoards(Pageable pageable) { @Transactional(readOnly = true) public BoardDetailsResponseDto getBoardDetails(Long boardId) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Board board = getBoardByIdOrThrow(boardId); boolean hasLikeByMe = checkLikeStatus(board, currentMember); boolean isOwner = board.isOwner(currentMember); @@ -83,7 +83,7 @@ public BoardDetailsResponseDto getBoardDetails(Long boardId) { @Transactional(readOnly = true) public PagedResponseDto<BoardMyResponseDto> getMyBoards(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Board> boards = getBoardByMember(pageable, currentMember); return new PagedResponseDto<>(boards.map(BoardMyResponseDto::toDto)); } @@ -96,7 +96,7 @@ public PagedResponseDto<BoardCategoryResponseDto> getBoardsByCategory(BoardCateg @Transactional public String updateBoard(Long boardId, BoardUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Board board = getBoardByIdOrThrow(boardId); board.validateAccessPermission(currentMember); board.update(requestDto); @@ -106,7 +106,7 @@ public String updateBoard(Long boardId, BoardUpdateRequestDto requestDto) throws @Transactional public Long toggleLikeStatus(Long boardId) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Board board = getBoardByIdOrThrow(boardId); Optional<BoardLike> boardLikeOpt = boardLikeRepository.findByBoardIdAndMemberId(board.getId(), currentMember.getId()); if (boardLikeOpt.isPresent()) { @@ -128,7 +128,7 @@ public PagedResponseDto<BoardListResponseDto> getDeletedBoards(Pageable pageable } public String deleteBoard(Long boardId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Board board = getBoardByIdOrThrow(boardId); board.validateAccessPermission(currentMember); boardRepository.delete(board); diff --git a/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java b/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java index 352214c4c..900781678 100644 --- a/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java +++ b/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java @@ -16,7 +16,7 @@ import page.clab.api.domain.book.dto.response.BookLoanRecordResponseDto; import page.clab.api.domain.book.exception.BookAlreadyAppliedForLoanException; import page.clab.api.domain.book.exception.MaxBorrowLimitExceededException; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.global.common.dto.PagedResponseDto; @@ -30,7 +30,7 @@ public class BookLoanRecordService { private final BookService bookService; - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final NotificationService notificationService; @@ -43,7 +43,7 @@ public class BookLoanRecordService { @Transactional public Long requestBookLoan(BookLoanRecordRequestDto requestDto) throws CustomOptimisticLockingFailureException { try { - Member borrower = memberService.getCurrentMember(); + Member borrower = memberLookupService.getCurrentMember(); borrower.checkLoanSuspension(); validateBorrowLimit(borrower); @@ -63,7 +63,7 @@ public Long requestBookLoan(BookLoanRecordRequestDto requestDto) throws CustomOp @Transactional public Long returnBook(BookLoanRecordRequestDto requestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Book book = bookService.getBookByIdOrThrow(requestDto.getBookId()); book.returnBook(currentMember); bookRepository.save(book); @@ -78,7 +78,7 @@ public Long returnBook(BookLoanRecordRequestDto requestDto) { @Transactional public Long extendBookLoan(BookLoanRecordRequestDto requestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Book book = bookService.getBookByIdOrThrow(requestDto.getBookId()); book.validateCurrentBorrower(currentMember); @@ -93,7 +93,7 @@ public Long extendBookLoan(BookLoanRecordRequestDto requestDto) { @Transactional public Long approveBookLoan(Long bookLoanRecordId) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); BookLoanRecord bookLoanRecord = getBookLoanRecordByIdOrThrow(bookLoanRecordId); Book book = bookService.getBookByIdOrThrow(bookLoanRecord.getBook().getId()); diff --git a/src/main/java/page/clab/api/domain/comment/application/CommentService.java b/src/main/java/page/clab/api/domain/comment/application/CommentService.java index f2c579e72..575f5ee78 100644 --- a/src/main/java/page/clab/api/domain/comment/application/CommentService.java +++ b/src/main/java/page/clab/api/domain/comment/application/CommentService.java @@ -1,6 +1,5 @@ package page.clab.api.domain.comment.application; -import java.util.Comparator; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.hibernate.Hibernate; @@ -19,7 +18,7 @@ import page.clab.api.domain.comment.dto.response.CommentMyResponseDto; import page.clab.api.domain.comment.dto.response.CommentResponseDto; import page.clab.api.domain.comment.dto.response.DeletedCommentResponseDto; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.global.common.dto.PagedResponseDto; @@ -27,6 +26,7 @@ import page.clab.api.global.exception.PermissionDeniedException; import page.clab.api.global.validation.ValidationService; +import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -38,7 +38,7 @@ public class CommentService { private final BoardService boardService; - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final NotificationService notificationService; @@ -57,7 +57,7 @@ public Long createComment(Long parentId, Long boardId, CommentRequestDto request @Transactional(readOnly = true) public PagedResponseDto<CommentResponseDto> getAllComments(Long boardId, Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Comment> comments = getCommentByBoardIdAndParentIsNull(boardId, pageable); comments.forEach(comment -> { Hibernate.initialize(comment.getChildren()); @@ -69,7 +69,7 @@ public PagedResponseDto<CommentResponseDto> getAllComments(Long boardId, Pageabl @Transactional(readOnly = true) public PagedResponseDto<CommentMyResponseDto> getMyComments(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Comment> comments = getCommentByWriter(currentMember, pageable); List<CommentMyResponseDto> dtos = comments .map(comment -> toCommentMyResponseDto(comment, currentMember)) @@ -81,14 +81,14 @@ public PagedResponseDto<CommentMyResponseDto> getMyComments(Pageable pageable) { @Transactional(readOnly = true) public PagedResponseDto<DeletedCommentResponseDto> getDeletedComments(Long boardId, Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Comment> comments = commentRepository.findAllByIsDeletedTrueAndBoardId(boardId, pageable); return new PagedResponseDto<>(comments.map(comment -> DeletedCommentResponseDto.toDto(comment, currentMember.getId()))); } @Transactional public Long updateComment(Long commentId, CommentUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Comment comment = getCommentByIdOrThrow(commentId); comment.validateAccessPermission(currentMember); comment.update(requestDto); @@ -98,7 +98,7 @@ public Long updateComment(Long commentId, CommentUpdateRequestDto requestDto) th } public Long deleteComment(Long commentId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Comment comment = getCommentByIdOrThrow(commentId); comment.validateAccessPermission(currentMember); comment.updateIsDeleted(); @@ -108,7 +108,7 @@ public Long deleteComment(Long commentId) throws PermissionDeniedException { @Transactional public Long toggleLikeStatus(Long commentId) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Comment comment = getCommentByIdOrThrow(commentId); Optional<CommentLike> commentLikeOpt = commentLikeRepository.findByCommentIdAndMemberId(comment.getId(), currentMember.getId()); if (commentLikeOpt.isPresent()) { @@ -136,7 +136,7 @@ private Page<Comment> getCommentByWriter(Member member, Pageable pageable) { } private Comment createAndStoreComment(Long parentId, Long boardId, CommentRequestDto requestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Board board = boardService.getBoardByIdOrThrow(boardId); Comment parent = findParentComment(parentId); Comment comment = CommentRequestDto.toEntity(requestDto, board, currentMember, parent); diff --git a/src/main/java/page/clab/api/domain/donation/application/DonationService.java b/src/main/java/page/clab/api/domain/donation/application/DonationService.java index 398afb924..5073239e2 100644 --- a/src/main/java/page/clab/api/domain/donation/application/DonationService.java +++ b/src/main/java/page/clab/api/domain/donation/application/DonationService.java @@ -10,7 +10,7 @@ import page.clab.api.domain.donation.dto.request.DonationRequestDto; import page.clab.api.domain.donation.dto.request.DonationUpdateRequestDto; import page.clab.api.domain.donation.dto.response.DonationResponseDto; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; @@ -23,7 +23,7 @@ @RequiredArgsConstructor public class DonationService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final ValidationService validationService; @@ -31,7 +31,7 @@ public class DonationService { @Transactional public Long createDonation(DonationRequestDto requestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Donation donation = DonationRequestDto.toEntity(requestDto, currentMember); validationService.checkValid(donation); return donationRepository.save(donation).getId(); @@ -45,7 +45,7 @@ public PagedResponseDto<DonationResponseDto> getDonationsByConditions(String mem @Transactional(readOnly = true) public PagedResponseDto<DonationResponseDto> getMyDonations(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Donation> donations = getDonationsByDonor(currentMember, pageable); return new PagedResponseDto<>(donations.map(DonationResponseDto::toDto)); } @@ -58,7 +58,7 @@ public PagedResponseDto<DonationResponseDto> getDeletedDonations(Pageable pageab @Transactional public Long updateDonation(Long donationId, DonationUpdateRequestDto donationUpdateRequestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Donation donation = getDonationByIdOrThrow(donationId); validateDonationUpdatePermission(currentMember); donation.update(donationUpdateRequestDto); @@ -67,7 +67,7 @@ public Long updateDonation(Long donationId, DonationUpdateRequestDto donationUpd } public Long deleteDonation(Long donationId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Donation donation = getDonationByIdOrThrow(donationId); validateDonationUpdatePermission(currentMember); donationRepository.delete(donation); diff --git a/src/main/java/page/clab/api/domain/login/application/AccountLockInfoService.java b/src/main/java/page/clab/api/domain/login/application/AccountLockInfoService.java index f372ec533..49cdebda2 100644 --- a/src/main/java/page/clab/api/domain/login/application/AccountLockInfoService.java +++ b/src/main/java/page/clab/api/domain/login/application/AccountLockInfoService.java @@ -13,7 +13,7 @@ import page.clab.api.domain.login.dto.response.AccountLockInfoResponseDto; import page.clab.api.domain.login.exception.LoginFaliedException; import page.clab.api.domain.login.exception.MemberLockedException; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.common.slack.application.SlackService; @@ -26,7 +26,7 @@ @Slf4j public class AccountLockInfoService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final SlackService slackService; @@ -42,7 +42,7 @@ public class AccountLockInfoService { @Transactional public Long banMemberById(HttpServletRequest request, String memberId) { - Member member = memberService.getMemberById(memberId); + Member member = memberLookupService.getMemberById(memberId); AccountLockInfo accountLockInfo = ensureAccountLockInfo(member); accountLockInfo.banPermanently(); redisTokenService.deleteRedisTokenByMemberId(memberId); @@ -52,7 +52,7 @@ public Long banMemberById(HttpServletRequest request, String memberId) { @Transactional public Long unbanMemberById(HttpServletRequest request, String memberId) { - Member member = memberService.getMemberById(memberId); + Member member = memberLookupService.getMemberById(memberId); AccountLockInfo accountLockInfo = ensureAccountLockInfo(member); accountLockInfo.unban(); slackService.sendSecurityAlertNotification(request, SecurityAlertType.MEMBER_UNBANNED, "ID: " + member.getId() + ", Name: " + member.getName()); @@ -76,7 +76,7 @@ public void handleAccountLockInfo(String memberId) throws MemberLockedException, @Transactional public void handleLoginFailure(HttpServletRequest request, String memberId) throws MemberLockedException, LoginFaliedException { - Member member = memberService.getMemberById(memberId); + Member member = memberLookupService.getMemberById(memberId); AccountLockInfo accountLockInfo = ensureAccountLockInfoForMemberId(memberId); validateAccountLockStatus(accountLockInfo); accountLockInfo.incrementLoginFailCount(); @@ -99,7 +99,10 @@ private AccountLockInfo ensureAccountLockInfo(Member member) { } private AccountLockInfo ensureAccountLockInfoForMemberId(String memberId) throws LoginFaliedException { - Member member = memberService.getMemberByIdOrThrowLoginFailed(memberId); + Member member = memberLookupService.getMemberById(memberId); + if (member == null) { + throw new LoginFaliedException(); + } return ensureAccountLockInfo(member); } diff --git a/src/main/java/page/clab/api/domain/login/application/LoginService.java b/src/main/java/page/clab/api/domain/login/application/LoginService.java index e076d494a..f9a243ef0 100644 --- a/src/main/java/page/clab/api/domain/login/application/LoginService.java +++ b/src/main/java/page/clab/api/domain/login/application/LoginService.java @@ -20,7 +20,7 @@ import page.clab.api.domain.login.dto.response.TokenInfo; import page.clab.api.domain.login.exception.LoginFaliedException; import page.clab.api.domain.login.exception.MemberLockedException; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.global.auth.exception.TokenForgeryException; import page.clab.api.global.auth.exception.TokenMisuseException; @@ -43,7 +43,7 @@ public class LoginService { private final AccountLockInfoService accountLockInfoService; - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final LoginAttemptLogService loginAttemptLogService; @@ -57,7 +57,7 @@ public class LoginService { public LoginResult login(HttpServletRequest request, LoginRequestDto requestDto) throws LoginFaliedException, MemberLockedException { authenticateAndCheckStatus(request, requestDto); logLoginAttempt(request, requestDto.getId(), true); - Member loginMember = memberService.getMemberByIdOrThrow(requestDto.getId()); + Member loginMember = memberLookupService.getMemberByIdOrThrow(requestDto.getId()); loginMember.updateLastLoginTime(); return generateLoginResult(loginMember); } @@ -65,7 +65,7 @@ public LoginResult login(HttpServletRequest request, LoginRequestDto requestDto) @Transactional public LoginResult authenticator(HttpServletRequest request, TwoFactorAuthenticationRequestDto twoFactorAuthenticationRequestDto) throws LoginFaliedException, MemberLockedException { String memberId = twoFactorAuthenticationRequestDto.getMemberId(); - Member loginMember = memberService.getMemberById(memberId); + Member loginMember = memberLookupService.getMemberById(memberId); String totp = twoFactorAuthenticationRequestDto.getTotp(); accountLockInfoService.handleAccountLockInfo(memberId); @@ -82,7 +82,7 @@ public String resetAuthenticator(String memberId) { } public String revoke(String memberId) { - Member member = memberService.getMemberById(memberId); + Member member = memberLookupService.getMemberById(memberId); redisTokenService.deleteRedisTokenByMemberId(memberId); return member.getId(); } @@ -165,7 +165,7 @@ private void sendAdminLoginNotification(HttpServletRequest request, Member login private void validateMemberExistence(Authentication authentication) { String id = authentication.getName(); - Member member = memberService.getMemberById(id); + Member member = memberLookupService.getMemberById(id); if (member == null) { throw new TokenForgeryException("존재하지 않는 회원에 대한 토큰입니다."); } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java new file mode 100644 index 000000000..a578dad11 --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -0,0 +1,28 @@ +package page.clab.api.domain.member.application; + +import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.response.MemberResponseDto; + +import java.util.List; + +public interface MemberLookupService { + + boolean existsMemberById(String memberId); + + Member getMemberById(String memberId); + + Member getMemberByIdOrThrow(String memberId); + + Member getMemberByEmail(String email); + + Member getCurrentMember(); + + List<MemberResponseDto> getMembers(); + + List<Member> findAllMembers(); + + List<Member> getAdmins(); + + List<Member> getSuperAdmins(); + +} diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java new file mode 100644 index 000000000..07e4bf5d3 --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -0,0 +1,78 @@ +package page.clab.api.domain.member.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import page.clab.api.domain.member.dao.MemberRepository; +import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.response.MemberResponseDto; +import page.clab.api.global.auth.util.AuthUtil; +import page.clab.api.global.exception.NotFoundException; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class MemberLookupServiceImpl implements MemberLookupService { + + private final MemberRepository memberRepository; + + @Override + public boolean existsMemberById(String memberId) { + return memberRepository.existsById(memberId); + } + + @Override + public Member getMemberById(String memberId) { + return memberRepository.findById(memberId) + .orElse(null); + } + + @Override + public Member getMemberByIdOrThrow(String memberId) { + return memberRepository.findById(memberId) + .orElseThrow(() -> new NotFoundException("[Member] id: " + memberId + "에 해당하는 멤버가 존재하지 않습니다.")); + } + + @Override + public Member getMemberByEmail(String email) { + return memberRepository.findByEmail(email) + .orElseThrow(() -> new NotFoundException("해당 이메일을 사용하는 멤버가 없습니다.")); + } + + @Override + public Member getCurrentMember() { + String memberId = AuthUtil.getAuthenticationInfoMemberId(); + return memberRepository.findById(memberId) + .orElseThrow(() -> new NotFoundException("[Member] id: " + memberId + "에 해당하는 멤버가 존재하지 않습니다.")); + } + + @Override + public List<MemberResponseDto> getMembers() { + List<Member> members = memberRepository.findAll(); + return members.stream() + .map(MemberResponseDto::toDto) + .toList(); + } + + @Override + public List<Member> findAllMembers() { + return memberRepository.findAll(); + } + + @Override + public List<Member> getAdmins() { + return memberRepository.findAll() + .stream() + .filter(Member::isAdminRole) + .toList(); + } + + @Override + public List<Member> getSuperAdmins() { + return memberRepository.findAll() + .stream() + .filter(Member::isSuperAdminRole) + .toList(); + } + +} diff --git a/src/main/java/page/clab/api/domain/member/application/MemberService.java b/src/main/java/page/clab/api/domain/member/application/MemberService.java index 4de503bcb..0efd76d84 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberService.java @@ -2,8 +2,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.security.crypto.password.PasswordEncoder; @@ -12,7 +10,6 @@ import page.clab.api.domain.application.dao.ApplicationRepository; import page.clab.api.domain.application.domain.Application; import page.clab.api.domain.application.exception.NotApprovedApplicationException; -import page.clab.api.domain.login.exception.LoginFaliedException; import page.clab.api.domain.member.dao.MemberRepository; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.request.MemberRequestDto; @@ -27,7 +24,6 @@ import page.clab.api.domain.position.dao.PositionRepository; import page.clab.api.domain.position.domain.Position; import page.clab.api.domain.position.domain.PositionType; -import page.clab.api.global.auth.util.AuthUtil; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.common.email.application.EmailService; import page.clab.api.global.common.file.application.FileService; @@ -49,11 +45,13 @@ @Slf4j public class MemberService { + private final MemberLookupService memberLookupService; + private final VerificationService verificationService; private final ValidationService validationService; - private EmailService emailService; + private final EmailService emailService; private final ApplicationRepository applicationRepository; @@ -63,17 +61,7 @@ public class MemberService { private final PasswordEncoder passwordEncoder; - private FileService fileService; - - @Autowired - public void setEmailService(@Lazy EmailService emailService) { - this.emailService = emailService; - } - - @Autowired - public void setFileServie(@Lazy FileService fileService) { - this.fileService = fileService; - } + private final FileService fileService; @Transactional public String createMember(MemberRequestDto requestDto) { @@ -100,13 +88,6 @@ public String createMemberByRecruitmentId(Long recruitmentId, String memberId) { return createMemberFromApplication(application); } - public List<MemberResponseDto> getMembers() { - List<Member> members = memberRepository.findAll(); - return members.stream() - .map(MemberResponseDto::toDto) - .toList(); - } - @Transactional(readOnly = true) public PagedResponseDto<MemberResponseDto> getMembersByConditions(String id, String name, Pageable pageable) { Page<Member> members = memberRepository.findByConditions(id, name, pageable); @@ -115,7 +96,7 @@ public PagedResponseDto<MemberResponseDto> getMembersByConditions(String id, Str @Transactional(readOnly = true) public MyProfileResponseDto getMyProfile() { - Member currentMember = getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); return MyProfileResponseDto.toDto(currentMember); } @@ -127,8 +108,8 @@ public PagedResponseDto<MemberBirthdayResponseDto> getBirthdaysThisMonth(int mon @Transactional public String updateMemberInfo(String memberId, MemberUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = getCurrentMember(); - Member member = getMemberByIdOrThrow(memberId); + Member currentMember = memberLookupService.getCurrentMember(); + Member member = memberLookupService.getMemberByIdOrThrow(memberId); member.validateAccessPermission(currentMember); updateMember(requestDto, member); validationService.checkValid(member); @@ -146,47 +127,17 @@ public String requestResetMemberPassword(MemberResetPasswordRequestDto requestDt @Transactional public String verifyResetMemberPassword(VerificationRequestDto requestDto) { - Member member = getMemberByIdOrThrow(requestDto.getMemberId()); + Member member = memberLookupService.getMemberByIdOrThrow(requestDto.getMemberId()); Verification verification = verificationService.validateVerificationCode(requestDto, member); updateMemberPasswordWithVerificationCode(verification.getVerificationCode(), member); return member.getId(); } - public Member getMemberById(String memberId) { - return memberRepository.findById(memberId) - .orElse(null); - } - - public Member getMemberByIdOrThrow(String memberId) { - return memberRepository.findById(memberId) - .orElseThrow(() -> new NotFoundException("해당 멤버가 없습니다.")); - } - private Application getApplicationByRecruitmentIdAndStudentIdOrThrow(Long recruitmentId, String memberId) { return applicationRepository.findByRecruitmentIdAndStudentId(recruitmentId, memberId) .orElseThrow(() -> new NotFoundException("존재하지 않는 지원서입니다.")); } - public Member getMemberByIdOrThrowLoginFailed(String memberId) throws LoginFaliedException { - return memberRepository.findById(memberId) - .orElseThrow(LoginFaliedException::new); - } - - public Member getCurrentMember() { - String memberId = AuthUtil.getAuthenticationInfoMemberId(); - return memberRepository.findById(memberId) - .orElseThrow(() -> new NotFoundException("해당 멤버가 없습니다.")); - } - - public Member getMemberByEmail(String email) { - return (Member)memberRepository.findByEmail(email) - .orElseThrow(() -> new NotFoundException("해당 이메일을 사용하는 멤버가 없습니다.")); - } - - public List<Member> findAll() { - return memberRepository.findAll(); - } - private void setupMemberPassword(Member member) { if (member.getPassword().isEmpty()) { setRandomPasswordAndSendEmail(member); @@ -246,7 +197,7 @@ public void createPositionByMember(Member member) { } private Member validateResetPasswordRequest(MemberResetPasswordRequestDto requestDto) { - Member member = getMemberByIdOrThrow(requestDto.getId()); + Member member = memberLookupService.getMemberByIdOrThrow(requestDto.getId()); if (!member.isSameName(requestDto.getName()) || !member.isSameEmail(requestDto.getEmail())) { throw new InvalidInformationException("올바르지 않은 정보입니다."); } @@ -267,18 +218,4 @@ private void updateMember(MemberUpdateRequestDto requestDto, Member member) thro } } - public List<Member> getAdmins() { - return memberRepository.findAll() - .stream() - .filter(Member::isAdminRole) - .toList(); - } - - public List<Member> getSuperAdmins() { - return memberRepository.findAll() - .stream() - .filter(Member::isSuperAdminRole) - .toList(); - } - } diff --git a/src/main/java/page/clab/api/domain/member/dao/MemberRepository.java b/src/main/java/page/clab/api/domain/member/dao/MemberRepository.java index 2a24bdbf3..4f5696d10 100644 --- a/src/main/java/page/clab/api/domain/member/dao/MemberRepository.java +++ b/src/main/java/page/clab/api/domain/member/dao/MemberRepository.java @@ -16,7 +16,7 @@ public interface MemberRepository extends JpaRepository<Member, String>, MemberR boolean existsByEmail(String email); - Optional<Object> findByEmail(String email); + Optional<Member> findByEmail(String email); Page<Member> findAllByOrderByCreatedAtDesc(Pageable pageable); diff --git a/src/main/java/page/clab/api/domain/membershipFee/application/MembershipFeeService.java b/src/main/java/page/clab/api/domain/membershipFee/application/MembershipFeeService.java index 292930d26..50466da4c 100644 --- a/src/main/java/page/clab/api/domain/membershipFee/application/MembershipFeeService.java +++ b/src/main/java/page/clab/api/domain/membershipFee/application/MembershipFeeService.java @@ -5,7 +5,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.membershipFee.dao.MembershipFeeRepository; import page.clab.api.domain.membershipFee.domain.MembershipFee; @@ -23,7 +23,7 @@ @RequiredArgsConstructor public class MembershipFeeService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final NotificationService notificationService; @@ -33,7 +33,7 @@ public class MembershipFeeService { @Transactional public Long createMembershipFee(MembershipFeeRequestDto requestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); MembershipFee membershipFee = MembershipFeeRequestDto.toEntity(requestDto, currentMember); validationService.checkValid(membershipFee); notificationService.sendNotificationToAdmins("새로운 회비 내역이 등록되었습니다."); @@ -42,7 +42,7 @@ public Long createMembershipFee(MembershipFeeRequestDto requestDto) { @Transactional(readOnly = true) public PagedResponseDto<MembershipFeeResponseDto> getMembershipFeesByConditions(String memberId, String memberName, String category, MembershipFeeStatus status, Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); boolean isAdminOrSuper = currentMember.isAdminRole(); Page<MembershipFee> membershipFeesPage = membershipFeeRepository.findByConditions(memberId, memberName, category, status, pageable); return new PagedResponseDto<>(membershipFeesPage.map(membershipFee -> MembershipFeeResponseDto.toDto(membershipFee, isAdminOrSuper))); @@ -50,7 +50,7 @@ public PagedResponseDto<MembershipFeeResponseDto> getMembershipFeesByConditions( @Transactional(readOnly = true) public PagedResponseDto<MembershipFeeResponseDto> getDeletedMembershipFees(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); boolean isAdminOrSuper = currentMember.isAdminRole(); Page<MembershipFee> membershipFees = membershipFeeRepository.findAllByIsDeletedTrue(pageable); return new PagedResponseDto<>(membershipFees.map(membershipFee -> MembershipFeeResponseDto.toDto(membershipFee, isAdminOrSuper))); @@ -58,7 +58,7 @@ public PagedResponseDto<MembershipFeeResponseDto> getDeletedMembershipFees(Pagea @Transactional public Long updateMembershipFee(Long membershipFeeId, MembershipFeeUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); MembershipFee membershipFee = getMembershipFeeByIdOrThrow(membershipFeeId); membershipFee.validateAccessPermission(currentMember); membershipFee.update(requestDto); @@ -67,7 +67,7 @@ public Long updateMembershipFee(Long membershipFeeId, MembershipFeeUpdateRequest } public Long deleteMembershipFee(Long membershipFeeId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); MembershipFee membershipFee = getMembershipFeeByIdOrThrow(membershipFeeId); membershipFee.validateAccessPermission(currentMember); membershipFeeRepository.delete(membershipFee); diff --git a/src/main/java/page/clab/api/domain/notification/application/NotificationService.java b/src/main/java/page/clab/api/domain/notification/application/NotificationService.java index 607c2fccc..bfc98daba 100644 --- a/src/main/java/page/clab/api/domain/notification/application/NotificationService.java +++ b/src/main/java/page/clab/api/domain/notification/application/NotificationService.java @@ -1,13 +1,11 @@ package page.clab.api.domain.notification.application; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.dao.NotificationRepository; import page.clab.api.domain.notification.domain.Notification; @@ -25,20 +23,15 @@ @RequiredArgsConstructor public class NotificationService { - private MemberService memberService; + private MemberLookupService memberLookupService; private final ValidationService validationService; private final NotificationRepository notificationRepository; - @Autowired - public void setMemberService(@Lazy MemberService memberService) { - this.memberService = memberService; - } - @Transactional public Long createNotification(NotificationRequestDto requestDto) { - Member member = memberService.getMemberByIdOrThrow(requestDto.getMemberId()); + Member member = memberLookupService.getMemberByIdOrThrow(requestDto.getMemberId()); Notification notification = NotificationRequestDto.toEntity(requestDto, member); validationService.checkValid(notification); return notificationRepository.save(notification).getId(); @@ -46,7 +39,7 @@ public Long createNotification(NotificationRequestDto requestDto) { @Transactional(readOnly = true) public PagedResponseDto<NotificationResponseDto> getNotifications(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Notification> notifications = getNotificationByMember(currentMember, pageable); return new PagedResponseDto<>(notifications.map(NotificationResponseDto::toDto)); } @@ -58,7 +51,7 @@ public PagedResponseDto<NotificationResponseDto> getDeletedNotifications(Pageabl } public Long deleteNotification(Long notificationId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Notification notification = getNotificationByIdOrThrow(notificationId); notification.validateAccessPermission(currentMember); notificationRepository.delete(notification); @@ -66,7 +59,7 @@ public Long deleteNotification(Long notificationId) throws PermissionDeniedExcep } public void sendNotificationToAllMembers(String content) { - List<Notification> notifications = memberService.findAll().stream() + List<Notification> notifications = memberLookupService.findAllMembers().stream() .map(member -> Notification.create(member, content)) .toList(); notificationRepository.saveAll(notifications); @@ -85,17 +78,17 @@ public void sendNotificationToMembers(List<Member> members, String content) { } public void sendNotificationToMember(String memberId, String content) { - Member member = memberService.getMemberByIdOrThrow(memberId); + Member member = memberLookupService.getMemberByIdOrThrow(memberId); Notification notification = Notification.create(member, content); notificationRepository.save(notification); } public void sendNotificationToAdmins(String content) { - sendNotificationToSpecificRole(memberService::getAdmins, content); + sendNotificationToSpecificRole(memberLookupService::getAdmins, content); } public void sendNotificationToSuperAdmins(String content) { - sendNotificationToSpecificRole(memberService::getSuperAdmins, content); + sendNotificationToSpecificRole(memberLookupService::getSuperAdmins, content); } private void sendNotificationToSpecificRole(Supplier<List<Member>> memberSupplier, String content) { diff --git a/src/main/java/page/clab/api/domain/position/application/PositionService.java b/src/main/java/page/clab/api/domain/position/application/PositionService.java index 8459720d4..22eb51f6a 100644 --- a/src/main/java/page/clab/api/domain/position/application/PositionService.java +++ b/src/main/java/page/clab/api/domain/position/application/PositionService.java @@ -5,7 +5,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.position.dao.PositionRepository; import page.clab.api.domain.position.domain.Position; @@ -22,13 +22,13 @@ @RequiredArgsConstructor public class PositionService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final PositionRepository positionRepository; @Transactional public Long createPosition(PositionRequestDto requestDto) { - Member member = memberService.getMemberByIdOrThrow(requestDto.getMemberId()); + Member member = memberLookupService.getMemberByIdOrThrow(requestDto.getMemberId()); return positionRepository.findByMemberAndYearAndPositionType(member, requestDto.getYear(), requestDto.getPositionType()) .map(Position::getId) .orElseGet(() -> { @@ -45,7 +45,7 @@ public PagedResponseDto<PositionResponseDto> getPositionsByConditions(String yea @Transactional(readOnly = true) public PositionMyResponseDto getMyPositionsByYear(String year) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); List<Position> positions = getPositionsByMemberAndYear(currentMember, year); if (positions.isEmpty()) { throw new NotFoundException("해당 멤버의 " + year + "년도 직책이 존재하지 않습니다."); diff --git a/src/main/java/page/clab/api/domain/review/application/ReviewService.java b/src/main/java/page/clab/api/domain/review/application/ReviewService.java index 28d593eb2..cf3fadd3d 100644 --- a/src/main/java/page/clab/api/domain/review/application/ReviewService.java +++ b/src/main/java/page/clab/api/domain/review/application/ReviewService.java @@ -11,7 +11,7 @@ import page.clab.api.domain.activityGroup.domain.ActivityGroupRole; import page.clab.api.domain.activityGroup.domain.GroupMember; import page.clab.api.domain.activityGroup.exception.ActivityGroupNotFinishedException; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.domain.review.dao.ReviewRepository; @@ -30,7 +30,7 @@ @Slf4j public class ReviewService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final ActivityGroupMemberService activityGroupMemberService; @@ -42,7 +42,7 @@ public class ReviewService { @Transactional public Long createReview(ReviewRequestDto requestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = activityGroupMemberService.getActivityGroupByIdOrThrow(requestDto.getActivityGroupId()); validateReviewCreationPermission(activityGroup, currentMember); Review review = ReviewRequestDto.toEntity(requestDto, currentMember, activityGroup); @@ -53,28 +53,28 @@ public Long createReview(ReviewRequestDto requestDto) { @Transactional(readOnly = true) public PagedResponseDto<ReviewResponseDto> getReviewsByConditions(String memberId, String memberName, Long activityId, Boolean isPublic, Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Review> reviews = reviewRepository.findByConditions(memberId, memberName, activityId, isPublic, pageable); return new PagedResponseDto<>(reviews.map(review -> ReviewResponseDto.toDto(review, currentMember))); } @Transactional(readOnly = true) public PagedResponseDto<ReviewResponseDto> getMyReviews(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Review> reviews = getReviewByMember(currentMember, pageable); return new PagedResponseDto<>(reviews.map(review -> ReviewResponseDto.toDto(review, currentMember))); } @Transactional(readOnly = true) public PagedResponseDto<ReviewResponseDto> getDeletedReviews(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Review> reviews = reviewRepository.findAllByIsDeletedTrue(pageable); return new PagedResponseDto<>(reviews.map(review -> ReviewResponseDto.toDto(review, currentMember))); } @Transactional public Long updateReview(Long reviewId, ReviewUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Review review = getReviewByIdOrThrow(reviewId); review.validateAccessPermission(currentMember); review.update(requestDto); @@ -83,7 +83,7 @@ public Long updateReview(Long reviewId, ReviewUpdateRequestDto requestDto) throw } public Long deleteReview(Long reviewId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Review review = getReviewByIdOrThrow(reviewId); review.validateAccessPermission(currentMember); reviewRepository.delete(review); diff --git a/src/main/java/page/clab/api/domain/schedule/application/ScheduleService.java b/src/main/java/page/clab/api/domain/schedule/application/ScheduleService.java index 87353be65..a1a5fc133 100644 --- a/src/main/java/page/clab/api/domain/schedule/application/ScheduleService.java +++ b/src/main/java/page/clab/api/domain/schedule/application/ScheduleService.java @@ -11,7 +11,7 @@ import page.clab.api.domain.activityGroup.domain.ActivityGroup; import page.clab.api.domain.activityGroup.domain.ActivityGroupRole; import page.clab.api.domain.activityGroup.domain.GroupMember; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.schedule.dao.ScheduleRepository; import page.clab.api.domain.schedule.domain.Schedule; @@ -34,7 +34,7 @@ @Slf4j public class ScheduleService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final ActivityGroupMemberService activityGroupMemberService; @@ -44,7 +44,7 @@ public class ScheduleService { @Transactional public Long createSchedule(ScheduleRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); ActivityGroup activityGroup = resolveActivityGroupForSchedule(requestDto, currentMember); Schedule schedule = ScheduleRequestDto.toEntity(requestDto, currentMember, activityGroup); schedule.validateAccessPermissionForCreation(currentMember); @@ -53,7 +53,7 @@ public Long createSchedule(ScheduleRequestDto requestDto) throws PermissionDenie @Transactional(readOnly = true) public PagedResponseDto<ScheduleResponseDto> getSchedulesWithinDateRange(LocalDate startDate, LocalDate endDate, Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); List<GroupMember> groupMembers = activityGroupMemberService.getGroupMemberByMember(currentMember); List<ActivityGroup> myGroups = getMyActivityGroups(groupMembers); Page<Schedule> schedules = scheduleRepository.findByDateRangeAndMember(startDate, endDate, myGroups, pageable); @@ -71,7 +71,7 @@ public ScheduleCollectResponseDto getCollectSchedules() { @Transactional(readOnly = true) public PagedResponseDto<ScheduleResponseDto> getActivitySchedules(LocalDate startDate, LocalDate endDate, Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<Schedule> schedules = scheduleRepository.findActivitySchedulesByDateRangeAndMember(startDate, endDate, currentMember, pageable); return new PagedResponseDto<>(schedules.map(ScheduleResponseDto::toDto)); } @@ -83,7 +83,7 @@ public PagedResponseDto<ScheduleResponseDto> getDeletedSchedules(Pageable pageab } public Long deleteSchedule(Long scheduleId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Schedule schedule = getScheduleById(scheduleId); schedule.validateAccessPermission(currentMember); scheduleRepository.delete(schedule); diff --git a/src/main/java/page/clab/api/domain/sharedAccount/application/SharedAccountUsageService.java b/src/main/java/page/clab/api/domain/sharedAccount/application/SharedAccountUsageService.java index 9ec4b30d5..7c45b6155 100644 --- a/src/main/java/page/clab/api/domain/sharedAccount/application/SharedAccountUsageService.java +++ b/src/main/java/page/clab/api/domain/sharedAccount/application/SharedAccountUsageService.java @@ -9,7 +9,7 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.sharedAccount.dao.SharedAccountUsageRepository; import page.clab.api.domain.sharedAccount.domain.SharedAccount; @@ -33,7 +33,7 @@ public class SharedAccountUsageService { private final SharedAccountService sharedAccountService; - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final SharedAccountUsageRepository sharedAccountUsageRepository; @@ -130,7 +130,7 @@ private SharedAccountUsage prepareSharedAccountUsage(SharedAccountUsageRequestDt LocalDateTime startTime = sharedAccountUsageRequestDto.getStartTime() != null ? sharedAccountUsageRequestDto.getStartTime() : currentTime; LocalDateTime endTime = sharedAccountUsageRequestDto.getEndTime(); - String memberId = memberService.getCurrentMember().getId(); + String memberId = memberLookupService.getCurrentMember().getId(); SharedAccountUsage sharedAccountUsage = SharedAccountUsage.create(sharedAccount, memberId, startTime, endTime); sharedAccountUsage.validateUsageTimes(currentTime); @@ -166,7 +166,7 @@ private void validateReservedUsages(Long sharedAccountId, LocalDateTime startTim } private void updateUsageStatus(SharedAccountUsage sharedAccountUsage, SharedAccountUsageStatus status) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); sharedAccountUsage.updateStatus(status, currentMember); sharedAccountUsageRepository.save(sharedAccountUsage); sharedAccountUsage.getSharedAccount().updateIsInUse(false); diff --git a/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceService.java b/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceService.java index 76bd74959..7c094dd6a 100644 --- a/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceService.java +++ b/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceService.java @@ -5,7 +5,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.workExperience.dao.WorkExperienceRepository; import page.clab.api.domain.workExperience.domain.WorkExperience; @@ -21,7 +21,7 @@ @RequiredArgsConstructor public class WorkExperienceService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final ValidationService validationService; @@ -29,7 +29,7 @@ public class WorkExperienceService { @Transactional public Long createWorkExperience(WorkExperienceRequestDto requestDto) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); WorkExperience workExperience = WorkExperienceRequestDto.toEntity(requestDto, currentMember); validationService.checkValid(workExperience); return workExperienceRepository.save(workExperience).getId(); @@ -37,14 +37,14 @@ public Long createWorkExperience(WorkExperienceRequestDto requestDto) { @Transactional(readOnly = true) public PagedResponseDto<WorkExperienceResponseDto> getMyWorkExperience(Pageable pageable) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); Page<WorkExperience> workExperiences = workExperienceRepository.findAllByMember(currentMember, pageable); return new PagedResponseDto<>(workExperiences.map(WorkExperienceResponseDto::toDto)); } @Transactional(readOnly = true) public PagedResponseDto<WorkExperienceResponseDto> getWorkExperiencesByConditions(String memberId, Pageable pageable) { - Member member = memberService.getMemberByIdOrThrow(memberId); + Member member = memberLookupService.getMemberByIdOrThrow(memberId); Page<WorkExperience> workExperiences = workExperienceRepository.findAllByMember(member, pageable); return new PagedResponseDto<>(workExperiences.map(WorkExperienceResponseDto::toDto)); } @@ -57,7 +57,7 @@ public PagedResponseDto<WorkExperienceResponseDto> getDeletedWorkExperiences(Pag @Transactional public Long updateWorkExperience(Long workExperienceId, WorkExperienceUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); WorkExperience workExperience = getWorkExperienceByIdOrThrow(workExperienceId); workExperience.validateAccessPermission(currentMember); workExperience.update(requestDto); @@ -66,7 +66,7 @@ public Long updateWorkExperience(Long workExperienceId, WorkExperienceUpdateRequ } public Long deleteWorkExperience(Long workExperienceId) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); WorkExperience workExperience = getWorkExperienceByIdOrThrow(workExperienceId); workExperience.validateAccessPermission(currentMember); workExperienceRepository.deleteById(workExperienceId); diff --git a/src/main/java/page/clab/api/global/common/email/application/EmailService.java b/src/main/java/page/clab/api/global/common/email/application/EmailService.java index 2532e4d02..d0a133fe1 100644 --- a/src/main/java/page/clab/api/global/common/email/application/EmailService.java +++ b/src/main/java/page/clab/api/global/common/email/application/EmailService.java @@ -9,7 +9,7 @@ import org.springframework.web.multipart.MultipartFile; import org.thymeleaf.context.Context; import org.thymeleaf.spring6.SpringTemplateEngine; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.response.MemberResponseDto; import page.clab.api.global.common.email.domain.EmailTemplateType; @@ -28,7 +28,7 @@ @Slf4j public class EmailService { - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final SpringTemplateEngine springTemplateEngine; @@ -46,7 +46,7 @@ public List<String> broadcastEmail(EmailDto emailDto, List<MultipartFile> multip emailDto.getTo().parallelStream().forEach(address -> { try { - Member recipient = memberService.getMemberByEmail(address); + Member recipient = memberLookupService.getMemberByEmail(address); String emailContent = generateEmailContent(emailDto, recipient.getName()); emailAsyncService.sendEmailAsync(address, emailDto.getSubject(), emailContent, convertedFiles, emailDto.getEmailTemplateType()); successfulAddresses.add(address); @@ -61,7 +61,7 @@ public List<String> broadcastEmailToAllMember(EmailDto emailDto, List<MultipartF List<File> convertedFiles = multipartFiles != null && !multipartFiles.isEmpty() ? convertMultipartFiles(multipartFiles) : null; - List<MemberResponseDto> memberList = memberService.getMembers(); + List<MemberResponseDto> memberList = memberLookupService.getMembers(); List<String> successfulEmails = Collections.synchronizedList(new ArrayList<>()); diff --git a/src/main/java/page/clab/api/global/common/file/application/FileService.java b/src/main/java/page/clab/api/global/common/file/application/FileService.java index 77e3142d2..edc32625b 100644 --- a/src/main/java/page/clab/api/global/common/file/application/FileService.java +++ b/src/main/java/page/clab/api/global/common/file/application/FileService.java @@ -10,7 +10,7 @@ import page.clab.api.domain.activityGroup.dao.ActivityGroupRepository; import page.clab.api.domain.activityGroup.dao.GroupMemberRepository; import page.clab.api.domain.member.application.MemberCloudService; -import page.clab.api.domain.member.application.MemberService; +import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.file.domain.UploadedFile; import page.clab.api.global.common.file.dto.request.DeleteFileRequestDto; @@ -35,7 +35,7 @@ public class FileService { private final FileHandler fileHandler; - private final MemberService memberService; + private final MemberLookupService memberLookupService; private final MemberCloudService memberCloudService; @@ -57,7 +57,7 @@ public class FileService { private String maxFileSize; public String saveQRCodeImage(byte[] QRCodeImage, String path, long storagePeriod, String nowDateTime) throws IOException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); String extension = "png"; String originalFileName = path.replace(File.separator, "-") + nowDateTime; String saveFilename = fileHandler.makeFileName(extension); @@ -80,7 +80,7 @@ public List<UploadedFileResponseDto> saveFiles(List<MultipartFile> multipartFile } public UploadedFileResponseDto saveFile(MultipartFile multipartFile, String path, long storagePeriod) throws IOException, PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); validatePathVariable(path); validateMemberCloudUsage(multipartFile, path); @@ -96,7 +96,7 @@ public UploadedFileResponseDto saveFile(MultipartFile multipartFile, String path } public String deleteFile(DeleteFileRequestDto deleteFileRequestDto) throws PermissionDeniedException { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); UploadedFile uploadedFile = uploadedFileService.getUploadedFileByUrl(deleteFileRequestDto.getUrl()); String filePath = uploadedFile.getSavedPath(); File storedFile = new File(filePath); @@ -109,7 +109,7 @@ public String deleteFile(DeleteFileRequestDto deleteFileRequestDto) throws Permi } public String buildPath(String baseDirectory, Long... additionalSegments) { - Member currentMember = memberService.getCurrentMember(); + Member currentMember = memberLookupService.getCurrentMember(); StringBuilder pathBuilder = new StringBuilder(baseDirectory); for (Long segment : additionalSegments) { pathBuilder.append(File.separator).append(segment); @@ -123,7 +123,7 @@ public void validatePathVariable(String path) throws AssignmentFileUploadFailExc Long activityGroupId = Long.parseLong(path.split(Pattern.quote(File.separator))[1]); Long activityGroupBoardId = Long.parseLong(path.split(Pattern.quote(File.separator))[2]); String memberId = path.split(Pattern.quote(File.separator))[3]; - Member assignmentWriter = memberService.getMemberById(memberId); + Member assignmentWriter = memberLookupService.getMemberById(memberId); if (!activityGroupRepository.existsById(activityGroupId)) { throw new AssignmentFileUploadFailException("해당 활동은 존재하지 않습니다."); } From 67a712615508abc17e69c4d9bbb8f78550532000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Sun, 23 Jun 2024 11:46:35 +0900 Subject: [PATCH 14/47] =?UTF-8?q?feat(Member):=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=9D=B4=EB=B2=A4=ED=8A=B8,=20=EA=B3=B5=ED=86=B5?= =?UTF-8?q?=20=EB=A6=AC=EC=8A=A4=EB=84=88,=20=EC=9D=B4=EB=B2=A4=ED=8A=B8?= =?UTF-8?q?=20=EB=94=94=EC=8A=A4=ED=8C=A8=EC=B2=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/event/MemberDeletedEvent.java | 16 +++++++++++++ .../member/event/MemberEventDispatcher.java | 24 +++++++++++++++++++ .../member/event/MemberEventProcessor.java | 9 +++++++ .../event/MemberEventProcessorRegistry.java | 22 +++++++++++++++++ .../member/event/MemberUpdatedEvent.java | 16 +++++++++++++ 5 files changed, 87 insertions(+) create mode 100644 src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java create mode 100644 src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java create mode 100644 src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java create mode 100644 src/main/java/page/clab/api/domain/member/event/MemberEventProcessorRegistry.java create mode 100644 src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java diff --git a/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java b/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java new file mode 100644 index 000000000..c9d40fa5e --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java @@ -0,0 +1,16 @@ +package page.clab.api.domain.member.event; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +public class MemberDeletedEvent extends ApplicationEvent { + + private final String memberId; + + public MemberDeletedEvent(Object source, String memberId) { + super(source); + this.memberId = memberId; + } + +} diff --git a/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java b/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java new file mode 100644 index 000000000..76746915d --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java @@ -0,0 +1,24 @@ +package page.clab.api.domain.member.event; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class MemberEventDispatcher { + + private final List<MemberEventProcessor> processors; + + @EventListener + public void handleMemberDeletedEvent(MemberDeletedEvent event) { + processors.forEach(processor -> processor.processMemberDeleted(event.getMemberId())); + } + + @EventListener + public void handleMemberUpdatedEvent(MemberUpdatedEvent event) { + processors.forEach(processor -> processor.processMemberUpdated(event.getMemberId())); + } +} diff --git a/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java b/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java new file mode 100644 index 000000000..f3d34ca62 --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java @@ -0,0 +1,9 @@ +package page.clab.api.domain.member.event; + +public interface MemberEventProcessor { + + void processMemberDeleted(String memberId); + + void processMemberUpdated(String memberId); + +} diff --git a/src/main/java/page/clab/api/domain/member/event/MemberEventProcessorRegistry.java b/src/main/java/page/clab/api/domain/member/event/MemberEventProcessorRegistry.java new file mode 100644 index 000000000..90f9098a5 --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/event/MemberEventProcessorRegistry.java @@ -0,0 +1,22 @@ +package page.clab.api.domain.member.event; + +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Component +public class MemberEventProcessorRegistry { + + private final List<MemberEventProcessor> processors = new ArrayList<>(); + + public void registerProcessor(MemberEventProcessor processor) { + processors.add(processor); + } + + public List<MemberEventProcessor> getProcessors() { + return Collections.unmodifiableList(processors); + } + +} diff --git a/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java b/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java new file mode 100644 index 000000000..b1bc7b142 --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java @@ -0,0 +1,16 @@ +package page.clab.api.domain.member.event; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +public class MemberUpdatedEvent extends ApplicationEvent { + + private final String memberId; + + public MemberUpdatedEvent(Object source, String memberId) { + super(source); + this.memberId = memberId; + } + +} From de8b01ead35dea3e4472bb398d13f000b6057aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Sun, 23 Jun 2024 12:05:25 +0900 Subject: [PATCH 15/47] =?UTF-8?q?feat(Member):=20=EC=88=98=EC=A0=95,=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=EC=8B=9C=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=EA=B0=80=20=EB=B0=9C=EC=83=9D?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/api/MemberController.java | 20 +++++++++++++------ .../member/application/MemberService.java | 16 ++++++++++++++- .../clab/api/domain/member/domain/Member.java | 4 ++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/main/java/page/clab/api/domain/member/api/MemberController.java b/src/main/java/page/clab/api/domain/member/api/MemberController.java index 2a6c2b1f7..c046de494 100644 --- a/src/main/java/page/clab/api/domain/member/api/MemberController.java +++ b/src/main/java/page/clab/api/domain/member/api/MemberController.java @@ -3,12 +3,11 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -17,7 +16,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import page.clab.api.domain.application.domain.Application; import page.clab.api.domain.member.application.MemberService; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.request.MemberRequestDto; @@ -26,16 +24,16 @@ import page.clab.api.domain.member.dto.response.MemberBirthdayResponseDto; import page.clab.api.domain.member.dto.response.MemberResponseDto; import page.clab.api.domain.member.dto.response.MyProfileResponseDto; -import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.common.dto.ApiResponse; +import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.common.verification.dto.request.VerificationRequestDto; import page.clab.api.global.exception.InvalidColumnException; import page.clab.api.global.exception.PermissionDeniedException; - -import java.util.List; import page.clab.api.global.exception.SortingArgumentException; import page.clab.api.global.util.PageableUtils; +import java.util.List; + @RestController @RequestMapping("/api/v1/members") @RequiredArgsConstructor @@ -147,4 +145,14 @@ public ApiResponse<String> verifyResetMemberPassword( return ApiResponse.success(id); } + @Operation(summary = "[S] 멤버 정보 삭제", description = "ROLE_SUPER 이상의 권한이 필요함") + @Secured({"ROLE_SUPER"}) + @DeleteMapping("/{memberId}") + public ApiResponse<String> deleteMember( + @PathVariable(name = "memberId") String memberId + ) { + String id = memberService.deleteMember(memberId); + return ApiResponse.success(id); + } + } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberService.java b/src/main/java/page/clab/api/domain/member/application/MemberService.java index 0efd76d84..189b5b9a4 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberService.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.security.crypto.password.PasswordEncoder; @@ -18,6 +19,8 @@ import page.clab.api.domain.member.dto.response.MemberBirthdayResponseDto; import page.clab.api.domain.member.dto.response.MemberResponseDto; import page.clab.api.domain.member.dto.response.MyProfileResponseDto; +import page.clab.api.domain.member.event.MemberDeletedEvent; +import page.clab.api.domain.member.event.MemberUpdatedEvent; import page.clab.api.domain.member.exception.DuplicateMemberContactException; import page.clab.api.domain.member.exception.DuplicateMemberEmailException; import page.clab.api.domain.member.exception.DuplicateMemberIdException; @@ -63,6 +66,8 @@ public class MemberService { private final FileService fileService; + private final ApplicationEventPublisher eventPublisher; + @Transactional public String createMember(MemberRequestDto requestDto) { checkMemberUniqueness(requestDto); @@ -113,7 +118,9 @@ public String updateMemberInfo(String memberId, MemberUpdateRequestDto requestDt member.validateAccessPermission(currentMember); updateMember(requestDto, member); validationService.checkValid(member); - return memberRepository.save(member).getId(); + memberRepository.save(member); + eventPublisher.publishEvent(new MemberUpdatedEvent(this, member.getId())); + return member.getId(); } @Transactional @@ -133,6 +140,13 @@ public String verifyResetMemberPassword(VerificationRequestDto requestDto) { return member.getId(); } + public String deleteMember(String memberId) { + Member member = memberLookupService.getMemberByIdOrThrow(memberId); + memberRepository.delete(member); + eventPublisher.publishEvent(new MemberDeletedEvent(this, member.getId())); + return member.getId(); + } + private Application getApplicationByRecruitmentIdAndStudentIdOrThrow(Long recruitmentId, String memberId) { return applicationRepository.findByRecruitmentIdAndStudentId(recruitmentId, memberId) .orElseThrow(() -> new NotFoundException("존재하지 않는 지원서입니다.")); diff --git a/src/main/java/page/clab/api/domain/member/domain/Member.java b/src/main/java/page/clab/api/domain/member/domain/Member.java index f8656db93..bdb172ee8 100644 --- a/src/main/java/page/clab/api/domain/member/domain/Member.java +++ b/src/main/java/page/clab/api/domain/member/domain/Member.java @@ -16,6 +16,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.SQLRestriction; import org.hibernate.validator.constraints.URL; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -38,6 +40,8 @@ @Builder @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) +@SQLDelete(sql = "UPDATE member SET is_deleted = true WHERE id = ?") +@SQLRestriction("is_deleted = false") public class Member extends BaseEntity implements UserDetails { @Id From fb52e86a1ddbd1672b2262a995e2a60d1dfed25b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Sun, 23 Jun 2024 12:23:32 +0900 Subject: [PATCH 16/47] =?UTF-8?q?fix(Notification):=20MemberLookupService?= =?UTF-8?q?=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A3=BC=EC=9E=85=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/notification/application/NotificationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/page/clab/api/domain/notification/application/NotificationService.java b/src/main/java/page/clab/api/domain/notification/application/NotificationService.java index bfc98daba..49b4e3fa8 100644 --- a/src/main/java/page/clab/api/domain/notification/application/NotificationService.java +++ b/src/main/java/page/clab/api/domain/notification/application/NotificationService.java @@ -23,7 +23,7 @@ @RequiredArgsConstructor public class NotificationService { - private MemberLookupService memberLookupService; + private final MemberLookupService memberLookupService; private final ValidationService validationService; From 59d79d3feb14a123febe107254718f199b939d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Sun, 23 Jun 2024 12:53:47 +0900 Subject: [PATCH 17/47] =?UTF-8?q?refactor(Accuse):=20Accuse=EC=97=90?= =?UTF-8?q?=EC=84=9C=20Member=EB=A5=BC=20=EC=99=B8=EB=9E=98=ED=82=A4?= =?UTF-8?q?=EB=A1=9C=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accuse/application/AccuseService.java | 30 +++++++++++-------- .../domain/accuse/dao/AccuseRepository.java | 5 ++-- .../clab/api/domain/accuse/domain/Accuse.java | 6 ++-- .../accuse/dto/request/AccuseRequestDto.java | 5 ++-- .../accuse/dto/response/AccuseMemberInfo.java | 17 ++++------- .../clab/api/domain/board/domain/Board.java | 4 +++ .../application/MemberLookupService.java | 2 ++ .../application/MemberLookupServiceImpl.java | 5 ++++ .../clab/api/domain/review/domain/Review.java | 4 +++ 9 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java index 668bf358c..852c56220 100644 --- a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java @@ -60,14 +60,15 @@ public Long createAccuse(AccuseRequestDto requestDto) { TargetType type = requestDto.getTargetType(); Long targetId = requestDto.getTargetId(); Member currentMember = memberLookupService.getCurrentMember(); + String memberId = currentMember.getId(); - validateAccuseRequest(type, targetId, currentMember); + validateAccuseRequest(type, targetId, memberId); AccuseTarget target = getOrCreateAccuseTarget(requestDto, type, targetId); validationService.checkValid(target); accuseTargetRepository.save(target); - Accuse accuse = findOrCreateAccuse(requestDto, currentMember, target); + Accuse accuse = findOrCreateAccuse(requestDto, memberId, target); validationService.checkValid(accuse); notificationService.sendNotificationToMember(currentMember, "신고하신 내용이 접수되었습니다."); @@ -84,8 +85,8 @@ public PagedResponseDto<AccuseResponseDto> getAccusesByConditions(TargetType typ @Transactional(readOnly = true) public PagedResponseDto<AccuseMyResponseDto> getMyAccuses(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); - Page<Accuse> accuses = accuseRepository.findByMember(currentMember, pageable); + String currentMemberId = memberLookupService.getCurrentMemberId(); + Page<Accuse> accuses = accuseRepository.findByMemberId(currentMemberId, pageable); return new PagedResponseDto<>(accuses.map(AccuseMyResponseDto::toDto)); } @@ -103,23 +104,23 @@ private AccuseTarget getAccuseTargetByIdOrThrow(TargetType type, Long targetId) .orElseThrow(() -> new NotFoundException("존재하지 않는 신고 대상입니다.")); } - private void validateAccuseRequest(TargetType type, Long targetId, Member currentMember) { + private void validateAccuseRequest(TargetType type, Long targetId, String currentMemberId) { switch (type) { case BOARD: Board board = boardService.getBoardByIdOrThrow(targetId); - if (board.isOwner(currentMember)) { + if (board.isOwner(currentMemberId)) { throw new AccuseTargetTypeIncorrectException("자신의 게시글은 신고할 수 없습니다."); } break; case COMMENT: Comment comment = commentService.getCommentByIdOrThrow(targetId); - if (comment.isOwner(currentMember)) { + if (comment.isOwner(currentMemberId)) { throw new AccuseTargetTypeIncorrectException("자신의 댓글은 신고할 수 없습니다."); } break; case REVIEW: Review review = reviewService.getReviewByIdOrThrow(targetId); - if (review.isOwner(currentMember)) { + if (review.isOwner(currentMemberId)) { throw new AccuseTargetTypeIncorrectException("자신의 리뷰는 신고할 수 없습니다."); } break; @@ -133,15 +134,15 @@ private AccuseTarget getOrCreateAccuseTarget(AccuseRequestDto requestDto, Target .orElseGet(() -> AccuseRequestDto.toTargetEntity(requestDto)); } - private Accuse findOrCreateAccuse(AccuseRequestDto requestDto, Member currentMember, AccuseTarget target) { - return accuseRepository.findByMemberAndTarget(currentMember, target) + private Accuse findOrCreateAccuse(AccuseRequestDto requestDto, String memberId, AccuseTarget target) { + return accuseRepository.findByMemberIdAndTarget(memberId, target) .map(existingAccuse -> { existingAccuse.updateReason(requestDto.getReason()); return existingAccuse; }) .orElseGet(() -> { target.increaseAccuseCount(); - return AccuseRequestDto.toEntity(requestDto, currentMember, target); + return AccuseRequestDto.toEntity(requestDto, memberId, target); }); } @@ -150,7 +151,10 @@ private List<AccuseResponseDto> convertTargetsToResponseDtos(Page<AccuseTarget> return accuseTargets.stream() .map(accuseTarget -> { List<Accuse> accuses = accuseRepository.findByTargetOrderByCreatedAtDesc(accuseTarget); - List<AccuseMemberInfo> members = AccuseMemberInfo.create(accuses); + List<AccuseMemberInfo> members = accuses.stream() + .map(accuse -> memberLookupService.getMemberById(accuse.getMemberId())) + .map(AccuseMemberInfo::create) + .toList(); return AccuseResponseDto.toDto(accuses.getFirst(), members); }) .toList(); @@ -158,7 +162,7 @@ private List<AccuseResponseDto> convertTargetsToResponseDtos(Page<AccuseTarget> private void sendStatusUpdateNotifications(AccuseStatus status, AccuseTarget target) { List<Member> members = accuseRepository.findByTarget(target).stream() - .map(Accuse::getMember) + .map(accuse -> memberLookupService.getMemberById(accuse.getMemberId())) .toList(); notificationService.sendNotificationToMembers(members, "신고 상태가 " + status.getDescription() + "(으)로 변경되었습니다."); } diff --git a/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java b/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java index 3359e7cb0..b309861b3 100644 --- a/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java +++ b/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java @@ -6,7 +6,6 @@ import org.springframework.stereotype.Repository; import page.clab.api.domain.accuse.domain.Accuse; import page.clab.api.domain.accuse.domain.AccuseTarget; -import page.clab.api.domain.member.domain.Member; import java.util.List; import java.util.Optional; @@ -16,11 +15,11 @@ public interface AccuseRepository extends JpaRepository<Accuse, Long> { Page<Accuse> findAllByOrderByCreatedAtDesc(Pageable pageable); - Optional<Accuse> findByMemberAndTarget(Member member, AccuseTarget target); + Optional<Accuse> findByMemberIdAndTarget(String memberId, AccuseTarget target); List<Accuse> findByTargetOrderByCreatedAtDesc(AccuseTarget accuseTarget); - Page<Accuse> findByMember(Member currentMember, Pageable pageable); + Page<Accuse> findByMemberId(String memberId, Pageable pageable); List<Accuse> findByTarget(AccuseTarget target); diff --git a/src/main/java/page/clab/api/domain/accuse/domain/Accuse.java b/src/main/java/page/clab/api/domain/accuse/domain/Accuse.java index 90f5024d0..fa1734cf7 100644 --- a/src/main/java/page/clab/api/domain/accuse/domain/Accuse.java +++ b/src/main/java/page/clab/api/domain/accuse/domain/Accuse.java @@ -16,7 +16,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.domain.BaseEntity; @Entity @@ -32,9 +31,8 @@ public class Accuse extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - @JoinColumn(name = "member_id", nullable = false) - private Member member; + @Column(name = "member_id", nullable = false) + private String memberId; @ManyToOne @JoinColumns({ diff --git a/src/main/java/page/clab/api/domain/accuse/dto/request/AccuseRequestDto.java b/src/main/java/page/clab/api/domain/accuse/dto/request/AccuseRequestDto.java index 34f60c50d..94d841548 100644 --- a/src/main/java/page/clab/api/domain/accuse/dto/request/AccuseRequestDto.java +++ b/src/main/java/page/clab/api/domain/accuse/dto/request/AccuseRequestDto.java @@ -8,7 +8,6 @@ import page.clab.api.domain.accuse.domain.AccuseStatus; import page.clab.api.domain.accuse.domain.AccuseTarget; import page.clab.api.domain.accuse.domain.TargetType; -import page.clab.api.domain.member.domain.Member; @Getter @Setter @@ -26,9 +25,9 @@ public class AccuseRequestDto { @Schema(description = "신고 사유", example = "부적절한 게시글입니다.", required = true) private String reason; - public static Accuse toEntity(AccuseRequestDto requestDto, Member member, AccuseTarget target) { + public static Accuse toEntity(AccuseRequestDto requestDto, String memberId, AccuseTarget target) { return Accuse.builder() - .member(member) + .memberId(memberId) .target(target) .reason(requestDto.getReason()) .build(); diff --git a/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseMemberInfo.java b/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseMemberInfo.java index 139747c6d..a7b019664 100644 --- a/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseMemberInfo.java +++ b/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseMemberInfo.java @@ -2,10 +2,9 @@ import lombok.Builder; import lombok.Getter; -import page.clab.api.domain.accuse.domain.Accuse; +import page.clab.api.domain.member.domain.Member; import java.time.LocalDateTime; -import java.util.List; @Getter @Builder @@ -17,17 +16,11 @@ public class AccuseMemberInfo { private LocalDateTime createdAt; - public static List<AccuseMemberInfo> create(List<Accuse> accuses) { - return accuses.stream() - .map(AccuseMemberInfo::create) - .toList(); - } - - public static AccuseMemberInfo create(Accuse accuse) { + public static AccuseMemberInfo create(Member member) { return AccuseMemberInfo.builder() - .memberId(accuse.getMember().getId()) - .name(accuse.getMember().getName()) - .createdAt(accuse.getCreatedAt()) + .memberId(member.getId()) + .name(member.getName()) + .createdAt(member.getCreatedAt()) .build(); } diff --git a/src/main/java/page/clab/api/domain/board/domain/Board.java b/src/main/java/page/clab/api/domain/board/domain/Board.java index 44db8437b..9b2e171bb 100644 --- a/src/main/java/page/clab/api/domain/board/domain/Board.java +++ b/src/main/java/page/clab/api/domain/board/domain/Board.java @@ -109,6 +109,10 @@ public boolean isOwner(Member member) { return this.member.isSameMember(member); } + public boolean isOwner(String memberId) { + return this.member.isSameMember(memberId); + } + public void validateAccessPermission(Member member) throws PermissionDeniedException { if (!isOwner(member) && !member.isAdminRole()) { throw new PermissionDeniedException("해당 게시글을 수정할 권한이 없습니다."); diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java index a578dad11..ae6e581ed 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -17,6 +17,8 @@ public interface MemberLookupService { Member getCurrentMember(); + String getCurrentMemberId(); + List<MemberResponseDto> getMembers(); List<Member> findAllMembers(); diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java index 07e4bf5d3..1fd2b004a 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -46,6 +46,11 @@ public Member getCurrentMember() { .orElseThrow(() -> new NotFoundException("[Member] id: " + memberId + "에 해당하는 멤버가 존재하지 않습니다.")); } + @Override + public String getCurrentMemberId() { + return AuthUtil.getAuthenticationInfoMemberId(); + } + @Override public List<MemberResponseDto> getMembers() { List<Member> members = memberRepository.findAll(); diff --git a/src/main/java/page/clab/api/domain/review/domain/Review.java b/src/main/java/page/clab/api/domain/review/domain/Review.java index 1dce023a0..57eabe2f2 100644 --- a/src/main/java/page/clab/api/domain/review/domain/Review.java +++ b/src/main/java/page/clab/api/domain/review/domain/Review.java @@ -64,6 +64,10 @@ public boolean isOwner(Member member) { return this.member.isSameMember(member); } + public boolean isOwner(String memberId) { + return this.member.isSameMember(memberId); + } + public void validateAccessPermission(Member member) throws PermissionDeniedException { if (!isOwner(member) && !member.isAdminRole()) { throw new PermissionDeniedException("해당 후기를 수정/삭제할 권한이 없습니다."); From d986c99b7eb065f16f46b00b3f1b72482d29a710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Sun, 23 Jun 2024 13:15:30 +0900 Subject: [PATCH 18/47] =?UTF-8?q?feat(Accuse):=20Member=EA=B0=80=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=EB=90=98=EB=A9=B4,=20Accuse=EB=8F=84=20?= =?UTF-8?q?=EA=B0=99=EC=9D=B4=20=EC=82=AD=EC=A0=9C=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/AccuseEventProcessor.java | 37 +++++++++++++++++++ .../domain/accuse/dao/AccuseRepository.java | 2 + 2 files changed, 39 insertions(+) create mode 100644 src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java new file mode 100644 index 000000000..ded661eab --- /dev/null +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java @@ -0,0 +1,37 @@ +package page.clab.api.domain.accuse.application; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import page.clab.api.domain.accuse.dao.AccuseRepository; +import page.clab.api.domain.accuse.domain.Accuse; +import page.clab.api.domain.member.event.MemberEventProcessor; +import page.clab.api.domain.member.event.MemberEventProcessorRegistry; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class AccuseEventProcessor implements MemberEventProcessor { + + private final AccuseRepository accuseRepository; + + private final MemberEventProcessorRegistry processorRegistry; + + @PostConstruct + public void init() { + processorRegistry.registerProcessor(this); + } + + @Override + public void processMemberDeleted(String memberId) { + List<Accuse> accuses = accuseRepository.findByMemberId(memberId); + accuseRepository.deleteAll(accuses); + } + + @Override + public void processMemberUpdated(String memberId) { + // do nothing + } + +} diff --git a/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java b/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java index b309861b3..52e3e9366 100644 --- a/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java +++ b/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java @@ -21,6 +21,8 @@ public interface AccuseRepository extends JpaRepository<Accuse, Long> { Page<Accuse> findByMemberId(String memberId, Pageable pageable); + List<Accuse> findByMemberId(String memberId); + List<Accuse> findByTarget(AccuseTarget target); } From a88a474930e08de11a9e986fec0ac7f764992109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Sun, 23 Jun 2024 13:54:05 +0900 Subject: [PATCH 19/47] =?UTF-8?q?feat(Accuse):=20=EC=86=8C=ED=94=84?= =?UTF-8?q?=ED=8A=B8=20=EB=94=9C=EB=A6=AC=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accuse/application/AccuseEventProcessor.java | 5 ++++- .../domain/accuse/application/AccuseService.java | 11 ++++++++--- .../api/domain/accuse/dao/AccuseRepository.java | 16 ++++++++++------ .../clab/api/domain/accuse/domain/Accuse.java | 8 ++++++++ 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java index ded661eab..88a7bb49e 100644 --- a/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java @@ -3,6 +3,7 @@ import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.accuse.dao.AccuseRepository; import page.clab.api.domain.accuse.domain.Accuse; import page.clab.api.domain.member.event.MemberEventProcessor; @@ -24,9 +25,11 @@ public void init() { } @Override + @Transactional public void processMemberDeleted(String memberId) { List<Accuse> accuses = accuseRepository.findByMemberId(memberId); - accuseRepository.deleteAll(accuses); + accuses.forEach(Accuse::delete); + accuseRepository.saveAll(accuses); } @Override diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java index 852c56220..8393637f9 100644 --- a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java @@ -33,6 +33,7 @@ import page.clab.api.global.validation.ValidationService; import java.util.List; +import java.util.Objects; @Service @RequiredArgsConstructor @@ -135,7 +136,7 @@ private AccuseTarget getOrCreateAccuseTarget(AccuseRequestDto requestDto, Target } private Accuse findOrCreateAccuse(AccuseRequestDto requestDto, String memberId, AccuseTarget target) { - return accuseRepository.findByMemberIdAndTarget(memberId, target) + return accuseRepository.findByMemberIdAndTarget(memberId, target.getTargetType(), target.getTargetReferenceId()) .map(existingAccuse -> { existingAccuse.updateReason(requestDto.getReason()); return existingAccuse; @@ -150,18 +151,22 @@ private Accuse findOrCreateAccuse(AccuseRequestDto requestDto, String memberId, private List<AccuseResponseDto> convertTargetsToResponseDtos(Page<AccuseTarget> accuseTargets) { return accuseTargets.stream() .map(accuseTarget -> { - List<Accuse> accuses = accuseRepository.findByTargetOrderByCreatedAtDesc(accuseTarget); + List<Accuse> accuses = accuseRepository.findByTargetOrderByCreatedAtDesc(accuseTarget.getTargetType(), accuseTarget.getTargetReferenceId()); + if (accuses.isEmpty()) { + return null; + } List<AccuseMemberInfo> members = accuses.stream() .map(accuse -> memberLookupService.getMemberById(accuse.getMemberId())) .map(AccuseMemberInfo::create) .toList(); return AccuseResponseDto.toDto(accuses.getFirst(), members); }) + .filter(Objects::nonNull) .toList(); } private void sendStatusUpdateNotifications(AccuseStatus status, AccuseTarget target) { - List<Member> members = accuseRepository.findByTarget(target).stream() + List<Member> members = accuseRepository.findByTarget(target.getTargetType(), target.getTargetReferenceId()).stream() .map(accuse -> memberLookupService.getMemberById(accuse.getMemberId())) .toList(); notificationService.sendNotificationToMembers(members, "신고 상태가 " + status.getDescription() + "(으)로 변경되었습니다."); diff --git a/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java b/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java index 52e3e9366..324aea80a 100644 --- a/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java +++ b/src/main/java/page/clab/api/domain/accuse/dao/AccuseRepository.java @@ -3,9 +3,10 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import page.clab.api.domain.accuse.domain.Accuse; -import page.clab.api.domain.accuse.domain.AccuseTarget; +import page.clab.api.domain.accuse.domain.TargetType; import java.util.List; import java.util.Optional; @@ -13,16 +14,19 @@ @Repository public interface AccuseRepository extends JpaRepository<Accuse, Long> { - Page<Accuse> findAllByOrderByCreatedAtDesc(Pageable pageable); + @Query("SELECT a FROM Accuse a WHERE a.isDeleted = false AND a.memberId = :memberId AND a.target.targetType = :targetType AND a.target.targetReferenceId = :targetReferenceId") + Optional<Accuse> findByMemberIdAndTarget(String memberId, TargetType targetType, Long targetReferenceId); - Optional<Accuse> findByMemberIdAndTarget(String memberId, AccuseTarget target); - - List<Accuse> findByTargetOrderByCreatedAtDesc(AccuseTarget accuseTarget); + @Query("SELECT a FROM Accuse a WHERE a.isDeleted = false AND a.target.targetType = :targetType AND a.target.targetReferenceId = :targetReferenceId ORDER BY a.createdAt DESC") + List<Accuse> findByTargetOrderByCreatedAtDesc(TargetType targetType, Long targetReferenceId); + @Query("SELECT a FROM Accuse a WHERE a.isDeleted = false AND a.memberId = :memberId ORDER BY a.createdAt DESC") Page<Accuse> findByMemberId(String memberId, Pageable pageable); + @Query("SELECT a FROM Accuse a WHERE a.isDeleted = false AND a.memberId = :memberId") List<Accuse> findByMemberId(String memberId); - List<Accuse> findByTarget(AccuseTarget target); + @Query("SELECT a FROM Accuse a WHERE a.isDeleted = false AND a.target.targetType = :targetType AND a.target.targetReferenceId = :targetReferenceId") + List<Accuse> findByTarget(TargetType targetType, Long targetReferenceId); } diff --git a/src/main/java/page/clab/api/domain/accuse/domain/Accuse.java b/src/main/java/page/clab/api/domain/accuse/domain/Accuse.java index fa1734cf7..10e48b4fe 100644 --- a/src/main/java/page/clab/api/domain/accuse/domain/Accuse.java +++ b/src/main/java/page/clab/api/domain/accuse/domain/Accuse.java @@ -16,6 +16,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.SQLRestriction; import page.clab.api.global.common.domain.BaseEntity; @Entity @@ -25,6 +27,8 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false) +@SQLDelete(sql = "UPDATE accuse SET is_deleted = true WHERE id = ?") +@SQLRestriction("is_deleted = false") public class Accuse extends BaseEntity { @Id @@ -49,4 +53,8 @@ public void updateReason(String reason) { this.reason = reason; } + public void delete() { + this.isDeleted = true; + } + } From 61bb43a48c952064acbdb4b3a2dc50e887a11bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Tue, 25 Jun 2024 14:35:53 +0900 Subject: [PATCH 20/47] =?UTF-8?q?feat(Award):=20Award=EC=97=90=EC=84=9C=20?= =?UTF-8?q?Member=EB=A5=BC=20=EC=99=B8=EB=9E=98=ED=82=A4=EB=A1=9C=20?= =?UTF-8?q?=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/AwardEventProcessor.java | 39 +++++++++++++++++++ .../award/application/AwardService.java | 12 +++--- .../api/domain/award/dao/AwardRepository.java | 7 +++- .../domain/award/dao/AwardRepositoryImpl.java | 6 +-- .../clab/api/domain/award/domain/Award.java | 17 ++++---- .../award/dto/request/AwardRequestDto.java | 5 +-- 6 files changed, 64 insertions(+), 22 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java diff --git a/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java b/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java new file mode 100644 index 000000000..8d2ef818f --- /dev/null +++ b/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java @@ -0,0 +1,39 @@ +package page.clab.api.domain.award.application; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import page.clab.api.domain.award.dao.AwardRepository; +import page.clab.api.domain.award.domain.Award; +import page.clab.api.domain.member.event.MemberEventProcessor; +import page.clab.api.domain.member.event.MemberEventProcessorRegistry; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class AwardEventProcessor implements MemberEventProcessor { + + private final AwardRepository awardRepository; + + private final MemberEventProcessorRegistry processorRegistry; + + @PostConstruct + public void init() { + processorRegistry.registerProcessor(this); + } + + @Override + @Transactional + public void processMemberDeleted(String memberId) { + List<Award> awards = awardRepository.findByMemberId(memberId); + awards.forEach(Award::delete); + awardRepository.saveAll(awards); + } + + @Override + public void processMemberUpdated(String memberId) { + // do nothing + } +} diff --git a/src/main/java/page/clab/api/domain/award/application/AwardService.java b/src/main/java/page/clab/api/domain/award/application/AwardService.java index cfa5a2260..cfb50f6cc 100644 --- a/src/main/java/page/clab/api/domain/award/application/AwardService.java +++ b/src/main/java/page/clab/api/domain/award/application/AwardService.java @@ -29,8 +29,8 @@ public class AwardService { @Transactional public Long createAward(AwardRequestDto requestDto) { - Member currentMember = memberLookupService.getCurrentMember(); - Award award = AwardRequestDto.toEntity(requestDto, currentMember); + String currentMemberId = memberLookupService.getCurrentMemberId(); + Award award = AwardRequestDto.toEntity(requestDto, currentMemberId); validationService.checkValid(award); return awardRepository.save(award).getId(); } @@ -43,8 +43,8 @@ public PagedResponseDto<AwardResponseDto> getAwardsByConditions(String memberId, @Transactional(readOnly = true) public PagedResponseDto<AwardResponseDto> getMyAwards(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); - Page<Award> awards = getAwardByMember(pageable, currentMember); + String currentMemberId = memberLookupService.getCurrentMemberId(); + Page<Award> awards = getAwardByMemberId(pageable, currentMemberId); return new PagedResponseDto<>(awards.map(AwardResponseDto::toDto)); } @@ -77,8 +77,8 @@ private Award getAwardByIdOrThrow(Long awardId) { .orElseThrow(() -> new NotFoundException("해당 수상 이력이 존재하지 않습니다.")); } - private Page<Award> getAwardByMember(Pageable pageable, Member member) { - return awardRepository.findAllByMember(member, pageable); + private Page<Award> getAwardByMemberId(Pageable pageable, String memberId) { + return awardRepository.findByMemberId(memberId, pageable); } } \ No newline at end of file diff --git a/src/main/java/page/clab/api/domain/award/dao/AwardRepository.java b/src/main/java/page/clab/api/domain/award/dao/AwardRepository.java index 7037c5531..dac66260f 100644 --- a/src/main/java/page/clab/api/domain/award/dao/AwardRepository.java +++ b/src/main/java/page/clab/api/domain/award/dao/AwardRepository.java @@ -7,14 +7,17 @@ import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.stereotype.Repository; import page.clab.api.domain.award.domain.Award; -import page.clab.api.domain.member.domain.Member; + +import java.util.List; @Repository public interface AwardRepository extends JpaRepository<Award, Long>, AwardRepositoryCustom, QuerydslPredicateExecutor<Award> { - Page<Award> findAllByMember(Member member, Pageable pageable); + Page<Award> findByMemberId(String memberId, Pageable pageable); @Query(value = "SELECT a.* FROM award a WHERE a.is_deleted = true", nativeQuery = true) Page<Award> findAllByIsDeletedTrue(Pageable pageable); + List<Award> findByMemberId(String memberId); + } diff --git a/src/main/java/page/clab/api/domain/award/dao/AwardRepositoryImpl.java b/src/main/java/page/clab/api/domain/award/dao/AwardRepositoryImpl.java index ba1221246..409030277 100644 --- a/src/main/java/page/clab/api/domain/award/dao/AwardRepositoryImpl.java +++ b/src/main/java/page/clab/api/domain/award/dao/AwardRepositoryImpl.java @@ -10,10 +10,10 @@ import page.clab.api.domain.award.domain.Award; import page.clab.api.domain.award.domain.QAward; import page.clab.api.domain.member.domain.QMember; +import page.clab.api.global.util.OrderSpecifierUtil; import java.time.LocalDate; import java.util.List; -import page.clab.api.global.util.OrderSpecifierUtil; @Repository @RequiredArgsConstructor @@ -27,7 +27,7 @@ public Page<Award> findByConditions(String memberId, Long year, Pageable pageabl QMember qMember = QMember.member; BooleanBuilder builder = new BooleanBuilder(); - if (memberId != null) builder.and(qAward.member.id.eq(memberId)); + if (memberId != null) builder.and(qAward.memberId.eq(memberId)); if (year != null) { LocalDate startOfYear = LocalDate.of(year.intValue(), 1, 1); LocalDate endOfYear = LocalDate.of(year.intValue(), 12, 31); @@ -35,7 +35,7 @@ public Page<Award> findByConditions(String memberId, Long year, Pageable pageabl } List<Award> awards = queryFactory.selectFrom(qAward) - .leftJoin(qAward.member, qMember) + .leftJoin(qMember).on(qAward.memberId.eq(qMember.id)) .where(builder) .orderBy(OrderSpecifierUtil.getOrderSpecifiers(pageable, qAward)) .offset(pageable.getOffset()) diff --git a/src/main/java/page/clab/api/domain/award/domain/Award.java b/src/main/java/page/clab/api/domain/award/domain/Award.java index d9f7646e5..e54d92e3c 100644 --- a/src/main/java/page/clab/api/domain/award/domain/Award.java +++ b/src/main/java/page/clab/api/domain/award/domain/Award.java @@ -5,8 +5,6 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; import jakarta.validation.constraints.Size; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -53,9 +51,8 @@ public class Award extends BaseEntity { @Column(nullable = false) private LocalDate awardDate; - @ManyToOne - @JoinColumn(name = "member_id") - private Member member; + @Column(name = "member_id", nullable = false) + private String memberId; public void update(AwardUpdateRequestDto requestDto) { Optional.ofNullable(requestDto.getCompetitionName()).ifPresent(this::setCompetitionName); @@ -64,12 +61,16 @@ public void update(AwardUpdateRequestDto requestDto) { Optional.ofNullable(requestDto.getAwardDate()).ifPresent(this::setAwardDate); } - public boolean isOwner(Member member) { - return this.member.isSameMember(member); + public void delete() { + this.isDeleted = true; + } + + public boolean isOwner(String memberId) { + return this.memberId.equals(memberId); } public void validateAccessPermission(Member member) throws PermissionDeniedException { - if (!isOwner(member) && !member.isAdminRole()) { + if (!isOwner(member.getId()) && !member.isAdminRole()) { throw new PermissionDeniedException("해당 게시글을 수정/삭제할 권한이 없습니다."); } } diff --git a/src/main/java/page/clab/api/domain/award/dto/request/AwardRequestDto.java b/src/main/java/page/clab/api/domain/award/dto/request/AwardRequestDto.java index 80ce4fe91..31f6173fc 100644 --- a/src/main/java/page/clab/api/domain/award/dto/request/AwardRequestDto.java +++ b/src/main/java/page/clab/api/domain/award/dto/request/AwardRequestDto.java @@ -5,7 +5,6 @@ import lombok.Getter; import lombok.Setter; import page.clab.api.domain.award.domain.Award; -import page.clab.api.domain.member.domain.Member; import java.time.LocalDate; @@ -29,13 +28,13 @@ public class AwardRequestDto { @Schema(description = "수상일", example = "2023-08-18", required = true) private LocalDate awardDate; - public static Award toEntity(AwardRequestDto requestDto, Member member) { + public static Award toEntity(AwardRequestDto requestDto, String memberId) { return Award.builder() .competitionName(requestDto.getCompetitionName()) .organizer(requestDto.getOrganizer()) .awardName(requestDto.getAwardName()) .awardDate(requestDto.getAwardDate()) - .member(member) + .memberId(memberId) .build(); } From 3a63c93b92fa3681af5c952fb01522a1073a3aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Tue, 25 Jun 2024 15:14:11 +0900 Subject: [PATCH 21/47] =?UTF-8?q?refactor(Blog):=20Blog=EC=97=90=EC=84=9C?= =?UTF-8?q?=20Member=EB=A5=BC=20=EC=99=B8=EB=9E=98=ED=82=A4=EB=A1=9C=20?= =?UTF-8?q?=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blog/application/BlogEventProcessor.java | 39 +++++++++++++++++++ .../domain/blog/application/BlogService.java | 8 ++-- .../api/domain/blog/dao/BlogRepository.java | 4 ++ .../domain/blog/dao/BlogRepositoryImpl.java | 6 +-- .../clab/api/domain/blog/domain/Blog.java | 13 ++++--- .../blog/dto/request/BlogRequestDto.java | 5 +-- .../dto/response/BlogDetailsResponseDto.java | 7 ++-- 7 files changed, 63 insertions(+), 19 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java diff --git a/src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java b/src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java new file mode 100644 index 000000000..e27ec84a8 --- /dev/null +++ b/src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java @@ -0,0 +1,39 @@ +package page.clab.api.domain.blog.application; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import page.clab.api.domain.blog.dao.BlogRepository; +import page.clab.api.domain.blog.domain.Blog; +import page.clab.api.domain.member.event.MemberEventProcessor; +import page.clab.api.domain.member.event.MemberEventProcessorRegistry; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class BlogEventProcessor implements MemberEventProcessor { + + private final BlogRepository blogRepository; + + private final MemberEventProcessorRegistry processorRegistry; + + @PostConstruct + public void init() { + processorRegistry.registerProcessor(this); + } + + @Override + @Transactional + public void processMemberDeleted(String memberId) { + List<Blog> blogs = blogRepository.findByMemberId(memberId); + blogs.forEach(Blog::delete); + blogRepository.saveAll(blogs); + } + + @Override + public void processMemberUpdated(String memberId) { + // do nothing + } +} diff --git a/src/main/java/page/clab/api/domain/blog/application/BlogService.java b/src/main/java/page/clab/api/domain/blog/application/BlogService.java index 1119a5c6d..5f98d352a 100644 --- a/src/main/java/page/clab/api/domain/blog/application/BlogService.java +++ b/src/main/java/page/clab/api/domain/blog/application/BlogService.java @@ -30,8 +30,8 @@ public class BlogService { @Transactional public Long createBlog(BlogRequestDto requestDto) { - Member currentMember = memberLookupService.getCurrentMember(); - Blog blog = BlogRequestDto.toEntity(requestDto, currentMember); + String currentMemberId = memberLookupService.getCurrentMemberId(); + Blog blog = BlogRequestDto.toEntity(requestDto, currentMemberId); validationService.checkValid(blog); return blogRepository.save(blog).getId(); } @@ -47,7 +47,7 @@ public BlogDetailsResponseDto getBlogDetails(Long blogId) { Member currentMember = memberLookupService.getCurrentMember(); Blog blog = getBlogByIdOrThrow(blogId); boolean isOwner = blog.isOwner(currentMember); - return BlogDetailsResponseDto.toDto(blog, isOwner); + return BlogDetailsResponseDto.toDto(blog, currentMember, isOwner); } @Transactional(readOnly = true) @@ -55,7 +55,7 @@ public PagedResponseDto<BlogDetailsResponseDto> getDeletedBlogs(Pageable pageabl Member currentMember = memberLookupService.getCurrentMember(); Page<Blog> blogs = blogRepository.findAllByIsDeletedTrue(pageable); return new PagedResponseDto<>(blogs - .map(blog -> BlogDetailsResponseDto.toDto(blog, blog.isOwner(currentMember)))); + .map(blog -> BlogDetailsResponseDto.toDto(blog, currentMember, blog.isOwner(currentMember)))); } @Transactional diff --git a/src/main/java/page/clab/api/domain/blog/dao/BlogRepository.java b/src/main/java/page/clab/api/domain/blog/dao/BlogRepository.java index 57c5f8720..6c8465e72 100644 --- a/src/main/java/page/clab/api/domain/blog/dao/BlogRepository.java +++ b/src/main/java/page/clab/api/domain/blog/dao/BlogRepository.java @@ -8,6 +8,8 @@ import org.springframework.stereotype.Repository; import page.clab.api.domain.blog.domain.Blog; +import java.util.List; + @Repository public interface BlogRepository extends JpaRepository<Blog, Long>, BlogRepositoryCustom, QuerydslPredicateExecutor<Blog> { @@ -16,4 +18,6 @@ public interface BlogRepository extends JpaRepository<Blog, Long>, BlogRepositor @Query(value = "SELECT b.* FROM blog b WHERE b.is_deleted = true", nativeQuery = true) Page<Blog> findAllByIsDeletedTrue(Pageable pageable); + List<Blog> findByMemberId(String memberId); + } diff --git a/src/main/java/page/clab/api/domain/blog/dao/BlogRepositoryImpl.java b/src/main/java/page/clab/api/domain/blog/dao/BlogRepositoryImpl.java index fdb01257a..6a3f65266 100644 --- a/src/main/java/page/clab/api/domain/blog/dao/BlogRepositoryImpl.java +++ b/src/main/java/page/clab/api/domain/blog/dao/BlogRepositoryImpl.java @@ -10,9 +10,9 @@ import page.clab.api.domain.blog.domain.Blog; import page.clab.api.domain.blog.domain.QBlog; import page.clab.api.domain.member.domain.QMember; +import page.clab.api.global.util.OrderSpecifierUtil; import java.util.List; -import page.clab.api.global.util.OrderSpecifierUtil; @Repository @RequiredArgsConstructor @@ -31,7 +31,7 @@ public Page<Blog> findByConditions(String title, String memberName, Pageable pag if (memberName != null && !memberName.isBlank()) builder.and(qMember.name.eq(memberName)); List<Blog> blogs = queryFactory.selectFrom(qBlog) - .leftJoin(qBlog.member, qMember) + .leftJoin(qMember).on(qBlog.memberId.eq(qMember.id)) .where(builder) .orderBy(OrderSpecifierUtil.getOrderSpecifiers(pageable, qBlog)) .offset(pageable.getOffset()) @@ -40,7 +40,7 @@ public Page<Blog> findByConditions(String title, String memberName, Pageable pag long count = queryFactory .selectFrom(qBlog) - .leftJoin(qBlog.member, qMember) + .leftJoin(qMember).on(qBlog.memberId.eq(qMember.id)) .where(builder) .fetchCount(); diff --git a/src/main/java/page/clab/api/domain/blog/domain/Blog.java b/src/main/java/page/clab/api/domain/blog/domain/Blog.java index 98994f6fd..6b3ab132d 100644 --- a/src/main/java/page/clab/api/domain/blog/domain/Blog.java +++ b/src/main/java/page/clab/api/domain/blog/domain/Blog.java @@ -5,8 +5,6 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; import jakarta.validation.constraints.Size; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -37,9 +35,8 @@ public class Blog extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - @JoinColumn(name = "member_id", nullable = false) - private Member member; + @Column(name = "member_id", nullable = false) + private String memberId; @Column(nullable = false) @Size(min = 1, max = 100, message = "{size.blog.title}") @@ -64,8 +61,12 @@ public void update(BlogUpdateRequestDto requestDto) { Optional.ofNullable(requestDto.getHyperlink()).ifPresent(this::setHyperlink); } + public void delete() { + this.isDeleted = true; + } + public boolean isOwner(Member member) { - return this.member.isSameMember(member); + return this.memberId.equals(member.getId()); } public void validateAccessPermission(Member member) throws PermissionDeniedException { diff --git a/src/main/java/page/clab/api/domain/blog/dto/request/BlogRequestDto.java b/src/main/java/page/clab/api/domain/blog/dto/request/BlogRequestDto.java index 6bf9d769d..4cdca912a 100644 --- a/src/main/java/page/clab/api/domain/blog/dto/request/BlogRequestDto.java +++ b/src/main/java/page/clab/api/domain/blog/dto/request/BlogRequestDto.java @@ -5,7 +5,6 @@ import lombok.Getter; import lombok.Setter; import page.clab.api.domain.blog.domain.Blog; -import page.clab.api.domain.member.domain.Member; @Getter @Setter @@ -29,9 +28,9 @@ public class BlogRequestDto { @Schema(description = "하이퍼링크", example = "https://www.clab.page") private String hyperlink; - public static Blog toEntity(BlogRequestDto requestDto, Member member) { + public static Blog toEntity(BlogRequestDto requestDto, String memberId) { return Blog.builder() - .member(member) + .memberId(memberId) .title(requestDto.getTitle()) .subTitle(requestDto.getSubTitle()) .content(requestDto.getContent()) diff --git a/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java b/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java index e646dbce2..c96d9808a 100644 --- a/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java +++ b/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java @@ -4,6 +4,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.blog.domain.Blog; +import page.clab.api.domain.member.domain.Member; import java.time.LocalDateTime; @@ -32,11 +33,11 @@ public class BlogDetailsResponseDto { private LocalDateTime createdAt; - public static BlogDetailsResponseDto toDto(Blog blog, boolean isOwner) { + public static BlogDetailsResponseDto toDto(Blog blog, Member member, boolean isOwner) { return BlogDetailsResponseDto.builder() .id(blog.getId()) - .memberId(blog.getMember().getId()) - .name(blog.getMember().getName()) + .memberId(member.getId()) + .name(member.getName()) .title(blog.getTitle()) .subTitle(blog.getSubTitle()) .content(blog.getContent()) From 6d52b3479b2d43c785870e5ddec007a020117878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Tue, 25 Jun 2024 18:08:53 +0900 Subject: [PATCH 22/47] =?UTF-8?q?refactor(Board):=20Board=EC=97=90?= =?UTF-8?q?=EC=84=9C=20Member=EB=A5=BC=20=EC=99=B8=EB=9E=98=ED=82=A4?= =?UTF-8?q?=EB=A1=9C=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/BoardEventProcessor.java | 39 +++++++++++++++++++ .../board/application/BoardService.java | 37 ++++++++++-------- .../api/domain/board/dao/BoardRepository.java | 7 +++- .../clab/api/domain/board/domain/Board.java | 23 +++++------ .../domain/board/domain/SlackBoardInfo.java | 25 ++++++++++++ .../board/dto/request/BoardRequestDto.java | 5 +-- .../response/BoardCategoryResponseDto.java | 6 +-- .../dto/response/BoardDetailsResponseDto.java | 5 ++- .../dto/response/BoardListResponseDto.java | 5 ++- .../dto/response/BoardMyResponseDto.java | 5 ++- .../domain/board/dto/response/WriterInfo.java | 13 ++++--- .../comment/application/CommentService.java | 2 +- .../slack/application/SlackService.java | 4 +- .../slack/application/SlackServiceHelper.java | 14 +++---- 14 files changed, 130 insertions(+), 60 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java create mode 100644 src/main/java/page/clab/api/domain/board/domain/SlackBoardInfo.java diff --git a/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java b/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java new file mode 100644 index 000000000..eef69cf84 --- /dev/null +++ b/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java @@ -0,0 +1,39 @@ +package page.clab.api.domain.board.application; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import page.clab.api.domain.board.dao.BoardRepository; +import page.clab.api.domain.board.domain.Board; +import page.clab.api.domain.member.event.MemberEventProcessor; +import page.clab.api.domain.member.event.MemberEventProcessorRegistry; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class BoardEventProcessor implements MemberEventProcessor { + + private final BoardRepository boardRepository; + + private final MemberEventProcessorRegistry processorRegistry; + + @PostConstruct + public void init() { + processorRegistry.registerProcessor(this); + } + + @Override + @Transactional + public void processMemberDeleted(String memberId) { + List<Board> boards = boardRepository.findByMemberId(memberId); + boards.forEach(Board::delete); + boardRepository.saveAll(boards); + } + + @Override + public void processMemberUpdated(String memberId) { + // do nothing + } +} diff --git a/src/main/java/page/clab/api/domain/board/application/BoardService.java b/src/main/java/page/clab/api/domain/board/application/BoardService.java index 8d4b27eaf..fe68c8937 100644 --- a/src/main/java/page/clab/api/domain/board/application/BoardService.java +++ b/src/main/java/page/clab/api/domain/board/application/BoardService.java @@ -11,6 +11,7 @@ import page.clab.api.domain.board.domain.Board; import page.clab.api.domain.board.domain.BoardCategory; import page.clab.api.domain.board.domain.BoardLike; +import page.clab.api.domain.board.domain.SlackBoardInfo; import page.clab.api.domain.board.dto.request.BoardRequestDto; import page.clab.api.domain.board.dto.request.BoardUpdateRequestDto; import page.clab.api.domain.board.dto.response.BoardCategoryResponseDto; @@ -56,20 +57,22 @@ public class BoardService { public String createBoard(BoardRequestDto requestDto) throws PermissionDeniedException { Member currentMember = memberLookupService.getCurrentMember(); List<UploadedFile> uploadedFiles = uploadedFileService.getUploadedFilesByUrls(requestDto.getFileUrlList()); - Board board = BoardRequestDto.toEntity(requestDto, currentMember, uploadedFiles); + Board board = BoardRequestDto.toEntity(requestDto, currentMember.getId(), uploadedFiles); board.validateAccessPermissionForCreation(currentMember); validationService.checkValid(board); - if (board.shouldNotifyForNewBoard()) { + if (board.shouldNotifyForNewBoard(currentMember)) { notificationService.sendNotificationToMember(currentMember, "[" + board.getTitle() + "] 새로운 공지사항이 등록되었습니다."); } - slackService.sendNewBoardNotification(board); + SlackBoardInfo boardInfo = SlackBoardInfo.create(board, currentMember); + slackService.sendNewBoardNotification(boardInfo); return boardRepository.save(board).getCategory().getKey(); } @Transactional(readOnly = true) public PagedResponseDto<BoardListResponseDto> getBoards(Pageable pageable) { + Member currentMember = memberLookupService.getCurrentMember(); Page<Board> boards = boardRepository.findAll(pageable); - return new PagedResponseDto<>(boards.map(this::mapToBoardListResponseDto)); + return new PagedResponseDto<>(boards.map(board -> mapToBoardListResponseDto(board, currentMember))); } @Transactional(readOnly = true) @@ -77,21 +80,22 @@ public BoardDetailsResponseDto getBoardDetails(Long boardId) { Member currentMember = memberLookupService.getCurrentMember(); Board board = getBoardByIdOrThrow(boardId); boolean hasLikeByMe = checkLikeStatus(board, currentMember); - boolean isOwner = board.isOwner(currentMember); - return BoardDetailsResponseDto.toDto(board, hasLikeByMe, isOwner); + boolean isOwner = board.isOwner(currentMember.getId()); + return BoardDetailsResponseDto.toDto(board, currentMember, hasLikeByMe, isOwner); } @Transactional(readOnly = true) public PagedResponseDto<BoardMyResponseDto> getMyBoards(Pageable pageable) { Member currentMember = memberLookupService.getCurrentMember(); - Page<Board> boards = getBoardByMember(pageable, currentMember); - return new PagedResponseDto<>(boards.map(BoardMyResponseDto::toDto)); + Page<Board> boards = getBoardByMemberId(pageable, currentMember.getId()); + return new PagedResponseDto<>(boards.map(board -> BoardMyResponseDto.toDto(board, currentMember))); } @Transactional(readOnly = true) public PagedResponseDto<BoardCategoryResponseDto> getBoardsByCategory(BoardCategory category, Pageable pageable) { + Member currentMember = memberLookupService.getCurrentMember(); Page<Board> boards = getBoardByCategory(category, pageable); - return new PagedResponseDto<>(boards.map(this::mapToBoardCategoryResponseDto)); + return new PagedResponseDto<>(boards.map(board -> mapToBoardCategoryResponseDto(board, currentMember))); } @Transactional @@ -123,8 +127,9 @@ public Long toggleLikeStatus(Long boardId) { @Transactional(readOnly = true) public PagedResponseDto<BoardListResponseDto> getDeletedBoards(Pageable pageable) { + Member currentMember = memberLookupService.getCurrentMember(); Page<Board> boards = boardRepository.findAllByIsDeletedTrue(pageable); - return new PagedResponseDto<>(boards.map(this::mapToBoardListResponseDto)); + return new PagedResponseDto<>(boards.map(board -> mapToBoardListResponseDto(board, currentMember))); } public String deleteBoard(Long boardId) throws PermissionDeniedException { @@ -136,15 +141,15 @@ public String deleteBoard(Long boardId) throws PermissionDeniedException { } @NotNull - private BoardListResponseDto mapToBoardListResponseDto(Board board) { + private BoardListResponseDto mapToBoardListResponseDto(Board board, Member member) { Long commentCount = commentRepository.countByBoard(board); - return BoardListResponseDto.toDto(board, commentCount); + return BoardListResponseDto.toDto(board, member, commentCount); } @NotNull - private BoardCategoryResponseDto mapToBoardCategoryResponseDto(Board board) { + private BoardCategoryResponseDto mapToBoardCategoryResponseDto(Board board, Member member) { Long commentCount = commentRepository.countByBoard(board); - return BoardCategoryResponseDto.toDto(board, commentCount); + return BoardCategoryResponseDto.toDto(board, member, commentCount); } public Board getBoardByIdOrThrow(Long boardId) { @@ -152,8 +157,8 @@ public Board getBoardByIdOrThrow(Long boardId) { .orElseThrow(() -> new NotFoundException("해당 게시글이 존재하지 않습니다.")); } - private Page<Board> getBoardByMember(Pageable pageable, Member member) { - return boardRepository.findAllByMember(member, pageable); + private Page<Board> getBoardByMemberId(Pageable pageable, String memberId) { + return boardRepository.findAllByMemberId(memberId, pageable); } private Page<Board> getBoardByCategory(BoardCategory category, Pageable pageable) { diff --git a/src/main/java/page/clab/api/domain/board/dao/BoardRepository.java b/src/main/java/page/clab/api/domain/board/dao/BoardRepository.java index 6887d8fa2..11550788a 100644 --- a/src/main/java/page/clab/api/domain/board/dao/BoardRepository.java +++ b/src/main/java/page/clab/api/domain/board/dao/BoardRepository.java @@ -7,18 +7,21 @@ import org.springframework.stereotype.Repository; import page.clab.api.domain.board.domain.Board; import page.clab.api.domain.board.domain.BoardCategory; -import page.clab.api.domain.member.domain.Member; + +import java.util.List; @Repository public interface BoardRepository extends JpaRepository<Board, Long> { Page<Board> findAll(Pageable pageable); - Page<Board> findAllByMember(Member member, Pageable pageable); + Page<Board> findAllByMemberId(String member, Pageable pageable); Page<Board> findAllByCategory(BoardCategory category, Pageable pageable); @Query(value = "SELECT b.* FROM board b WHERE b.is_deleted = true", nativeQuery = true) Page<Board> findAllByIsDeletedTrue(Pageable pageable); + List<Board> findByMemberId(String memberId); + } diff --git a/src/main/java/page/clab/api/domain/board/domain/Board.java b/src/main/java/page/clab/api/domain/board/domain/Board.java index 9b2e171bb..8c0be374f 100644 --- a/src/main/java/page/clab/api/domain/board/domain/Board.java +++ b/src/main/java/page/clab/api/domain/board/domain/Board.java @@ -9,7 +9,6 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.validation.constraints.Size; import lombok.AccessLevel; @@ -22,7 +21,6 @@ import org.hibernate.annotations.SQLRestriction; import page.clab.api.domain.board.dto.request.BoardUpdateRequestDto; import page.clab.api.domain.member.domain.Member; -import page.clab.api.domain.member.domain.Role; import page.clab.api.global.common.domain.BaseEntity; import page.clab.api.global.common.file.domain.UploadedFile; import page.clab.api.global.exception.PermissionDeniedException; @@ -44,9 +42,8 @@ public class Board extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - @JoinColumn(name = "member_id", nullable = false) - private Member member; + @Column(name = "member_id", nullable = false) + private String memberId; @Column(nullable = false) private String nickname; @@ -83,6 +80,10 @@ public void update(BoardUpdateRequestDto boardUpdateRequestDto) { Optional.of(boardUpdateRequestDto.isWantAnonymous()).ifPresent(this::setWantAnonymous); } + public void delete() { + this.isDeleted = true; + } + public boolean isNotice() { return this.category.equals(BoardCategory.NOTICE); } @@ -91,8 +92,8 @@ public boolean isGraduated() { return this.category.equals(BoardCategory.GRADUATED); } - public boolean shouldNotifyForNewBoard() { - return !this.member.getRole().equals(Role.USER) && this.category.equals(BoardCategory.NOTICE); + public boolean shouldNotifyForNewBoard(Member member) { + return member.isAdminRole() && this.category.equals(BoardCategory.NOTICE); } public void incrementLikes() { @@ -105,16 +106,12 @@ public void decrementLikes() { } } - public boolean isOwner(Member member) { - return this.member.isSameMember(member); - } - public boolean isOwner(String memberId) { - return this.member.isSameMember(memberId); + return this.memberId.equals(memberId); } public void validateAccessPermission(Member member) throws PermissionDeniedException { - if (!isOwner(member) && !member.isAdminRole()) { + if (!isOwner(member.getId()) && !member.isAdminRole()) { throw new PermissionDeniedException("해당 게시글을 수정할 권한이 없습니다."); } } diff --git a/src/main/java/page/clab/api/domain/board/domain/SlackBoardInfo.java b/src/main/java/page/clab/api/domain/board/domain/SlackBoardInfo.java new file mode 100644 index 000000000..62c1f4ee8 --- /dev/null +++ b/src/main/java/page/clab/api/domain/board/domain/SlackBoardInfo.java @@ -0,0 +1,25 @@ +package page.clab.api.domain.board.domain; + +import lombok.Builder; +import lombok.Getter; +import page.clab.api.domain.member.domain.Member; + +@Getter +@Builder +public class SlackBoardInfo { + + private String title; + + private String category; + + private String username; + + public static SlackBoardInfo create(Board board, Member member) { + return SlackBoardInfo.builder() + .title(board.getTitle()) + .category(board.getCategory().getDescription()) + .username(board.isWantAnonymous() ? board.getNickname() : member.getId() + " " + member.getName()) + .build(); + } + +} diff --git a/src/main/java/page/clab/api/domain/board/dto/request/BoardRequestDto.java b/src/main/java/page/clab/api/domain/board/dto/request/BoardRequestDto.java index eb011dee7..06bfca15a 100644 --- a/src/main/java/page/clab/api/domain/board/dto/request/BoardRequestDto.java +++ b/src/main/java/page/clab/api/domain/board/dto/request/BoardRequestDto.java @@ -6,7 +6,6 @@ import lombok.Setter; import page.clab.api.domain.board.domain.Board; import page.clab.api.domain.board.domain.BoardCategory; -import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.file.domain.UploadedFile; import page.clab.api.global.util.RandomNicknameUtil; @@ -38,9 +37,9 @@ public class BoardRequestDto { @Schema(description = "익명 사용 여부", example = "false", required = true) private boolean wantAnonymous; - public static Board toEntity(BoardRequestDto requestDto, Member member, List<UploadedFile> uploadedFiles) { + public static Board toEntity(BoardRequestDto requestDto, String memberId, List<UploadedFile> uploadedFiles) { return Board.builder() - .member(member) + .memberId(memberId) .nickname(RandomNicknameUtil.makeRandomNickname()) .category(requestDto.getCategory()) .title(requestDto.getTitle()) diff --git a/src/main/java/page/clab/api/domain/board/dto/response/BoardCategoryResponseDto.java b/src/main/java/page/clab/api/domain/board/dto/response/BoardCategoryResponseDto.java index aaa19f054..c8fdce527 100644 --- a/src/main/java/page/clab/api/domain/board/dto/response/BoardCategoryResponseDto.java +++ b/src/main/java/page/clab/api/domain/board/dto/response/BoardCategoryResponseDto.java @@ -3,7 +3,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.board.domain.Board; -import page.clab.api.domain.board.domain.BoardCategory; +import page.clab.api.domain.member.domain.Member; import java.time.LocalDateTime; @@ -27,8 +27,8 @@ public class BoardCategoryResponseDto { private LocalDateTime createdAt; - public static BoardCategoryResponseDto toDto(Board board, Long commentCount) { - WriterInfo writerInfo = WriterInfo.fromBoard(board); + public static BoardCategoryResponseDto toDto(Board board, Member member, Long commentCount) { + WriterInfo writerInfo = WriterInfo.fromBoard(board, member); return BoardCategoryResponseDto.builder() .id(board.getId()) .category(board.getCategory().getKey()) diff --git a/src/main/java/page/clab/api/domain/board/dto/response/BoardDetailsResponseDto.java b/src/main/java/page/clab/api/domain/board/dto/response/BoardDetailsResponseDto.java index 10ed09778..6155820ad 100644 --- a/src/main/java/page/clab/api/domain/board/dto/response/BoardDetailsResponseDto.java +++ b/src/main/java/page/clab/api/domain/board/dto/response/BoardDetailsResponseDto.java @@ -4,6 +4,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.board.domain.Board; +import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.file.dto.response.UploadedFileResponseDto; import java.time.LocalDateTime; @@ -42,8 +43,8 @@ public class BoardDetailsResponseDto { private LocalDateTime createdAt; - public static BoardDetailsResponseDto toDto(Board board, boolean hasLikeByMe, boolean isOwner) { - WriterInfo writerInfo = WriterInfo.fromBoardDetails(board); + public static BoardDetailsResponseDto toDto(Board board, Member member, boolean hasLikeByMe, boolean isOwner) { + WriterInfo writerInfo = WriterInfo.fromBoardDetails(board, member); return BoardDetailsResponseDto.builder() .id(board.getId()) .writerId(writerInfo.getId()) diff --git a/src/main/java/page/clab/api/domain/board/dto/response/BoardListResponseDto.java b/src/main/java/page/clab/api/domain/board/dto/response/BoardListResponseDto.java index eef2f6165..c509454fd 100644 --- a/src/main/java/page/clab/api/domain/board/dto/response/BoardListResponseDto.java +++ b/src/main/java/page/clab/api/domain/board/dto/response/BoardListResponseDto.java @@ -3,6 +3,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.board.domain.Board; +import page.clab.api.domain.member.domain.Member; import java.time.LocalDateTime; @@ -28,8 +29,8 @@ public class BoardListResponseDto { private LocalDateTime createdAt; - public static BoardListResponseDto toDto(Board board, Long commentCount) { - WriterInfo writerInfo = WriterInfo.fromBoard(board); + public static BoardListResponseDto toDto(Board board, Member member, Long commentCount) { + WriterInfo writerInfo = WriterInfo.fromBoard(board, member); return BoardListResponseDto.builder() .id(board.getId()) .writerId(writerInfo.getId()) diff --git a/src/main/java/page/clab/api/domain/board/dto/response/BoardMyResponseDto.java b/src/main/java/page/clab/api/domain/board/dto/response/BoardMyResponseDto.java index 4842a1a6a..f78875737 100644 --- a/src/main/java/page/clab/api/domain/board/dto/response/BoardMyResponseDto.java +++ b/src/main/java/page/clab/api/domain/board/dto/response/BoardMyResponseDto.java @@ -3,6 +3,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.board.domain.Board; +import page.clab.api.domain.member.domain.Member; import java.time.LocalDateTime; @@ -22,11 +23,11 @@ public class BoardMyResponseDto { private LocalDateTime createdAt; - public static BoardMyResponseDto toDto(Board board) { + public static BoardMyResponseDto toDto(Board board, Member member) { return BoardMyResponseDto.builder() .id(board.getId()) .category(board.getCategory().getKey()) - .writerName(board.isWantAnonymous() ? board.getNickname() : board.getMember().getName()) + .writerName(board.isWantAnonymous() ? board.getNickname() : member.getName()) .title(board.getTitle()) .imageUrl(board.getImageUrl()) .createdAt(board.getCreatedAt()) diff --git a/src/main/java/page/clab/api/domain/board/dto/response/WriterInfo.java b/src/main/java/page/clab/api/domain/board/dto/response/WriterInfo.java index 9ce553141..b8536da75 100644 --- a/src/main/java/page/clab/api/domain/board/dto/response/WriterInfo.java +++ b/src/main/java/page/clab/api/domain/board/dto/response/WriterInfo.java @@ -2,6 +2,7 @@ import lombok.Getter; import page.clab.api.domain.board.domain.Board; +import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.domain.Role; @Getter @@ -27,22 +28,22 @@ public WriterInfo(String id, String name, Long roleLevel, String imageUrl) { this.imageUrl = imageUrl; } - public static WriterInfo fromBoard(Board board) { - if (board.getMember().isAdminRole() && board.isNotice()) { + public static WriterInfo fromBoard(Board board, Member member) { + if (member.isAdminRole() && board.isNotice()) { return new WriterInfo(null, "운영진"); } else if (board.isWantAnonymous()) { return new WriterInfo(null, board.getNickname()); } - return new WriterInfo(board.getMember().getId(), board.getMember().getName()); + return new WriterInfo(member.getId(), member.getName()); } - public static WriterInfo fromBoardDetails(Board board) { - if (board.getMember().isAdminRole() && board.isNotice()) { + public static WriterInfo fromBoardDetails(Board board, Member member) { + if (member.isAdminRole() && board.isNotice()) { return new WriterInfo(null, "운영진", Role.ADMIN.toRoleLevel(), null); } else if (board.isWantAnonymous()) { return new WriterInfo(null, board.getNickname(), null, null); } - return new WriterInfo(board.getMember().getId(), board.getMember().getName(), board.getMember().getRole().toRoleLevel(), board.getMember().getImageUrl()); + return new WriterInfo(member.getId(), member.getName(), member.getRole().toRoleLevel(), member.getImageUrl()); } } diff --git a/src/main/java/page/clab/api/domain/comment/application/CommentService.java b/src/main/java/page/clab/api/domain/comment/application/CommentService.java index 575f5ee78..adef5f5f7 100644 --- a/src/main/java/page/clab/api/domain/comment/application/CommentService.java +++ b/src/main/java/page/clab/api/domain/comment/application/CommentService.java @@ -153,7 +153,7 @@ private Comment findParentComment(Long parentId) { private void sendNotificationForNewComment(Comment comment) { Board board = comment.getBoard(); - Member boardOwner = board.getMember(); + Member boardOwner = memberLookupService.getMemberById(board.getMemberId()); String notificationMessage = String.format("[%s] %s님이 게시글에 댓글을 남겼습니다.", board.getTitle(), comment.getWriterName()); notificationService.sendNotificationToMember(boardOwner, notificationMessage); } diff --git a/src/main/java/page/clab/api/global/common/slack/application/SlackService.java b/src/main/java/page/clab/api/global/common/slack/application/SlackService.java index 8963b6f54..5f2c1a966 100644 --- a/src/main/java/page/clab/api/global/common/slack/application/SlackService.java +++ b/src/main/java/page/clab/api/global/common/slack/application/SlackService.java @@ -8,7 +8,7 @@ import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import page.clab.api.domain.application.dto.request.ApplicationRequestDto; -import page.clab.api.domain.board.domain.Board; +import page.clab.api.domain.board.domain.SlackBoardInfo; import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.slack.domain.GeneralAlertType; import page.clab.api.global.common.slack.domain.SecurityAlertType; @@ -37,7 +37,7 @@ public void sendNewApplicationNotification(ApplicationRequestDto applicationRequ eventPublisher.publishEvent(new NotificationEvent(this, GeneralAlertType.APPLICATION_CREATED, null, applicationRequestDto)); } - public void sendNewBoardNotification(Board board) { + public void sendNewBoardNotification(SlackBoardInfo board) { eventPublisher.publishEvent(new NotificationEvent(this, GeneralAlertType.BOARD_CREATED, null, board)); } diff --git a/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java b/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java index 3bd9c0e6d..67902c100 100644 --- a/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java +++ b/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java @@ -21,7 +21,7 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import page.clab.api.domain.application.dto.request.ApplicationRequestDto; -import page.clab.api.domain.board.domain.Board; +import page.clab.api.domain.board.domain.SlackBoardInfo; import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.slack.domain.AlertType; import page.clab.api.global.common.slack.domain.GeneralAlertType; @@ -113,8 +113,8 @@ public List<LayoutBlock> createBlocks(AlertType alertType, HttpServletRequest re } break; case BOARD_CREATED: - if (additionalData instanceof Board) { - return createBoardBlocks((Board) additionalData); + if (additionalData instanceof SlackBoardInfo) { + return createBoardBlocks((SlackBoardInfo) additionalData); } break; case SERVER_START: @@ -205,16 +205,14 @@ private List<LayoutBlock> createApplicationBlocks(ApplicationRequestDto requestD return blocks; } - private List<LayoutBlock> createBoardBlocks(Board board) { + private List<LayoutBlock> createBoardBlocks(SlackBoardInfo board) { List<LayoutBlock> blocks = new ArrayList<>(); - String username = board.isWantAnonymous() ? - board.getNickname() : board.getMember().getId() + " " + board.getMember().getName(); blocks.add(section(section -> section.text(markdownText(":writing_hand: *New Board*")))); blocks.add(section(section -> section.fields(Arrays.asList( markdownText("*Title:*\n" + board.getTitle()), - markdownText("*Category:*\n" + board.getCategory().getDescription()), - markdownText("*User:*\n" + username) + markdownText("*Category:*\n" + board.getCategory()), + markdownText("*User:*\n" + board.getUsername()) )))); return blocks; } From d5e5eba050d482174d9537f5f26fa813a57d79c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Tue, 25 Jun 2024 19:24:47 +0900 Subject: [PATCH 23/47] =?UTF-8?q?refactor(Member):=20Member=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EB=B3=80=EA=B2=BD=EC=8B=9C=20memberId=EA=B0=80=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20Member=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=EB=A1=9C=20=EB=B3=B4=EB=82=B4?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/accuse/application/AccuseEventProcessor.java | 7 ++++--- .../api/domain/award/application/AwardEventProcessor.java | 7 ++++--- .../api/domain/blog/application/BlogEventProcessor.java | 7 ++++--- .../api/domain/board/application/BoardEventProcessor.java | 7 ++++--- .../clab/api/domain/member/application/MemberService.java | 4 ++-- .../clab/api/domain/member/event/MemberDeletedEvent.java | 7 ++++--- .../api/domain/member/event/MemberEventDispatcher.java | 4 ++-- .../clab/api/domain/member/event/MemberEventProcessor.java | 6 ++++-- .../clab/api/domain/member/event/MemberUpdatedEvent.java | 7 ++++--- 9 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java index 88a7bb49e..6dab8da72 100644 --- a/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java @@ -6,6 +6,7 @@ import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.accuse.dao.AccuseRepository; import page.clab.api.domain.accuse.domain.Accuse; +import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.event.MemberEventProcessor; import page.clab.api.domain.member.event.MemberEventProcessorRegistry; @@ -26,14 +27,14 @@ public void init() { @Override @Transactional - public void processMemberDeleted(String memberId) { - List<Accuse> accuses = accuseRepository.findByMemberId(memberId); + public void processMemberDeleted(Member member) { + List<Accuse> accuses = accuseRepository.findByMemberId(member.getId()); accuses.forEach(Accuse::delete); accuseRepository.saveAll(accuses); } @Override - public void processMemberUpdated(String memberId) { + public void processMemberUpdated(Member member) { // do nothing } diff --git a/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java b/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java index 8d2ef818f..2372393aa 100644 --- a/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java +++ b/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java @@ -6,6 +6,7 @@ import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.award.dao.AwardRepository; import page.clab.api.domain.award.domain.Award; +import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.event.MemberEventProcessor; import page.clab.api.domain.member.event.MemberEventProcessorRegistry; @@ -26,14 +27,14 @@ public void init() { @Override @Transactional - public void processMemberDeleted(String memberId) { - List<Award> awards = awardRepository.findByMemberId(memberId); + public void processMemberDeleted(Member member) { + List<Award> awards = awardRepository.findByMemberId(member.getId()); awards.forEach(Award::delete); awardRepository.saveAll(awards); } @Override - public void processMemberUpdated(String memberId) { + public void processMemberUpdated(Member member) { // do nothing } } diff --git a/src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java b/src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java index e27ec84a8..bd1a1d131 100644 --- a/src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java +++ b/src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java @@ -6,6 +6,7 @@ import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.blog.dao.BlogRepository; import page.clab.api.domain.blog.domain.Blog; +import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.event.MemberEventProcessor; import page.clab.api.domain.member.event.MemberEventProcessorRegistry; @@ -26,14 +27,14 @@ public void init() { @Override @Transactional - public void processMemberDeleted(String memberId) { - List<Blog> blogs = blogRepository.findByMemberId(memberId); + public void processMemberDeleted(Member member) { + List<Blog> blogs = blogRepository.findByMemberId(member.getId()); blogs.forEach(Blog::delete); blogRepository.saveAll(blogs); } @Override - public void processMemberUpdated(String memberId) { + public void processMemberUpdated(Member member) { // do nothing } } diff --git a/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java b/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java index eef69cf84..e7ffa7a03 100644 --- a/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java +++ b/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java @@ -6,6 +6,7 @@ import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.board.dao.BoardRepository; import page.clab.api.domain.board.domain.Board; +import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.event.MemberEventProcessor; import page.clab.api.domain.member.event.MemberEventProcessorRegistry; @@ -26,14 +27,14 @@ public void init() { @Override @Transactional - public void processMemberDeleted(String memberId) { - List<Board> boards = boardRepository.findByMemberId(memberId); + public void processMemberDeleted(Member member) { + List<Board> boards = boardRepository.findByMemberId(member.getId()); boards.forEach(Board::delete); boardRepository.saveAll(boards); } @Override - public void processMemberUpdated(String memberId) { + public void processMemberUpdated(Member member) { // do nothing } } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberService.java b/src/main/java/page/clab/api/domain/member/application/MemberService.java index 189b5b9a4..820fdb6b2 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberService.java @@ -119,7 +119,7 @@ public String updateMemberInfo(String memberId, MemberUpdateRequestDto requestDt updateMember(requestDto, member); validationService.checkValid(member); memberRepository.save(member); - eventPublisher.publishEvent(new MemberUpdatedEvent(this, member.getId())); + eventPublisher.publishEvent(new MemberUpdatedEvent(this, member)); return member.getId(); } @@ -143,7 +143,7 @@ public String verifyResetMemberPassword(VerificationRequestDto requestDto) { public String deleteMember(String memberId) { Member member = memberLookupService.getMemberByIdOrThrow(memberId); memberRepository.delete(member); - eventPublisher.publishEvent(new MemberDeletedEvent(this, member.getId())); + eventPublisher.publishEvent(new MemberDeletedEvent(this, member)); return member.getId(); } diff --git a/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java b/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java index c9d40fa5e..692247e07 100644 --- a/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java +++ b/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java @@ -2,15 +2,16 @@ import lombok.Getter; import org.springframework.context.ApplicationEvent; +import page.clab.api.domain.member.domain.Member; @Getter public class MemberDeletedEvent extends ApplicationEvent { - private final String memberId; + private final Member member; - public MemberDeletedEvent(Object source, String memberId) { + public MemberDeletedEvent(Object source, Member member) { super(source); - this.memberId = memberId; + this.member = member; } } diff --git a/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java b/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java index 76746915d..4081107c0 100644 --- a/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java +++ b/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java @@ -14,11 +14,11 @@ public class MemberEventDispatcher { @EventListener public void handleMemberDeletedEvent(MemberDeletedEvent event) { - processors.forEach(processor -> processor.processMemberDeleted(event.getMemberId())); + processors.forEach(processor -> processor.processMemberDeleted(event.getMember())); } @EventListener public void handleMemberUpdatedEvent(MemberUpdatedEvent event) { - processors.forEach(processor -> processor.processMemberUpdated(event.getMemberId())); + processors.forEach(processor -> processor.processMemberUpdated(event.getMember())); } } diff --git a/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java b/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java index f3d34ca62..0bcb8fc4f 100644 --- a/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java +++ b/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java @@ -1,9 +1,11 @@ package page.clab.api.domain.member.event; +import page.clab.api.domain.member.domain.Member; + public interface MemberEventProcessor { - void processMemberDeleted(String memberId); + void processMemberDeleted(Member member); - void processMemberUpdated(String memberId); + void processMemberUpdated(Member member); } diff --git a/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java b/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java index b1bc7b142..37efe8d1b 100644 --- a/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java +++ b/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java @@ -2,15 +2,16 @@ import lombok.Getter; import org.springframework.context.ApplicationEvent; +import page.clab.api.domain.member.domain.Member; @Getter public class MemberUpdatedEvent extends ApplicationEvent { - private final String memberId; + private final Member member; - public MemberUpdatedEvent(Object source, String memberId) { + public MemberUpdatedEvent(Object source, Member member) { super(source); - this.memberId = memberId; + this.member = member; } } From d1f850b3aa9d182c6d2b9614b6fb92c2ff8f65cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Tue, 25 Jun 2024 19:40:31 +0900 Subject: [PATCH 24/47] =?UTF-8?q?refactor(Member):=20Book=EC=97=90?= =?UTF-8?q?=EC=84=9C=20Member=EB=A5=BC=20=EC=99=B8=EB=9E=98=ED=82=A4?= =?UTF-8?q?=EB=A1=9C=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../book/application/BookEventProcessor.java | 34 +++++++++++++++++++ .../application/BookLoanRecordService.java | 30 ++++++++-------- .../domain/book/application/BookService.java | 5 ++- .../book/dao/BookLoanRecordRepository.java | 3 +- .../dao/BookLoanRecordRepositoryImpl.java | 12 +++---- .../api/domain/book/dao/BookRepository.java | 3 +- .../domain/book/dao/BookRepositoryImpl.java | 6 ++-- .../clab/api/domain/book/domain/Book.java | 27 ++++++++------- .../domain/book/domain/BookLoanRecord.java | 22 +++++++----- .../dto/response/BookDetailsResponseDto.java | 4 +-- .../book/dto/response/BookResponseDto.java | 4 +-- 11 files changed, 95 insertions(+), 55 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/book/application/BookEventProcessor.java diff --git a/src/main/java/page/clab/api/domain/book/application/BookEventProcessor.java b/src/main/java/page/clab/api/domain/book/application/BookEventProcessor.java new file mode 100644 index 000000000..45af568a8 --- /dev/null +++ b/src/main/java/page/clab/api/domain/book/application/BookEventProcessor.java @@ -0,0 +1,34 @@ +package page.clab.api.domain.book.application; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.event.MemberEventProcessor; +import page.clab.api.domain.member.event.MemberEventProcessorRegistry; + +@Component +@RequiredArgsConstructor +public class BookEventProcessor implements MemberEventProcessor { + + private final MemberEventProcessorRegistry processorRegistry; + + @PostConstruct + public void init() { + processorRegistry.registerProcessor(this); + } + + @Override + @Transactional + public void processMemberDeleted(Member member) { + // do nothing + } + + @Override + @Transactional + public void processMemberUpdated(Member member) { + // do nothing + } + +} diff --git a/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java b/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java index 900781678..885488eb7 100644 --- a/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java +++ b/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java @@ -46,10 +46,10 @@ public Long requestBookLoan(BookLoanRecordRequestDto requestDto) throws CustomOp Member borrower = memberLookupService.getCurrentMember(); borrower.checkLoanSuspension(); - validateBorrowLimit(borrower); + validateBorrowLimit(borrower.getId()); Book book = bookService.getBookByIdOrThrow(requestDto.getBookId()); - checkIfLoanAlreadyApplied(book, borrower); + checkIfLoanAlreadyApplied(book, borrower.getId()); BookLoanRecord bookLoanRecord = BookLoanRecord.create(book, borrower); validationService.checkValid(bookLoanRecord); @@ -64,41 +64,43 @@ public Long requestBookLoan(BookLoanRecordRequestDto requestDto) throws CustomOp @Transactional public Long returnBook(BookLoanRecordRequestDto requestDto) { Member currentMember = memberLookupService.getCurrentMember(); + String currentMemberId = currentMember.getId(); Book book = bookService.getBookByIdOrThrow(requestDto.getBookId()); - book.returnBook(currentMember); + book.returnBook(currentMemberId); bookRepository.save(book); BookLoanRecord bookLoanRecord = getBookLoanRecordByBookAndReturnedAtIsNullOrThrow(book); - bookLoanRecord.markAsReturned(); + bookLoanRecord.markAsReturned(currentMember); validationService.checkValid(bookLoanRecord); - notificationService.sendNotificationToMember(currentMember.getId(), "[" + book.getTitle() + "] 도서 반납이 완료되었습니다."); + notificationService.sendNotificationToMember(currentMemberId, "[" + book.getTitle() + "] 도서 반납이 완료되었습니다."); return bookLoanRecordRepository.save(bookLoanRecord).getId(); } @Transactional public Long extendBookLoan(BookLoanRecordRequestDto requestDto) { Member currentMember = memberLookupService.getCurrentMember(); + String currentMemberId = currentMember.getId(); Book book = bookService.getBookByIdOrThrow(requestDto.getBookId()); - book.validateCurrentBorrower(currentMember); + book.validateCurrentBorrower(currentMemberId); BookLoanRecord bookLoanRecord = getBookLoanRecordByBookAndReturnedAtIsNullOrThrow(book); - bookLoanRecord.extendLoan(); + bookLoanRecord.extendLoan(currentMember); validationService.checkValid(bookLoanRecord); - notificationService.sendNotificationToMember(currentMember.getId(), "[" + book.getTitle() + "] 도서 대출 연장이 완료되었습니다."); + notificationService.sendNotificationToMember(currentMemberId, "[" + book.getTitle() + "] 도서 대출 연장이 완료되었습니다."); return bookLoanRecordRepository.save(bookLoanRecord).getId(); } @Transactional public Long approveBookLoan(Long bookLoanRecordId) { - Member currentMember = memberLookupService.getCurrentMember(); + String currentMemberId = memberLookupService.getCurrentMemberId(); BookLoanRecord bookLoanRecord = getBookLoanRecordByIdOrThrow(bookLoanRecordId); Book book = bookService.getBookByIdOrThrow(bookLoanRecord.getBook().getId()); book.validateBookIsNotBorrowed(); - validateBorrowLimit(currentMember); + validateBorrowLimit(currentMemberId); bookLoanRecord.approve(); validationService.checkValid(bookLoanRecord); @@ -134,16 +136,16 @@ public BookLoanRecord getBookLoanRecordByBookAndReturnedAtIsNullOrThrow(Book boo .orElseThrow(() -> new NotFoundException("해당 도서 대출 기록이 없습니다.")); } - private void validateBorrowLimit(Member borrower) { - int borrowedBookCount = bookService.getNumberOfBooksBorrowedByMember(borrower); + private void validateBorrowLimit(String borrowerId) { + int borrowedBookCount = bookService.getNumberOfBooksBorrowedByMember(borrowerId); int maxBorrowableBookCount = 3; if (borrowedBookCount >= maxBorrowableBookCount) { throw new MaxBorrowLimitExceededException("대출 가능한 도서의 수를 초과했습니다."); } } - private void checkIfLoanAlreadyApplied(Book book, Member borrower) { - bookLoanRecordRepository.findByBookAndBorrowerAndStatus(book, borrower, BookLoanStatus.PENDING) + private void checkIfLoanAlreadyApplied(Book book, String borrowerId) { + bookLoanRecordRepository.findByBookAndBorrowerIdAndStatus(book, borrowerId, BookLoanStatus.PENDING) .ifPresent(bookLoanRecord -> { throw new BookAlreadyAppliedForLoanException("이미 대출 신청한 도서입니다."); }); diff --git a/src/main/java/page/clab/api/domain/book/application/BookService.java b/src/main/java/page/clab/api/domain/book/application/BookService.java index b4e483478..3f5d0db75 100644 --- a/src/main/java/page/clab/api/domain/book/application/BookService.java +++ b/src/main/java/page/clab/api/domain/book/application/BookService.java @@ -15,7 +15,6 @@ import page.clab.api.domain.book.dto.request.BookUpdateRequestDto; import page.clab.api.domain.book.dto.response.BookDetailsResponseDto; import page.clab.api.domain.book.dto.response.BookResponseDto; -import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; @@ -77,8 +76,8 @@ public BookLoanRecord getBookLoanRecordByBookAndReturnedAtIsNull(Book book) { .orElse(null); } - public int getNumberOfBooksBorrowedByMember(Member member) { - return bookRepository.countByBorrower(member); + public int getNumberOfBooksBorrowedByMember(String member) { + return bookRepository.countByBorrowerId(member); } private LocalDateTime getDueDateForBook(Book book) { diff --git a/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepository.java b/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepository.java index 0998e4554..b65d7ced3 100644 --- a/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepository.java +++ b/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepository.java @@ -4,7 +4,6 @@ import page.clab.api.domain.book.domain.Book; import page.clab.api.domain.book.domain.BookLoanRecord; import page.clab.api.domain.book.domain.BookLoanStatus; -import page.clab.api.domain.member.domain.Member; import java.util.Optional; @@ -12,6 +11,6 @@ public interface BookLoanRecordRepository extends JpaRepository<BookLoanRecord, Optional<BookLoanRecord> findByBookAndReturnedAtIsNullAndStatus(Book book, BookLoanStatus bookLoanStatus); - Optional<Object> findByBookAndBorrowerAndStatus(Book book, Member borrower, BookLoanStatus bookLoanStatus); + Optional<Object> findByBookAndBorrowerIdAndStatus(Book book, String borrowerId, BookLoanStatus bookLoanStatus); } diff --git a/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepositoryImpl.java b/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepositoryImpl.java index ac79295ff..34e0ed84f 100644 --- a/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepositoryImpl.java +++ b/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepositoryImpl.java @@ -12,10 +12,10 @@ import page.clab.api.domain.book.domain.QBookLoanRecord; import page.clab.api.domain.book.dto.response.BookLoanRecordOverdueResponseDto; import page.clab.api.domain.book.dto.response.BookLoanRecordResponseDto; +import page.clab.api.global.util.OrderSpecifierUtil; import java.time.LocalDateTime; import java.util.List; -import page.clab.api.global.util.OrderSpecifierUtil; @Repository @RequiredArgsConstructor @@ -29,7 +29,7 @@ public Page<BookLoanRecordResponseDto> findByConditions(Long bookId, String borr BooleanBuilder builder = new BooleanBuilder(); if (bookId != null) builder.and(bookLoanRecord.book.id.eq(bookId)); - if (borrowerId != null && !borrowerId.trim().isEmpty()) builder.and(bookLoanRecord.borrower.id.eq(borrowerId)); + if (borrowerId != null && !borrowerId.trim().isEmpty()) builder.and(bookLoanRecord.borrowerId.eq(borrowerId)); if (status != null) builder.and(bookLoanRecord.status.eq(status)); List<BookLoanRecordResponseDto> results = queryFactory @@ -39,8 +39,8 @@ public Page<BookLoanRecordResponseDto> findByConditions(Long bookId, String borr bookLoanRecord.book.id, bookLoanRecord.book.title, bookLoanRecord.book.imageUrl, - bookLoanRecord.borrower.id, - bookLoanRecord.borrower.name, + bookLoanRecord.borrowerId, + bookLoanRecord.borrowerName, bookLoanRecord.borrowedAt, bookLoanRecord.returnedAt, bookLoanRecord.dueDate, @@ -73,8 +73,8 @@ public Page<BookLoanRecordOverdueResponseDto> findOverdueBookLoanRecords(Pageabl BookLoanRecordOverdueResponseDto.class, bookLoanRecord.book.id, bookLoanRecord.book.title, - bookLoanRecord.borrower.id, - bookLoanRecord.borrower.name, + bookLoanRecord.borrowerId, + bookLoanRecord.borrowerName, bookLoanRecord.borrowedAt, bookLoanRecord.dueDate, bookLoanRecord.status diff --git a/src/main/java/page/clab/api/domain/book/dao/BookRepository.java b/src/main/java/page/clab/api/domain/book/dao/BookRepository.java index 2944b2ec6..03927aa21 100644 --- a/src/main/java/page/clab/api/domain/book/dao/BookRepository.java +++ b/src/main/java/page/clab/api/domain/book/dao/BookRepository.java @@ -6,7 +6,6 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.querydsl.QuerydslPredicateExecutor; import page.clab.api.domain.book.domain.Book; -import page.clab.api.domain.member.domain.Member; import java.util.List; @@ -14,7 +13,7 @@ public interface BookRepository extends JpaRepository<Book, Long>, BookRepositor List<Book> findAllByOrderByCreatedAtDesc(); - int countByBorrower(Member member); + int countByBorrowerId(String memberId); @Query(value = "SELECT b.* FROM book b WHERE b.is_deleted = true", nativeQuery = true) Page<Book> findAllByIsDeletedTrue(Pageable pageable); diff --git a/src/main/java/page/clab/api/domain/book/dao/BookRepositoryImpl.java b/src/main/java/page/clab/api/domain/book/dao/BookRepositoryImpl.java index a904c02b2..e6bd7e2e2 100644 --- a/src/main/java/page/clab/api/domain/book/dao/BookRepositoryImpl.java +++ b/src/main/java/page/clab/api/domain/book/dao/BookRepositoryImpl.java @@ -10,9 +10,9 @@ import page.clab.api.domain.book.domain.Book; import page.clab.api.domain.book.domain.QBook; import page.clab.api.domain.member.domain.QMember; +import page.clab.api.global.util.OrderSpecifierUtil; import java.util.List; -import page.clab.api.global.util.OrderSpecifierUtil; @Repository @RequiredArgsConstructor @@ -33,7 +33,7 @@ public Page<Book> findByConditions(String title, String category, String publish if (borrowerName != null) builder.and(borrower.name.eq(borrowerName)); List<Book> books = queryFactory.selectFrom(book) - .leftJoin(book.borrower, borrower) + .leftJoin(borrower).on(book.borrowerId.eq(borrower.id)) .where(builder) .orderBy(OrderSpecifierUtil.getOrderSpecifiers(pageable, book)) .offset(pageable.getOffset()) @@ -41,7 +41,7 @@ public Page<Book> findByConditions(String title, String category, String publish .fetch(); long count = queryFactory.selectFrom(book) - .leftJoin(book.borrower, borrower) + .leftJoin(borrower).on(book.borrowerId.eq(borrower.id)) .where(builder) .fetchCount(); diff --git a/src/main/java/page/clab/api/domain/book/domain/Book.java b/src/main/java/page/clab/api/domain/book/domain/Book.java index 03e451f53..640154bed 100644 --- a/src/main/java/page/clab/api/domain/book/domain/Book.java +++ b/src/main/java/page/clab/api/domain/book/domain/Book.java @@ -6,8 +6,6 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; import jakarta.persistence.Version; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -19,7 +17,6 @@ import page.clab.api.domain.book.dto.request.BookUpdateRequestDto; import page.clab.api.domain.book.exception.BookAlreadyBorrowedException; import page.clab.api.domain.book.exception.InvalidBorrowerException; -import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.domain.BaseEntity; import page.clab.api.global.util.StringJsonConverter; @@ -57,9 +54,11 @@ public class Book extends BaseEntity { @Convert(converter = StringJsonConverter.class) private List<String> reviewLinks; - @ManyToOne - @JoinColumn(name = "member_id") - private Member borrower; + @Column(name = "member_id") + private String borrowerId; + + @Column(name = "member_name") + private String borrowerName; @Version private Long version; @@ -77,19 +76,23 @@ public void updateIsDeleted(Boolean isDeleted) { this.isDeleted = isDeleted; } + public boolean isBorrower(String borrowerId) { + return this.borrowerId == null || !this.borrowerId.equals(borrowerId); + } + public void validateBookIsNotBorrowed() { - if (this.borrower != null) { + if (this.borrowerId != null) { throw new BookAlreadyBorrowedException("이미 대출 중인 도서입니다."); } } - public void returnBook(Member currentMember) { - validateCurrentBorrower(currentMember); - this.borrower = null; + public void returnBook(String borrowerId) { + validateCurrentBorrower(borrowerId); + this.borrowerId = null; } - public void validateCurrentBorrower(Member currentMember) { - if (this.borrower == null || !this.borrower.equals(currentMember)) { + public void validateCurrentBorrower(String borrowerId) { + if (isBorrower(borrowerId)) { throw new InvalidBorrowerException("대출한 도서와 회원 정보가 일치하지 않습니다."); } } diff --git a/src/main/java/page/clab/api/domain/book/domain/BookLoanRecord.java b/src/main/java/page/clab/api/domain/book/domain/BookLoanRecord.java index 93aa70f45..aeed93507 100644 --- a/src/main/java/page/clab/api/domain/book/domain/BookLoanRecord.java +++ b/src/main/java/page/clab/api/domain/book/domain/BookLoanRecord.java @@ -1,5 +1,6 @@ package page.clab.api.domain.book.domain; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; @@ -40,9 +41,11 @@ public class BookLoanRecord extends BaseEntity { @JoinColumn(name = "book_id", nullable = false) private Book book; - @ManyToOne - @JoinColumn(name = "member_id", nullable = false) - private Member borrower; + @Column(name = "member_id", nullable = false) + private String borrowerId; + + @Column(name = "member_name", nullable = false) + private String borrowerName; private LocalDateTime borrowedAt; @@ -58,20 +61,21 @@ public class BookLoanRecord extends BaseEntity { public static BookLoanRecord create(Book book, Member borrower) { return BookLoanRecord.builder() .book(book) - .borrower(borrower) + .borrowerId(borrower.getId()) + .borrowerName(borrower.getName()) .loanExtensionCount(0L) .status(BookLoanStatus.PENDING) .build(); } - public void markAsReturned() { + public void markAsReturned(Member borrower) { if (this.returnedAt != null) { throw new BookAlreadyReturnedException("이미 반납된 도서입니다."); } this.returnedAt = LocalDateTime.now(); if (isOverdue(returnedAt)) { long overdueDays = ChronoUnit.DAYS.between(this.dueDate, this.returnedAt); - this.borrower.handleOverdueAndSuspension(overdueDays); + borrower.handleOverdueAndSuspension(overdueDays); } this.status = BookLoanStatus.RETURNED; } @@ -80,11 +84,11 @@ private boolean isOverdue(LocalDateTime returnedAt) { return returnedAt.isAfter(this.dueDate); } - public void extendLoan() { + public void extendLoan(Member borrower) { final long MAX_EXTENSIONS = 2; LocalDateTime now = LocalDateTime.now(); - if (this.borrower.getLoanSuspensionDate() != null && now.isBefore(this.borrower.getLoanSuspensionDate())) { + if (borrower.getLoanSuspensionDate() != null && now.isBefore(borrower.getLoanSuspensionDate())) { throw new LoanSuspensionException("대출 정지 중입니다. 연장할 수 없습니다."); } if (now.isAfter(this.dueDate)) { @@ -102,7 +106,7 @@ public void approve() { if (this.status != BookLoanStatus.PENDING) { throw new LoanNotPendingException("대출 신청 상태가 아닙니다."); } - this.book.setBorrower(this.borrower); + this.book.setBorrowerId(this.borrowerId); this.status = BookLoanStatus.APPROVED; this.borrowedAt = LocalDateTime.now(); this.dueDate = LocalDateTime.now().plusWeeks(1); diff --git a/src/main/java/page/clab/api/domain/book/dto/response/BookDetailsResponseDto.java b/src/main/java/page/clab/api/domain/book/dto/response/BookDetailsResponseDto.java index 7e5c0c459..a5f69adf9 100644 --- a/src/main/java/page/clab/api/domain/book/dto/response/BookDetailsResponseDto.java +++ b/src/main/java/page/clab/api/domain/book/dto/response/BookDetailsResponseDto.java @@ -38,8 +38,8 @@ public class BookDetailsResponseDto { public static BookDetailsResponseDto toDto(Book book, LocalDateTime dueDate) { return BookDetailsResponseDto.builder() .id(book.getId()) - .borrowerId(book.getBorrower() == null ? null : book.getBorrower().getId()) - .borrowerName(book.getBorrower() == null ? null : book.getBorrower().getName()) + .borrowerId(book.getBorrowerId() == null ? null : book.getBorrowerId()) + .borrowerName(book.getBorrowerName() == null ? null : book.getBorrowerName()) .category(book.getCategory()) .title(book.getTitle()) .author(book.getAuthor()) diff --git a/src/main/java/page/clab/api/domain/book/dto/response/BookResponseDto.java b/src/main/java/page/clab/api/domain/book/dto/response/BookResponseDto.java index 5920cf05e..df642cb19 100644 --- a/src/main/java/page/clab/api/domain/book/dto/response/BookResponseDto.java +++ b/src/main/java/page/clab/api/domain/book/dto/response/BookResponseDto.java @@ -35,8 +35,8 @@ public class BookResponseDto { public static BookResponseDto toDto(Book book, LocalDateTime dueDate) { return BookResponseDto.builder() .id(book.getId()) - .borrowerId(book.getBorrower() == null ? null : book.getBorrower().getId()) - .borrowerName(book.getBorrower() == null ? null : book.getBorrower().getName()) + .borrowerId(book.getBorrowerId() == null ? null : book.getBorrowerId()) + .borrowerName(book.getBorrowerName() == null ? null : book.getBorrowerName()) .category(book.getCategory()) .title(book.getTitle()) .author(book.getAuthor()) From faed6a92f8cd9f3845c88c549221fa79d8b06783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 00:43:50 +0900 Subject: [PATCH 25/47] =?UTF-8?q?refactor(Award):=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B6=8C=ED=95=9C=20=EA=B2=80=EC=82=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../clab/api/domain/award/application/AwardService.java | 3 ++- src/main/java/page/clab/api/domain/award/domain/Award.java | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/page/clab/api/domain/award/application/AwardService.java b/src/main/java/page/clab/api/domain/award/application/AwardService.java index cfb50f6cc..840dfcf49 100644 --- a/src/main/java/page/clab/api/domain/award/application/AwardService.java +++ b/src/main/java/page/clab/api/domain/award/application/AwardService.java @@ -62,7 +62,8 @@ public Long deleteAward(Long awardId) throws PermissionDeniedException { Member currentMember = memberLookupService.getCurrentMember(); Award award = getAwardByIdOrThrow(awardId); award.validateAccessPermission(currentMember); - awardRepository.delete(award); + award.delete(); + awardRepository.save(award); return award.getId(); } diff --git a/src/main/java/page/clab/api/domain/award/domain/Award.java b/src/main/java/page/clab/api/domain/award/domain/Award.java index e54d92e3c..f05805376 100644 --- a/src/main/java/page/clab/api/domain/award/domain/Award.java +++ b/src/main/java/page/clab/api/domain/award/domain/Award.java @@ -65,12 +65,12 @@ public void delete() { this.isDeleted = true; } - public boolean isOwner(String memberId) { - return this.memberId.equals(memberId); + public boolean isOwner(Member member) { + return member.isSameMember(memberId); } public void validateAccessPermission(Member member) throws PermissionDeniedException { - if (!isOwner(member.getId()) && !member.isAdminRole()) { + if (!isOwner(member) && !member.isAdminRole()) { throw new PermissionDeniedException("해당 게시글을 수정/삭제할 권한이 없습니다."); } } From 86a911cb1aa535ebdf22cf9126dbe7ef848144af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 00:51:34 +0900 Subject: [PATCH 26/47] =?UTF-8?q?refactor(Blog):=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B6=8C=ED=95=9C=20=EA=B2=80=EC=82=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../page/clab/api/domain/blog/application/BlogService.java | 3 ++- src/main/java/page/clab/api/domain/blog/domain/Blog.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/page/clab/api/domain/blog/application/BlogService.java b/src/main/java/page/clab/api/domain/blog/application/BlogService.java index 5f98d352a..f5a1090ab 100644 --- a/src/main/java/page/clab/api/domain/blog/application/BlogService.java +++ b/src/main/java/page/clab/api/domain/blog/application/BlogService.java @@ -72,7 +72,8 @@ public Long deleteBlog(Long blogId) throws PermissionDeniedException { Member currentMember = memberLookupService.getCurrentMember(); Blog blog = getBlogByIdOrThrow(blogId); blog.validateAccessPermission(currentMember); - blogRepository.delete(blog); + blog.delete(); + blogRepository.save(blog); return blog.getId(); } diff --git a/src/main/java/page/clab/api/domain/blog/domain/Blog.java b/src/main/java/page/clab/api/domain/blog/domain/Blog.java index 6b3ab132d..470c8cfc1 100644 --- a/src/main/java/page/clab/api/domain/blog/domain/Blog.java +++ b/src/main/java/page/clab/api/domain/blog/domain/Blog.java @@ -66,7 +66,7 @@ public void delete() { } public boolean isOwner(Member member) { - return this.memberId.equals(member.getId()); + return member.isSameMember(memberId); } public void validateAccessPermission(Member member) throws PermissionDeniedException { From 20359e21adcf4e51bb82fc0f82bfde220f659a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 01:00:18 +0900 Subject: [PATCH 27/47] =?UTF-8?q?refactor(Blog):=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EA=B0=80=20=EC=A7=81=EC=A0=91?= =?UTF-8?q?=EC=A0=81=EC=9C=BC=EB=A1=9C=20Member=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=B0=B8=EC=A1=B0?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../page/clab/api/domain/blog/application/BlogService.java | 6 +++--- .../domain/blog/dto/response/BlogDetailsResponseDto.java | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/page/clab/api/domain/blog/application/BlogService.java b/src/main/java/page/clab/api/domain/blog/application/BlogService.java index f5a1090ab..8954fb2ea 100644 --- a/src/main/java/page/clab/api/domain/blog/application/BlogService.java +++ b/src/main/java/page/clab/api/domain/blog/application/BlogService.java @@ -47,15 +47,14 @@ public BlogDetailsResponseDto getBlogDetails(Long blogId) { Member currentMember = memberLookupService.getCurrentMember(); Blog blog = getBlogByIdOrThrow(blogId); boolean isOwner = blog.isOwner(currentMember); - return BlogDetailsResponseDto.toDto(blog, currentMember, isOwner); + return BlogDetailsResponseDto.toDto(blog, currentMember.getId(), currentMember.getName(), isOwner); } @Transactional(readOnly = true) public PagedResponseDto<BlogDetailsResponseDto> getDeletedBlogs(Pageable pageable) { Member currentMember = memberLookupService.getCurrentMember(); Page<Blog> blogs = blogRepository.findAllByIsDeletedTrue(pageable); - return new PagedResponseDto<>(blogs - .map(blog -> BlogDetailsResponseDto.toDto(blog, currentMember, blog.isOwner(currentMember)))); + return new PagedResponseDto<>(blogs.map(blog -> BlogDetailsResponseDto.toDto(blog, currentMember.getId(), currentMember.getName(), blog.isOwner(currentMember)))); } @Transactional @@ -68,6 +67,7 @@ public Long updateBlog(Long blogId, BlogUpdateRequestDto requestDto) throws Perm return blogRepository.save(blog).getId(); } + @Transactional public Long deleteBlog(Long blogId) throws PermissionDeniedException { Member currentMember = memberLookupService.getCurrentMember(); Blog blog = getBlogByIdOrThrow(blogId); diff --git a/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java b/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java index c96d9808a..14a9b179e 100644 --- a/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java +++ b/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java @@ -4,7 +4,6 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.blog.domain.Blog; -import page.clab.api.domain.member.domain.Member; import java.time.LocalDateTime; @@ -33,11 +32,11 @@ public class BlogDetailsResponseDto { private LocalDateTime createdAt; - public static BlogDetailsResponseDto toDto(Blog blog, Member member, boolean isOwner) { + public static BlogDetailsResponseDto toDto(Blog blog, String memberId, String memberName, boolean isOwner) { return BlogDetailsResponseDto.builder() .id(blog.getId()) - .memberId(member.getId()) - .name(member.getName()) + .memberId(memberId) + .name(memberName) .title(blog.getTitle()) .subTitle(blog.getSubTitle()) .content(blog.getContent()) From 89002253131cb0491e5e38b12409294dae3ea486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 01:09:04 +0900 Subject: [PATCH 28/47] =?UTF-8?q?refactor(Accuse):=20=EC=8B=A0=EA=B3=A0=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=EC=9D=84=20=EB=B3=B4=EB=82=BC=20=EB=95=8C=20?= =?UTF-8?q?memberId=EB=A5=BC=20=EC=9D=B4=EC=9A=A9=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/accuse/application/AccuseService.java | 16 ++++++++-------- .../application/NotificationService.java | 5 +++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java index 8393637f9..e3f0dbccb 100644 --- a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -60,8 +61,7 @@ public class AccuseService { public Long createAccuse(AccuseRequestDto requestDto) { TargetType type = requestDto.getTargetType(); Long targetId = requestDto.getTargetId(); - Member currentMember = memberLookupService.getCurrentMember(); - String memberId = currentMember.getId(); + String memberId = memberLookupService.getCurrentMemberId(); validateAccuseRequest(type, targetId, memberId); @@ -72,8 +72,8 @@ public Long createAccuse(AccuseRequestDto requestDto) { Accuse accuse = findOrCreateAccuse(requestDto, memberId, target); validationService.checkValid(accuse); - notificationService.sendNotificationToMember(currentMember, "신고하신 내용이 접수되었습니다."); - notificationService.sendNotificationToSuperAdmins(currentMember.getName() + "님이 신고를 접수하였습니다. 확인해주세요."); + notificationService.sendNotificationToMember(memberId, "신고하신 내용이 접수되었습니다."); + notificationService.sendNotificationToSuperAdmins(memberId + "님이 신고를 접수하였습니다. 확인해주세요."); return accuseRepository.save(accuse).getId(); } @@ -166,10 +166,10 @@ private List<AccuseResponseDto> convertTargetsToResponseDtos(Page<AccuseTarget> } private void sendStatusUpdateNotifications(AccuseStatus status, AccuseTarget target) { - List<Member> members = accuseRepository.findByTarget(target.getTargetType(), target.getTargetReferenceId()).stream() - .map(accuse -> memberLookupService.getMemberById(accuse.getMemberId())) - .toList(); - notificationService.sendNotificationToMembers(members, "신고 상태가 " + status.getDescription() + "(으)로 변경되었습니다."); + List<String> memberIds = accuseRepository.findByTarget(target.getTargetType(), target.getTargetReferenceId()).stream() + .map(Accuse::getMemberId) + .collect(Collectors.toList()); + notificationService.sendNotificationToMembers(memberIds, "신고 상태가 " + status.getDescription() + "(으)로 변경되었습니다."); } } diff --git a/src/main/java/page/clab/api/domain/notification/application/NotificationService.java b/src/main/java/page/clab/api/domain/notification/application/NotificationService.java index 49b4e3fa8..ffbed68f6 100644 --- a/src/main/java/page/clab/api/domain/notification/application/NotificationService.java +++ b/src/main/java/page/clab/api/domain/notification/application/NotificationService.java @@ -70,8 +70,9 @@ public void sendNotificationToMember(Member member, String content) { notificationRepository.save(notification); } - public void sendNotificationToMembers(List<Member> members, String content) { - List<Notification> notifications = members.stream() + public void sendNotificationToMembers(List<String> memberIds, String content) { + List<Notification> notifications = memberIds.stream() + .map(memberLookupService::getMemberByIdOrThrow) .map(member -> Notification.create(member, content)) .toList(); notificationRepository.saveAll(notifications); From 226962c01180858a18bef5f7e8ebb7953b422aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 01:26:02 +0900 Subject: [PATCH 29/47] =?UTF-8?q?refactor(Accuse):=20Member=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accuse/application/AccuseService.java | 8 +++--- .../accuse/dto/response/AccuseMemberInfo.java | 27 ------------------- .../dto/response/AccuseResponseDto.java | 7 ++--- .../application/MemberLookupService.java | 3 +++ .../application/MemberLookupServiceImpl.java | 8 ++++++ .../member/dto/shared/MemberInfoDto.java | 22 +++++++++++++++ 6 files changed, 40 insertions(+), 35 deletions(-) delete mode 100644 src/main/java/page/clab/api/domain/accuse/dto/response/AccuseMemberInfo.java create mode 100644 src/main/java/page/clab/api/domain/member/dto/shared/MemberInfoDto.java diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java index e3f0dbccb..756333186 100644 --- a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java @@ -15,7 +15,7 @@ import page.clab.api.domain.accuse.domain.AccuseTargetId; import page.clab.api.domain.accuse.domain.TargetType; import page.clab.api.domain.accuse.dto.request.AccuseRequestDto; -import page.clab.api.domain.accuse.dto.response.AccuseMemberInfo; +import page.clab.api.domain.member.dto.shared.MemberInfoDto; import page.clab.api.domain.accuse.dto.response.AccuseMyResponseDto; import page.clab.api.domain.accuse.dto.response.AccuseResponseDto; import page.clab.api.domain.accuse.exception.AccuseTargetTypeIncorrectException; @@ -24,7 +24,6 @@ import page.clab.api.domain.comment.application.CommentService; import page.clab.api.domain.comment.domain.Comment; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.domain.review.application.ReviewService; import page.clab.api.domain.review.domain.Review; @@ -155,9 +154,8 @@ private List<AccuseResponseDto> convertTargetsToResponseDtos(Page<AccuseTarget> if (accuses.isEmpty()) { return null; } - List<AccuseMemberInfo> members = accuses.stream() - .map(accuse -> memberLookupService.getMemberById(accuse.getMemberId())) - .map(AccuseMemberInfo::create) + List<MemberInfoDto> members = accuses.stream() + .map(accuse -> memberLookupService.getMemberInfoById(accuse.getMemberId())) .toList(); return AccuseResponseDto.toDto(accuses.getFirst(), members); }) diff --git a/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseMemberInfo.java b/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseMemberInfo.java deleted file mode 100644 index a7b019664..000000000 --- a/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseMemberInfo.java +++ /dev/null @@ -1,27 +0,0 @@ -package page.clab.api.domain.accuse.dto.response; - -import lombok.Builder; -import lombok.Getter; -import page.clab.api.domain.member.domain.Member; - -import java.time.LocalDateTime; - -@Getter -@Builder -public class AccuseMemberInfo { - - private String memberId; - - private String name; - - private LocalDateTime createdAt; - - public static AccuseMemberInfo create(Member member) { - return AccuseMemberInfo.builder() - .memberId(member.getId()) - .name(member.getName()) - .createdAt(member.getCreatedAt()) - .build(); - } - -} diff --git a/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseResponseDto.java b/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseResponseDto.java index b546afd8c..dc42cea2c 100644 --- a/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseResponseDto.java +++ b/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseResponseDto.java @@ -5,6 +5,7 @@ import page.clab.api.domain.accuse.domain.Accuse; import page.clab.api.domain.accuse.domain.AccuseStatus; import page.clab.api.domain.accuse.domain.TargetType; +import page.clab.api.domain.member.dto.shared.MemberInfoDto; import java.time.LocalDateTime; import java.util.List; @@ -13,7 +14,7 @@ @Builder public class AccuseResponseDto { - private List<AccuseMemberInfo> members; + private List<MemberInfoDto> members; private TargetType targetType; @@ -27,7 +28,7 @@ public class AccuseResponseDto { private LocalDateTime createdAt; - public static AccuseResponseDto toDto(Accuse accuse, List<AccuseMemberInfo> members) { + public static AccuseResponseDto toDto(Accuse accuse, List<MemberInfoDto> members) { return AccuseResponseDto.builder() .members(members) .targetType(accuse.getTarget().getTargetType()) @@ -35,7 +36,7 @@ public static AccuseResponseDto toDto(Accuse accuse, List<AccuseMemberInfo> memb .reason(accuse.getReason()) .accuseStatus(accuse.getTarget().getAccuseStatus()) .accuseCount(accuse.getTarget().getAccuseCount()) - .createdAt(accuse.getTarget().getCreatedAt()) + .createdAt(accuse.getCreatedAt()) .build(); } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java index ae6e581ed..963e28c98 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -1,6 +1,7 @@ package page.clab.api.domain.member.application; import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberInfoDto; import page.clab.api.domain.member.dto.response.MemberResponseDto; import java.util.List; @@ -27,4 +28,6 @@ public interface MemberLookupService { List<Member> getSuperAdmins(); + MemberInfoDto getMemberInfoById(String memberId); + } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java index 1fd2b004a..743e00f96 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Service; import page.clab.api.domain.member.dao.MemberRepository; import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberInfoDto; import page.clab.api.domain.member.dto.response.MemberResponseDto; import page.clab.api.global.auth.util.AuthUtil; import page.clab.api.global.exception.NotFoundException; @@ -80,4 +81,11 @@ public List<Member> getSuperAdmins() { .toList(); } + @Override + public MemberInfoDto getMemberInfoById(String memberId) { + return memberRepository.findById(memberId) + .map(MemberInfoDto::create) + .orElseThrow(() -> new NotFoundException("[Member] id: " + memberId + "에 해당하는 멤버가 존재하지 않습니다.")); + } + } diff --git a/src/main/java/page/clab/api/domain/member/dto/shared/MemberInfoDto.java b/src/main/java/page/clab/api/domain/member/dto/shared/MemberInfoDto.java new file mode 100644 index 000000000..99263561e --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/dto/shared/MemberInfoDto.java @@ -0,0 +1,22 @@ +package page.clab.api.domain.member.dto.shared; + +import lombok.Builder; +import lombok.Getter; +import page.clab.api.domain.member.domain.Member; + +@Getter +@Builder +public class MemberInfoDto { + + private String memberId; + + private String memberName; + + public static MemberInfoDto create(Member member) { + return MemberInfoDto.builder() + .memberId(member.getId()) + .memberName(member.getName()) + .build(); + } + +} From 4ba27f3e01ad9e60c8dceda54be3eed0a8743bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 01:32:43 +0900 Subject: [PATCH 30/47] =?UTF-8?q?refactor(Blog):=20Member=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../clab/api/domain/blog/application/BlogService.java | 11 ++++++----- .../java/page/clab/api/domain/blog/domain/Blog.java | 6 +++--- .../blog/dto/response/BlogDetailsResponseDto.java | 7 ++++--- .../member/application/MemberLookupService.java | 4 +++- .../member/application/MemberLookupServiceImpl.java | 10 +++++++++- 5 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main/java/page/clab/api/domain/blog/application/BlogService.java b/src/main/java/page/clab/api/domain/blog/application/BlogService.java index 8954fb2ea..2f7ee1fcc 100644 --- a/src/main/java/page/clab/api/domain/blog/application/BlogService.java +++ b/src/main/java/page/clab/api/domain/blog/application/BlogService.java @@ -13,6 +13,7 @@ import page.clab.api.domain.blog.dto.response.BlogResponseDto; import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberInfoDto; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; import page.clab.api.global.exception.PermissionDeniedException; @@ -44,17 +45,17 @@ public PagedResponseDto<BlogResponseDto> getBlogsByConditions(String title, Stri @Transactional(readOnly = true) public BlogDetailsResponseDto getBlogDetails(Long blogId) { - Member currentMember = memberLookupService.getCurrentMember(); + MemberInfoDto currentMemberInfo = memberLookupService.getCurrentMemberInfo(); Blog blog = getBlogByIdOrThrow(blogId); - boolean isOwner = blog.isOwner(currentMember); - return BlogDetailsResponseDto.toDto(blog, currentMember.getId(), currentMember.getName(), isOwner); + boolean isOwner = blog.isOwner(currentMemberInfo.getMemberId()); + return BlogDetailsResponseDto.toDto(blog, currentMemberInfo, isOwner); } @Transactional(readOnly = true) public PagedResponseDto<BlogDetailsResponseDto> getDeletedBlogs(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); + MemberInfoDto currentMemberInfo = memberLookupService.getCurrentMemberInfo(); Page<Blog> blogs = blogRepository.findAllByIsDeletedTrue(pageable); - return new PagedResponseDto<>(blogs.map(blog -> BlogDetailsResponseDto.toDto(blog, currentMember.getId(), currentMember.getName(), blog.isOwner(currentMember)))); + return new PagedResponseDto<>(blogs.map(blog -> BlogDetailsResponseDto.toDto(blog, currentMemberInfo, blog.isOwner(currentMemberInfo.getMemberId())))); } @Transactional diff --git a/src/main/java/page/clab/api/domain/blog/domain/Blog.java b/src/main/java/page/clab/api/domain/blog/domain/Blog.java index 470c8cfc1..1384b5982 100644 --- a/src/main/java/page/clab/api/domain/blog/domain/Blog.java +++ b/src/main/java/page/clab/api/domain/blog/domain/Blog.java @@ -65,12 +65,12 @@ public void delete() { this.isDeleted = true; } - public boolean isOwner(Member member) { - return member.isSameMember(memberId); + public boolean isOwner(String memberId) { + return this.memberId.equals(memberId); } public void validateAccessPermission(Member member) throws PermissionDeniedException { - if (!isOwner(member) && !member.isAdminRole()) { + if (!isOwner(member.getId()) && !member.isAdminRole()) { throw new PermissionDeniedException("해당 게시글을 수정/삭제할 권한이 없습니다."); } } diff --git a/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java b/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java index 14a9b179e..c611e5e74 100644 --- a/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java +++ b/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java @@ -4,6 +4,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.blog.domain.Blog; +import page.clab.api.domain.member.dto.shared.MemberInfoDto; import java.time.LocalDateTime; @@ -32,11 +33,11 @@ public class BlogDetailsResponseDto { private LocalDateTime createdAt; - public static BlogDetailsResponseDto toDto(Blog blog, String memberId, String memberName, boolean isOwner) { + public static BlogDetailsResponseDto toDto(Blog blog, MemberInfoDto memberInfo, boolean isOwner) { return BlogDetailsResponseDto.builder() .id(blog.getId()) - .memberId(memberId) - .name(memberName) + .memberId(memberInfo.getMemberId()) + .name(memberInfo.getMemberName()) .title(blog.getTitle()) .subTitle(blog.getSubTitle()) .content(blog.getContent()) diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java index 963e28c98..87b185c59 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -1,8 +1,8 @@ package page.clab.api.domain.member.application; import page.clab.api.domain.member.domain.Member; -import page.clab.api.domain.member.dto.shared.MemberInfoDto; import page.clab.api.domain.member.dto.response.MemberResponseDto; +import page.clab.api.domain.member.dto.shared.MemberInfoDto; import java.util.List; @@ -30,4 +30,6 @@ public interface MemberLookupService { MemberInfoDto getMemberInfoById(String memberId); + MemberInfoDto getCurrentMemberInfo(); + } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java index 743e00f96..31d7ac533 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -4,8 +4,8 @@ import org.springframework.stereotype.Service; import page.clab.api.domain.member.dao.MemberRepository; import page.clab.api.domain.member.domain.Member; -import page.clab.api.domain.member.dto.shared.MemberInfoDto; import page.clab.api.domain.member.dto.response.MemberResponseDto; +import page.clab.api.domain.member.dto.shared.MemberInfoDto; import page.clab.api.global.auth.util.AuthUtil; import page.clab.api.global.exception.NotFoundException; @@ -88,4 +88,12 @@ public MemberInfoDto getMemberInfoById(String memberId) { .orElseThrow(() -> new NotFoundException("[Member] id: " + memberId + "에 해당하는 멤버가 존재하지 않습니다.")); } + @Override + public MemberInfoDto getCurrentMemberInfo() { + String currentMemberId = getCurrentMemberId(); + return memberRepository.findById(currentMemberId) + .map(MemberInfoDto::create) + .orElseThrow(() -> new NotFoundException("[Member] id: " + currentMemberId + "에 해당하는 멤버가 존재하지 않습니다.")); + } + } From fa0ffc451dd2398a8fd99fccfd8bd5844ecf00ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 01:48:56 +0900 Subject: [PATCH 31/47] =?UTF-8?q?refactor(Member):=20MemberInfoDto=20->=20?= =?UTF-8?q?MemberBasicInfoDto=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/domain/accuse/application/AccuseService.java | 6 +++--- .../domain/accuse/dto/response/AccuseResponseDto.java | 6 +++--- .../clab/api/domain/blog/application/BlogService.java | 6 +++--- .../blog/dto/response/BlogDetailsResponseDto.java | 4 ++-- .../domain/member/application/MemberLookupService.java | 6 +++--- .../member/application/MemberLookupServiceImpl.java | 10 +++++----- .../{MemberInfoDto.java => MemberBasicInfoDto.java} | 6 +++--- 7 files changed, 22 insertions(+), 22 deletions(-) rename src/main/java/page/clab/api/domain/member/dto/shared/{MemberInfoDto.java => MemberBasicInfoDto.java} (71%) diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java index 756333186..fd266c624 100644 --- a/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseService.java @@ -15,7 +15,7 @@ import page.clab.api.domain.accuse.domain.AccuseTargetId; import page.clab.api.domain.accuse.domain.TargetType; import page.clab.api.domain.accuse.dto.request.AccuseRequestDto; -import page.clab.api.domain.member.dto.shared.MemberInfoDto; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.domain.accuse.dto.response.AccuseMyResponseDto; import page.clab.api.domain.accuse.dto.response.AccuseResponseDto; import page.clab.api.domain.accuse.exception.AccuseTargetTypeIncorrectException; @@ -154,8 +154,8 @@ private List<AccuseResponseDto> convertTargetsToResponseDtos(Page<AccuseTarget> if (accuses.isEmpty()) { return null; } - List<MemberInfoDto> members = accuses.stream() - .map(accuse -> memberLookupService.getMemberInfoById(accuse.getMemberId())) + List<MemberBasicInfoDto> members = accuses.stream() + .map(accuse -> memberLookupService.getMemberBasicInfoById(accuse.getMemberId())) .toList(); return AccuseResponseDto.toDto(accuses.getFirst(), members); }) diff --git a/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseResponseDto.java b/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseResponseDto.java index dc42cea2c..ae2433284 100644 --- a/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseResponseDto.java +++ b/src/main/java/page/clab/api/domain/accuse/dto/response/AccuseResponseDto.java @@ -5,7 +5,7 @@ import page.clab.api.domain.accuse.domain.Accuse; import page.clab.api.domain.accuse.domain.AccuseStatus; import page.clab.api.domain.accuse.domain.TargetType; -import page.clab.api.domain.member.dto.shared.MemberInfoDto; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import java.time.LocalDateTime; import java.util.List; @@ -14,7 +14,7 @@ @Builder public class AccuseResponseDto { - private List<MemberInfoDto> members; + private List<MemberBasicInfoDto> members; private TargetType targetType; @@ -28,7 +28,7 @@ public class AccuseResponseDto { private LocalDateTime createdAt; - public static AccuseResponseDto toDto(Accuse accuse, List<MemberInfoDto> members) { + public static AccuseResponseDto toDto(Accuse accuse, List<MemberBasicInfoDto> members) { return AccuseResponseDto.builder() .members(members) .targetType(accuse.getTarget().getTargetType()) diff --git a/src/main/java/page/clab/api/domain/blog/application/BlogService.java b/src/main/java/page/clab/api/domain/blog/application/BlogService.java index 2f7ee1fcc..e9ff4bcaa 100644 --- a/src/main/java/page/clab/api/domain/blog/application/BlogService.java +++ b/src/main/java/page/clab/api/domain/blog/application/BlogService.java @@ -13,7 +13,7 @@ import page.clab.api.domain.blog.dto.response.BlogResponseDto; import page.clab.api.domain.member.application.MemberLookupService; import page.clab.api.domain.member.domain.Member; -import page.clab.api.domain.member.dto.shared.MemberInfoDto; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; import page.clab.api.global.exception.PermissionDeniedException; @@ -45,7 +45,7 @@ public PagedResponseDto<BlogResponseDto> getBlogsByConditions(String title, Stri @Transactional(readOnly = true) public BlogDetailsResponseDto getBlogDetails(Long blogId) { - MemberInfoDto currentMemberInfo = memberLookupService.getCurrentMemberInfo(); + MemberBasicInfoDto currentMemberInfo = memberLookupService.getCurrentMemberBasicInfo(); Blog blog = getBlogByIdOrThrow(blogId); boolean isOwner = blog.isOwner(currentMemberInfo.getMemberId()); return BlogDetailsResponseDto.toDto(blog, currentMemberInfo, isOwner); @@ -53,7 +53,7 @@ public BlogDetailsResponseDto getBlogDetails(Long blogId) { @Transactional(readOnly = true) public PagedResponseDto<BlogDetailsResponseDto> getDeletedBlogs(Pageable pageable) { - MemberInfoDto currentMemberInfo = memberLookupService.getCurrentMemberInfo(); + MemberBasicInfoDto currentMemberInfo = memberLookupService.getCurrentMemberBasicInfo(); Page<Blog> blogs = blogRepository.findAllByIsDeletedTrue(pageable); return new PagedResponseDto<>(blogs.map(blog -> BlogDetailsResponseDto.toDto(blog, currentMemberInfo, blog.isOwner(currentMemberInfo.getMemberId())))); } diff --git a/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java b/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java index c611e5e74..959e9794c 100644 --- a/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java +++ b/src/main/java/page/clab/api/domain/blog/dto/response/BlogDetailsResponseDto.java @@ -4,7 +4,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.blog.domain.Blog; -import page.clab.api.domain.member.dto.shared.MemberInfoDto; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import java.time.LocalDateTime; @@ -33,7 +33,7 @@ public class BlogDetailsResponseDto { private LocalDateTime createdAt; - public static BlogDetailsResponseDto toDto(Blog blog, MemberInfoDto memberInfo, boolean isOwner) { + public static BlogDetailsResponseDto toDto(Blog blog, MemberBasicInfoDto memberInfo, boolean isOwner) { return BlogDetailsResponseDto.builder() .id(blog.getId()) .memberId(memberInfo.getMemberId()) diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java index 87b185c59..7dbf5c6f4 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -2,7 +2,7 @@ import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.response.MemberResponseDto; -import page.clab.api.domain.member.dto.shared.MemberInfoDto; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import java.util.List; @@ -28,8 +28,8 @@ public interface MemberLookupService { List<Member> getSuperAdmins(); - MemberInfoDto getMemberInfoById(String memberId); + MemberBasicInfoDto getMemberBasicInfoById(String memberId); - MemberInfoDto getCurrentMemberInfo(); + MemberBasicInfoDto getCurrentMemberBasicInfo(); } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java index 31d7ac533..cb4c430d9 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -5,7 +5,7 @@ import page.clab.api.domain.member.dao.MemberRepository; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.response.MemberResponseDto; -import page.clab.api.domain.member.dto.shared.MemberInfoDto; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.global.auth.util.AuthUtil; import page.clab.api.global.exception.NotFoundException; @@ -82,17 +82,17 @@ public List<Member> getSuperAdmins() { } @Override - public MemberInfoDto getMemberInfoById(String memberId) { + public MemberBasicInfoDto getMemberBasicInfoById(String memberId) { return memberRepository.findById(memberId) - .map(MemberInfoDto::create) + .map(MemberBasicInfoDto::create) .orElseThrow(() -> new NotFoundException("[Member] id: " + memberId + "에 해당하는 멤버가 존재하지 않습니다.")); } @Override - public MemberInfoDto getCurrentMemberInfo() { + public MemberBasicInfoDto getCurrentMemberBasicInfo() { String currentMemberId = getCurrentMemberId(); return memberRepository.findById(currentMemberId) - .map(MemberInfoDto::create) + .map(MemberBasicInfoDto::create) .orElseThrow(() -> new NotFoundException("[Member] id: " + currentMemberId + "에 해당하는 멤버가 존재하지 않습니다.")); } diff --git a/src/main/java/page/clab/api/domain/member/dto/shared/MemberInfoDto.java b/src/main/java/page/clab/api/domain/member/dto/shared/MemberBasicInfoDto.java similarity index 71% rename from src/main/java/page/clab/api/domain/member/dto/shared/MemberInfoDto.java rename to src/main/java/page/clab/api/domain/member/dto/shared/MemberBasicInfoDto.java index 99263561e..b7c27aec8 100644 --- a/src/main/java/page/clab/api/domain/member/dto/shared/MemberInfoDto.java +++ b/src/main/java/page/clab/api/domain/member/dto/shared/MemberBasicInfoDto.java @@ -6,14 +6,14 @@ @Getter @Builder -public class MemberInfoDto { +public class MemberBasicInfoDto { private String memberId; private String memberName; - public static MemberInfoDto create(Member member) { - return MemberInfoDto.builder() + public static MemberBasicInfoDto create(Member member) { + return MemberBasicInfoDto.builder() .memberId(member.getId()) .memberName(member.getName()) .build(); From ff63cd99096288b792f4332c4f717aa25bed25d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 01:51:49 +0900 Subject: [PATCH 32/47] =?UTF-8?q?feat(Member):=20MemberDetailedInfoDto=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/MemberLookupService.java | 3 ++ .../application/MemberLookupServiceImpl.java | 9 ++++++ .../dto/shared/MemberDetailedInfoDto.java | 28 +++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java index 7dbf5c6f4..d67c6e769 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -3,6 +3,7 @@ import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.response.MemberResponseDto; import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import java.util.List; @@ -32,4 +33,6 @@ public interface MemberLookupService { MemberBasicInfoDto getCurrentMemberBasicInfo(); + MemberDetailedInfoDto getCurrentMemberDetailedInfo(); + } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java index cb4c430d9..42985f56e 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -6,6 +6,7 @@ import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.response.MemberResponseDto; import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.global.auth.util.AuthUtil; import page.clab.api.global.exception.NotFoundException; @@ -96,4 +97,12 @@ public MemberBasicInfoDto getCurrentMemberBasicInfo() { .orElseThrow(() -> new NotFoundException("[Member] id: " + currentMemberId + "에 해당하는 멤버가 존재하지 않습니다.")); } + @Override + public MemberDetailedInfoDto getCurrentMemberDetailedInfo() { + String currentMemberId = getCurrentMemberId(); + return memberRepository.findById(currentMemberId) + .map(MemberDetailedInfoDto::create) + .orElseThrow(() -> new NotFoundException("[Member] id: " + currentMemberId + "에 해당하는 멤버가 존재하지 않습니다.")); + } + } diff --git a/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java b/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java new file mode 100644 index 000000000..a5116aac6 --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java @@ -0,0 +1,28 @@ +package page.clab.api.domain.member.dto.shared; + +import lombok.Builder; +import lombok.Getter; +import page.clab.api.domain.member.domain.Member; + +@Getter +@Builder +public class MemberDetailedInfoDto { + + private String memberId; + + private String memberName; + + private Long roleLevel; + + private String imageUrl; + + public static MemberDetailedInfoDto create(Member member) { + return MemberDetailedInfoDto.builder() + .memberId(member.getId()) + .memberName(member.getName()) + .roleLevel(member.getRole().toRoleLevel()) + .imageUrl(member.getImageUrl()) + .build(); + } + +} From 369e1c3a71e9130493c218220ffa420a5e54e526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 02:12:49 +0900 Subject: [PATCH 33/47] =?UTF-8?q?refactor(Board):=20Member=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../board/application/BoardService.java | 67 ++++++++++--------- .../clab/api/domain/board/domain/Board.java | 16 ++--- .../domain/board/domain/SlackBoardInfo.java | 6 +- .../response/BoardCategoryResponseDto.java | 6 +- .../dto/response/BoardDetailsResponseDto.java | 6 +- .../dto/response/BoardListResponseDto.java | 6 +- .../dto/response/BoardMyResponseDto.java | 6 +- .../domain/board/dto/response/WriterInfo.java | 17 +++-- .../dto/shared/MemberDetailedInfoDto.java | 7 ++ 9 files changed, 72 insertions(+), 65 deletions(-) diff --git a/src/main/java/page/clab/api/domain/board/application/BoardService.java b/src/main/java/page/clab/api/domain/board/application/BoardService.java index fe68c8937..584a14815 100644 --- a/src/main/java/page/clab/api/domain/board/application/BoardService.java +++ b/src/main/java/page/clab/api/domain/board/application/BoardService.java @@ -20,7 +20,8 @@ import page.clab.api.domain.board.dto.response.BoardMyResponseDto; import page.clab.api.domain.comment.dao.CommentRepository; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.common.file.application.UploadedFileService; @@ -55,54 +56,54 @@ public class BoardService { @Transactional public String createBoard(BoardRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); List<UploadedFile> uploadedFiles = uploadedFileService.getUploadedFilesByUrls(requestDto.getFileUrlList()); - Board board = BoardRequestDto.toEntity(requestDto, currentMember.getId(), uploadedFiles); - board.validateAccessPermissionForCreation(currentMember); + Board board = BoardRequestDto.toEntity(requestDto, currentMemberInfo.getMemberId(), uploadedFiles); + board.validateAccessPermissionForCreation(currentMemberInfo); validationService.checkValid(board); - if (board.shouldNotifyForNewBoard(currentMember)) { - notificationService.sendNotificationToMember(currentMember, "[" + board.getTitle() + "] 새로운 공지사항이 등록되었습니다."); + if (board.shouldNotifyForNewBoard(currentMemberInfo)) { + notificationService.sendNotificationToMember(currentMemberInfo.getMemberId(), "[" + board.getTitle() + "] 새로운 공지사항이 등록되었습니다."); } - SlackBoardInfo boardInfo = SlackBoardInfo.create(board, currentMember); + SlackBoardInfo boardInfo = SlackBoardInfo.create(board, currentMemberInfo); slackService.sendNewBoardNotification(boardInfo); return boardRepository.save(board).getCategory().getKey(); } @Transactional(readOnly = true) public PagedResponseDto<BoardListResponseDto> getBoards(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Page<Board> boards = boardRepository.findAll(pageable); - return new PagedResponseDto<>(boards.map(board -> mapToBoardListResponseDto(board, currentMember))); + return new PagedResponseDto<>(boards.map(board -> mapToBoardListResponseDto(board, currentMemberInfo))); } @Transactional(readOnly = true) public BoardDetailsResponseDto getBoardDetails(Long boardId) { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Board board = getBoardByIdOrThrow(boardId); - boolean hasLikeByMe = checkLikeStatus(board, currentMember); - boolean isOwner = board.isOwner(currentMember.getId()); - return BoardDetailsResponseDto.toDto(board, currentMember, hasLikeByMe, isOwner); + boolean hasLikeByMe = checkLikeStatus(board, currentMemberInfo); + boolean isOwner = board.isOwner(currentMemberInfo.getMemberId()); + return BoardDetailsResponseDto.toDto(board, currentMemberInfo, hasLikeByMe, isOwner); } @Transactional(readOnly = true) public PagedResponseDto<BoardMyResponseDto> getMyBoards(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); - Page<Board> boards = getBoardByMemberId(pageable, currentMember.getId()); - return new PagedResponseDto<>(boards.map(board -> BoardMyResponseDto.toDto(board, currentMember))); + MemberBasicInfoDto currentMemberInfo = memberLookupService.getCurrentMemberBasicInfo(); + Page<Board> boards = getBoardByMemberId(pageable, currentMemberInfo.getMemberId()); + return new PagedResponseDto<>(boards.map(board -> BoardMyResponseDto.toDto(board, currentMemberInfo))); } @Transactional(readOnly = true) public PagedResponseDto<BoardCategoryResponseDto> getBoardsByCategory(BoardCategory category, Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Page<Board> boards = getBoardByCategory(category, pageable); - return new PagedResponseDto<>(boards.map(board -> mapToBoardCategoryResponseDto(board, currentMember))); + return new PagedResponseDto<>(boards.map(board -> mapToBoardCategoryResponseDto(board, currentMemberInfo))); } @Transactional public String updateBoard(Long boardId, BoardUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Board board = getBoardByIdOrThrow(boardId); - board.validateAccessPermission(currentMember); + board.validateAccessPermission(currentMemberInfo); board.update(requestDto); validationService.checkValid(board); return boardRepository.save(board).getCategory().getKey(); @@ -110,15 +111,15 @@ public String updateBoard(Long boardId, BoardUpdateRequestDto requestDto) throws @Transactional public Long toggleLikeStatus(Long boardId) { - Member currentMember = memberLookupService.getCurrentMember(); + String currentMemberId = memberLookupService.getCurrentMemberId(); Board board = getBoardByIdOrThrow(boardId); - Optional<BoardLike> boardLikeOpt = boardLikeRepository.findByBoardIdAndMemberId(board.getId(), currentMember.getId()); + Optional<BoardLike> boardLikeOpt = boardLikeRepository.findByBoardIdAndMemberId(board.getId(), currentMemberId); if (boardLikeOpt.isPresent()) { board.decrementLikes(); boardLikeRepository.delete(boardLikeOpt.get()); } else { board.incrementLikes(); - BoardLike newBoardLike = BoardLike.create(currentMember.getId(), board.getId()); + BoardLike newBoardLike = BoardLike.create(currentMemberId, board.getId()); validationService.checkValid(newBoardLike); boardLikeRepository.save(newBoardLike); } @@ -127,29 +128,29 @@ public Long toggleLikeStatus(Long boardId) { @Transactional(readOnly = true) public PagedResponseDto<BoardListResponseDto> getDeletedBoards(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Page<Board> boards = boardRepository.findAllByIsDeletedTrue(pageable); - return new PagedResponseDto<>(boards.map(board -> mapToBoardListResponseDto(board, currentMember))); + return new PagedResponseDto<>(boards.map(board -> mapToBoardListResponseDto(board, currentMemberInfo))); } public String deleteBoard(Long boardId) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Board board = getBoardByIdOrThrow(boardId); - board.validateAccessPermission(currentMember); + board.validateAccessPermission(currentMemberInfo); boardRepository.delete(board); return board.getCategory().getKey(); } @NotNull - private BoardListResponseDto mapToBoardListResponseDto(Board board, Member member) { + private BoardListResponseDto mapToBoardListResponseDto(Board board, MemberDetailedInfoDto memberInfo) { Long commentCount = commentRepository.countByBoard(board); - return BoardListResponseDto.toDto(board, member, commentCount); + return BoardListResponseDto.toDto(board, memberInfo, commentCount); } @NotNull - private BoardCategoryResponseDto mapToBoardCategoryResponseDto(Board board, Member member) { + private BoardCategoryResponseDto mapToBoardCategoryResponseDto(Board board, MemberDetailedInfoDto memberInfo) { Long commentCount = commentRepository.countByBoard(board); - return BoardCategoryResponseDto.toDto(board, member, commentCount); + return BoardCategoryResponseDto.toDto(board, memberInfo, commentCount); } public Board getBoardByIdOrThrow(Long boardId) { @@ -165,8 +166,8 @@ private Page<Board> getBoardByCategory(BoardCategory category, Pageable pageable return boardRepository.findAllByCategory(category, pageable); } - private boolean checkLikeStatus(Board board, Member member) { - return boardLikeRepository.existsByBoardIdAndMemberId(board.getId(), member.getId()); + private boolean checkLikeStatus(Board board, MemberDetailedInfoDto memberInfo) { + return boardLikeRepository.existsByBoardIdAndMemberId(board.getId(), memberInfo.getMemberId()); } } \ No newline at end of file diff --git a/src/main/java/page/clab/api/domain/board/domain/Board.java b/src/main/java/page/clab/api/domain/board/domain/Board.java index 8c0be374f..663e9c45f 100644 --- a/src/main/java/page/clab/api/domain/board/domain/Board.java +++ b/src/main/java/page/clab/api/domain/board/domain/Board.java @@ -20,7 +20,7 @@ import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; import page.clab.api.domain.board.dto.request.BoardUpdateRequestDto; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.global.common.domain.BaseEntity; import page.clab.api.global.common.file.domain.UploadedFile; import page.clab.api.global.exception.PermissionDeniedException; @@ -92,8 +92,8 @@ public boolean isGraduated() { return this.category.equals(BoardCategory.GRADUATED); } - public boolean shouldNotifyForNewBoard(Member member) { - return member.isAdminRole() && this.category.equals(BoardCategory.NOTICE); + public boolean shouldNotifyForNewBoard(MemberDetailedInfoDto memberInfo) { + return memberInfo.isAdminRole() && this.category.equals(BoardCategory.NOTICE); // Assuming 2 is Admin role level } public void incrementLikes() { @@ -110,17 +110,17 @@ public boolean isOwner(String memberId) { return this.memberId.equals(memberId); } - public void validateAccessPermission(Member member) throws PermissionDeniedException { - if (!isOwner(member.getId()) && !member.isAdminRole()) { + public void validateAccessPermission(MemberDetailedInfoDto memberInfo) throws PermissionDeniedException { + if (!isOwner(memberInfo.getMemberId()) && !memberInfo.isAdminRole()) { throw new PermissionDeniedException("해당 게시글을 수정할 권한이 없습니다."); } } - public void validateAccessPermissionForCreation(Member currentMember) throws PermissionDeniedException { - if (this.isNotice() && !currentMember.isAdminRole()) { + public void validateAccessPermissionForCreation(MemberDetailedInfoDto currentMemberInfo) throws PermissionDeniedException { + if (this.isNotice() && !currentMemberInfo.isAdminRole()) { throw new PermissionDeniedException("공지사항은 관리자만 작성할 수 있습니다."); } - if (this.isGraduated() && !currentMember.isGraduated()) { + if (this.isGraduated() && !currentMemberInfo.isGraduated()) { throw new PermissionDeniedException("졸업생 게시판은 졸업생만 작성할 수 있습니다."); } } diff --git a/src/main/java/page/clab/api/domain/board/domain/SlackBoardInfo.java b/src/main/java/page/clab/api/domain/board/domain/SlackBoardInfo.java index 62c1f4ee8..055409963 100644 --- a/src/main/java/page/clab/api/domain/board/domain/SlackBoardInfo.java +++ b/src/main/java/page/clab/api/domain/board/domain/SlackBoardInfo.java @@ -2,7 +2,7 @@ import lombok.Builder; import lombok.Getter; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; @Getter @Builder @@ -14,11 +14,11 @@ public class SlackBoardInfo { private String username; - public static SlackBoardInfo create(Board board, Member member) { + public static SlackBoardInfo create(Board board, MemberDetailedInfoDto memberInfo) { return SlackBoardInfo.builder() .title(board.getTitle()) .category(board.getCategory().getDescription()) - .username(board.isWantAnonymous() ? board.getNickname() : member.getId() + " " + member.getName()) + .username(board.isWantAnonymous() ? board.getNickname() : memberInfo.getMemberId() + " " + memberInfo.getMemberName()) .build(); } diff --git a/src/main/java/page/clab/api/domain/board/dto/response/BoardCategoryResponseDto.java b/src/main/java/page/clab/api/domain/board/dto/response/BoardCategoryResponseDto.java index c8fdce527..44074b4cf 100644 --- a/src/main/java/page/clab/api/domain/board/dto/response/BoardCategoryResponseDto.java +++ b/src/main/java/page/clab/api/domain/board/dto/response/BoardCategoryResponseDto.java @@ -3,7 +3,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.board.domain.Board; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import java.time.LocalDateTime; @@ -27,8 +27,8 @@ public class BoardCategoryResponseDto { private LocalDateTime createdAt; - public static BoardCategoryResponseDto toDto(Board board, Member member, Long commentCount) { - WriterInfo writerInfo = WriterInfo.fromBoard(board, member); + public static BoardCategoryResponseDto toDto(Board board, MemberDetailedInfoDto memberInfo, Long commentCount) { + WriterInfo writerInfo = WriterInfo.fromBoard(board, memberInfo); return BoardCategoryResponseDto.builder() .id(board.getId()) .category(board.getCategory().getKey()) diff --git a/src/main/java/page/clab/api/domain/board/dto/response/BoardDetailsResponseDto.java b/src/main/java/page/clab/api/domain/board/dto/response/BoardDetailsResponseDto.java index 6155820ad..5177b12ab 100644 --- a/src/main/java/page/clab/api/domain/board/dto/response/BoardDetailsResponseDto.java +++ b/src/main/java/page/clab/api/domain/board/dto/response/BoardDetailsResponseDto.java @@ -4,7 +4,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.board.domain.Board; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.global.common.file.dto.response.UploadedFileResponseDto; import java.time.LocalDateTime; @@ -43,8 +43,8 @@ public class BoardDetailsResponseDto { private LocalDateTime createdAt; - public static BoardDetailsResponseDto toDto(Board board, Member member, boolean hasLikeByMe, boolean isOwner) { - WriterInfo writerInfo = WriterInfo.fromBoardDetails(board, member); + public static BoardDetailsResponseDto toDto(Board board, MemberDetailedInfoDto memberInfo, boolean hasLikeByMe, boolean isOwner) { + WriterInfo writerInfo = WriterInfo.fromBoardDetails(board, memberInfo); return BoardDetailsResponseDto.builder() .id(board.getId()) .writerId(writerInfo.getId()) diff --git a/src/main/java/page/clab/api/domain/board/dto/response/BoardListResponseDto.java b/src/main/java/page/clab/api/domain/board/dto/response/BoardListResponseDto.java index c509454fd..2e1577ac2 100644 --- a/src/main/java/page/clab/api/domain/board/dto/response/BoardListResponseDto.java +++ b/src/main/java/page/clab/api/domain/board/dto/response/BoardListResponseDto.java @@ -3,7 +3,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.board.domain.Board; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import java.time.LocalDateTime; @@ -29,8 +29,8 @@ public class BoardListResponseDto { private LocalDateTime createdAt; - public static BoardListResponseDto toDto(Board board, Member member, Long commentCount) { - WriterInfo writerInfo = WriterInfo.fromBoard(board, member); + public static BoardListResponseDto toDto(Board board, MemberDetailedInfoDto memberInfo, Long commentCount) { + WriterInfo writerInfo = WriterInfo.fromBoard(board, memberInfo); return BoardListResponseDto.builder() .id(board.getId()) .writerId(writerInfo.getId()) diff --git a/src/main/java/page/clab/api/domain/board/dto/response/BoardMyResponseDto.java b/src/main/java/page/clab/api/domain/board/dto/response/BoardMyResponseDto.java index f78875737..0fa9997c7 100644 --- a/src/main/java/page/clab/api/domain/board/dto/response/BoardMyResponseDto.java +++ b/src/main/java/page/clab/api/domain/board/dto/response/BoardMyResponseDto.java @@ -3,7 +3,7 @@ import lombok.Builder; import lombok.Getter; import page.clab.api.domain.board.domain.Board; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import java.time.LocalDateTime; @@ -23,11 +23,11 @@ public class BoardMyResponseDto { private LocalDateTime createdAt; - public static BoardMyResponseDto toDto(Board board, Member member) { + public static BoardMyResponseDto toDto(Board board, MemberBasicInfoDto memberInfo) { return BoardMyResponseDto.builder() .id(board.getId()) .category(board.getCategory().getKey()) - .writerName(board.isWantAnonymous() ? board.getNickname() : member.getName()) + .writerName(board.isWantAnonymous() ? board.getNickname() : memberInfo.getMemberName()) .title(board.getTitle()) .imageUrl(board.getImageUrl()) .createdAt(board.getCreatedAt()) diff --git a/src/main/java/page/clab/api/domain/board/dto/response/WriterInfo.java b/src/main/java/page/clab/api/domain/board/dto/response/WriterInfo.java index b8536da75..52b4ef268 100644 --- a/src/main/java/page/clab/api/domain/board/dto/response/WriterInfo.java +++ b/src/main/java/page/clab/api/domain/board/dto/response/WriterInfo.java @@ -2,8 +2,7 @@ import lombok.Getter; import page.clab.api.domain.board.domain.Board; -import page.clab.api.domain.member.domain.Member; -import page.clab.api.domain.member.domain.Role; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; @Getter public class WriterInfo { @@ -28,22 +27,22 @@ public WriterInfo(String id, String name, Long roleLevel, String imageUrl) { this.imageUrl = imageUrl; } - public static WriterInfo fromBoard(Board board, Member member) { - if (member.isAdminRole() && board.isNotice()) { + public static WriterInfo fromBoard(Board board, MemberDetailedInfoDto memberInfo) { + if (memberInfo.isAdminRole() && board.isNotice()) { return new WriterInfo(null, "운영진"); } else if (board.isWantAnonymous()) { return new WriterInfo(null, board.getNickname()); } - return new WriterInfo(member.getId(), member.getName()); + return new WriterInfo(memberInfo.getMemberId(), memberInfo.getMemberName()); } - public static WriterInfo fromBoardDetails(Board board, Member member) { - if (member.isAdminRole() && board.isNotice()) { - return new WriterInfo(null, "운영진", Role.ADMIN.toRoleLevel(), null); + public static WriterInfo fromBoardDetails(Board board, MemberDetailedInfoDto memberInfo) { + if (memberInfo.isAdminRole() && board.isNotice()) { + return new WriterInfo(null, "운영진", memberInfo.getRoleLevel(), null); } else if (board.isWantAnonymous()) { return new WriterInfo(null, board.getNickname(), null, null); } - return new WriterInfo(member.getId(), member.getName(), member.getRole().toRoleLevel(), member.getImageUrl()); + return new WriterInfo(memberInfo.getMemberId(), memberInfo.getMemberName(), memberInfo.getRoleLevel(), memberInfo.getImageUrl()); } } diff --git a/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java b/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java index a5116aac6..be5b1c3c7 100644 --- a/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java +++ b/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java @@ -16,13 +16,20 @@ public class MemberDetailedInfoDto { private String imageUrl; + private boolean isGraduated; + public static MemberDetailedInfoDto create(Member member) { return MemberDetailedInfoDto.builder() .memberId(member.getId()) .memberName(member.getName()) .roleLevel(member.getRole().toRoleLevel()) .imageUrl(member.getImageUrl()) + .isGraduated(member.isGraduated()) .build(); } + public boolean isAdminRole() { + return roleLevel >= 2; + } + } From dc8107fc99e646a1c93e049ca8aa39274427b154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 02:15:48 +0900 Subject: [PATCH 34/47] =?UTF-8?q?refactor(Award):=20Member=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/domain/award/application/AwardService.java | 11 ++++++----- .../java/page/clab/api/domain/award/domain/Award.java | 10 +++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/page/clab/api/domain/award/application/AwardService.java b/src/main/java/page/clab/api/domain/award/application/AwardService.java index 840dfcf49..c46da4931 100644 --- a/src/main/java/page/clab/api/domain/award/application/AwardService.java +++ b/src/main/java/page/clab/api/domain/award/application/AwardService.java @@ -11,7 +11,7 @@ import page.clab.api.domain.award.dto.request.AwardUpdateRequestDto; import page.clab.api.domain.award.dto.response.AwardResponseDto; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; import page.clab.api.global.exception.PermissionDeniedException; @@ -50,18 +50,19 @@ public PagedResponseDto<AwardResponseDto> getMyAwards(Pageable pageable) { @Transactional public Long updateAward(Long awardId, AwardUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Award award = getAwardByIdOrThrow(awardId); - award.validateAccessPermission(currentMember); + award.validateAccessPermission(currentMemberInfo); award.update(requestDto); validationService.checkValid(award); return awardRepository.save(award).getId(); } + @Transactional public Long deleteAward(Long awardId) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Award award = getAwardByIdOrThrow(awardId); - award.validateAccessPermission(currentMember); + award.validateAccessPermission(currentMemberInfo); award.delete(); awardRepository.save(award); return award.getId(); diff --git a/src/main/java/page/clab/api/domain/award/domain/Award.java b/src/main/java/page/clab/api/domain/award/domain/Award.java index f05805376..3fd5168c2 100644 --- a/src/main/java/page/clab/api/domain/award/domain/Award.java +++ b/src/main/java/page/clab/api/domain/award/domain/Award.java @@ -15,7 +15,7 @@ import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; import page.clab.api.domain.award.dto.request.AwardUpdateRequestDto; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.global.common.domain.BaseEntity; import page.clab.api.global.exception.PermissionDeniedException; @@ -65,12 +65,12 @@ public void delete() { this.isDeleted = true; } - public boolean isOwner(Member member) { - return member.isSameMember(memberId); + public boolean isOwner(String memberId) { + return this.memberId.equals(memberId); } - public void validateAccessPermission(Member member) throws PermissionDeniedException { - if (!isOwner(member) && !member.isAdminRole()) { + public void validateAccessPermission(MemberDetailedInfoDto memberInfo) throws PermissionDeniedException { + if (!isOwner(memberInfo.getMemberId()) && !memberInfo.isAdminRole()) { throw new PermissionDeniedException("해당 게시글을 수정/삭제할 권한이 없습니다."); } } From 7601e7150bc5ebc03310b1090d669aea5e86d5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 03:08:08 +0900 Subject: [PATCH 35/47] =?UTF-8?q?refactor(Book):=20Member=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/BookLoanRecordService.java | 32 ++++++------- .../domain/book/application/BookService.java | 20 ++++++--- .../dao/BookLoanRecordRepositoryImpl.java | 11 ++++- .../clab/api/domain/book/domain/Book.java | 7 +-- .../domain/book/domain/BookLoanRecord.java | 21 ++++----- .../dto/response/BookDetailsResponseDto.java | 4 +- .../book/dto/response/BookResponseDto.java | 4 +- .../application/MemberLookupService.java | 8 +++- .../application/MemberLookupServiceImpl.java | 21 ++++++--- .../clab/api/domain/member/domain/Member.java | 22 ++------- .../dto/shared/BookBorrowerInfoDto.java | 45 +++++++++++++++++++ 11 files changed, 125 insertions(+), 70 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/member/dto/shared/BookBorrowerInfoDto.java diff --git a/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java b/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java index 885488eb7..d4e5cb8a0 100644 --- a/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java +++ b/src/main/java/page/clab/api/domain/book/application/BookLoanRecordService.java @@ -17,7 +17,7 @@ import page.clab.api.domain.book.exception.BookAlreadyAppliedForLoanException; import page.clab.api.domain.book.exception.MaxBorrowLimitExceededException; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.BookBorrowerInfoDto; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.CustomOptimisticLockingFailureException; @@ -43,18 +43,18 @@ public class BookLoanRecordService { @Transactional public Long requestBookLoan(BookLoanRecordRequestDto requestDto) throws CustomOptimisticLockingFailureException { try { - Member borrower = memberLookupService.getCurrentMember(); - borrower.checkLoanSuspension(); + BookBorrowerInfoDto borrowerInfo = memberLookupService.getCurrentMemberBorrowerInfo(); - validateBorrowLimit(borrower.getId()); + borrowerInfo.checkLoanSuspension(); + validateBorrowLimit(borrowerInfo.getMemberId()); Book book = bookService.getBookByIdOrThrow(requestDto.getBookId()); - checkIfLoanAlreadyApplied(book, borrower.getId()); + checkIfLoanAlreadyApplied(book, borrowerInfo.getMemberId()); - BookLoanRecord bookLoanRecord = BookLoanRecord.create(book, borrower); + BookLoanRecord bookLoanRecord = BookLoanRecord.create(book, borrowerInfo); validationService.checkValid(bookLoanRecord); - notificationService.sendNotificationToMember(borrower.getId(), "[" + book.getTitle() + "] 도서 대출 신청이 완료되었습니다."); + notificationService.sendNotificationToMember(borrowerInfo.getMemberId(), "[" + book.getTitle() + "] 도서 대출 신청이 완료되었습니다."); return bookLoanRecordRepository.save(bookLoanRecord).getId(); } catch (ObjectOptimisticLockingFailureException e) { throw new CustomOptimisticLockingFailureException("도서 대출 신청에 실패했습니다. 다시 시도해주세요."); @@ -63,29 +63,31 @@ public Long requestBookLoan(BookLoanRecordRequestDto requestDto) throws CustomOp @Transactional public Long returnBook(BookLoanRecordRequestDto requestDto) { - Member currentMember = memberLookupService.getCurrentMember(); - String currentMemberId = currentMember.getId(); + BookBorrowerInfoDto borrowerInfo = memberLookupService.getCurrentMemberBorrowerInfo(); + String currentMemberId = borrowerInfo.getMemberId(); Book book = bookService.getBookByIdOrThrow(requestDto.getBookId()); book.returnBook(currentMemberId); bookRepository.save(book); BookLoanRecord bookLoanRecord = getBookLoanRecordByBookAndReturnedAtIsNullOrThrow(book); - bookLoanRecord.markAsReturned(currentMember); + bookLoanRecord.markAsReturned(borrowerInfo); validationService.checkValid(bookLoanRecord); + memberLookupService.updateLoanSuspensionDate(borrowerInfo.getMemberId(), borrowerInfo.getLoanSuspensionDate()); + notificationService.sendNotificationToMember(currentMemberId, "[" + book.getTitle() + "] 도서 반납이 완료되었습니다."); return bookLoanRecordRepository.save(bookLoanRecord).getId(); } @Transactional public Long extendBookLoan(BookLoanRecordRequestDto requestDto) { - Member currentMember = memberLookupService.getCurrentMember(); - String currentMemberId = currentMember.getId(); + BookBorrowerInfoDto borrowerInfo = memberLookupService.getCurrentMemberBorrowerInfo(); + String currentMemberId = borrowerInfo.getMemberId(); Book book = bookService.getBookByIdOrThrow(requestDto.getBookId()); book.validateCurrentBorrower(currentMemberId); BookLoanRecord bookLoanRecord = getBookLoanRecordByBookAndReturnedAtIsNullOrThrow(book); - bookLoanRecord.extendLoan(currentMember); + bookLoanRecord.extendLoan(borrowerInfo); validationService.checkValid(bookLoanRecord); notificationService.sendNotificationToMember(currentMemberId, "[" + book.getTitle() + "] 도서 대출 연장이 완료되었습니다."); @@ -95,12 +97,12 @@ public Long extendBookLoan(BookLoanRecordRequestDto requestDto) { @Transactional public Long approveBookLoan(Long bookLoanRecordId) { - String currentMemberId = memberLookupService.getCurrentMemberId(); + String borrowerId = memberLookupService.getCurrentMemberId(); BookLoanRecord bookLoanRecord = getBookLoanRecordByIdOrThrow(bookLoanRecordId); Book book = bookService.getBookByIdOrThrow(bookLoanRecord.getBook().getId()); book.validateBookIsNotBorrowed(); - validateBorrowLimit(currentMemberId); + validateBorrowLimit(borrowerId); bookLoanRecord.approve(); validationService.checkValid(bookLoanRecord); diff --git a/src/main/java/page/clab/api/domain/book/application/BookService.java b/src/main/java/page/clab/api/domain/book/application/BookService.java index 3f5d0db75..31c017882 100644 --- a/src/main/java/page/clab/api/domain/book/application/BookService.java +++ b/src/main/java/page/clab/api/domain/book/application/BookService.java @@ -15,6 +15,8 @@ import page.clab.api.domain.book.dto.request.BookUpdateRequestDto; import page.clab.api.domain.book.dto.response.BookDetailsResponseDto; import page.clab.api.domain.book.dto.response.BookResponseDto; +import page.clab.api.domain.member.application.MemberLookupService; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; @@ -24,6 +26,8 @@ @RequiredArgsConstructor public class BookService { + private final MemberLookupService memberLookupService; + private final BookRepository bookRepository; private final BookLoanRecordRepository bookLoanRecordRepository; @@ -42,14 +46,16 @@ public PagedResponseDto<BookResponseDto> getBooksByConditions(String title, Stri @Transactional(readOnly = true) public BookDetailsResponseDto getBookDetails(Long bookId) { + MemberBasicInfoDto currentMemberInfo = memberLookupService.getCurrentMemberBasicInfo(); Book book = getBookByIdOrThrow(bookId); - return mapToBookDetailsResponseDto(book); + return mapToBookDetailsResponseDto(book, currentMemberInfo.getMemberName()); } @Transactional(readOnly = true) public PagedResponseDto<BookDetailsResponseDto> getDeletedBooks(Pageable pageable) { + MemberBasicInfoDto currentMemberInfo = memberLookupService.getCurrentMemberBasicInfo(); Page<Book> books = bookRepository.findAllByIsDeletedTrue(pageable); - return new PagedResponseDto<>(books.map(this::mapToBookDetailsResponseDto)); + return new PagedResponseDto<>(books.map((book) -> mapToBookDetailsResponseDto(book, currentMemberInfo.getMemberName()))); } @Transactional @@ -59,9 +65,10 @@ public Long updateBookInfo(Long bookId, BookUpdateRequestDto bookUpdateRequestDt return bookRepository.save(book).getId(); } + @Transactional public Long deleteBook(Long bookId) { Book book = getBookByIdOrThrow(bookId); - book.updateIsDeleted(true); + book.delete(); bookRepository.save(book); return book.getId(); } @@ -87,14 +94,15 @@ private LocalDateTime getDueDateForBook(Book book) { @NotNull private BookResponseDto mapToBookResponseDto(Book book) { + MemberBasicInfoDto currentMemberInfo = memberLookupService.getCurrentMemberBasicInfo(); LocalDateTime dueDate = getDueDateForBook(book); - return BookResponseDto.toDto(book, dueDate); + return BookResponseDto.toDto(book, currentMemberInfo.getMemberName(), dueDate); } @NotNull - private BookDetailsResponseDto mapToBookDetailsResponseDto(Book book) { + private BookDetailsResponseDto mapToBookDetailsResponseDto(Book book, String borrowerName) { LocalDateTime dueDate = getDueDateForBook(book); - return BookDetailsResponseDto.toDto(book, dueDate); + return BookDetailsResponseDto.toDto(book, borrowerName, dueDate); } } diff --git a/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepositoryImpl.java b/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepositoryImpl.java index 34e0ed84f..902690fe0 100644 --- a/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepositoryImpl.java +++ b/src/main/java/page/clab/api/domain/book/dao/BookLoanRecordRepositoryImpl.java @@ -12,6 +12,7 @@ import page.clab.api.domain.book.domain.QBookLoanRecord; import page.clab.api.domain.book.dto.response.BookLoanRecordOverdueResponseDto; import page.clab.api.domain.book.dto.response.BookLoanRecordResponseDto; +import page.clab.api.domain.member.domain.QMember; import page.clab.api.global.util.OrderSpecifierUtil; import java.time.LocalDateTime; @@ -26,6 +27,7 @@ public class BookLoanRecordRepositoryImpl implements BookLoanRecordRepositoryCus @Override public Page<BookLoanRecordResponseDto> findByConditions(Long bookId, String borrowerId, BookLoanStatus status, Pageable pageable) { QBookLoanRecord bookLoanRecord = QBookLoanRecord.bookLoanRecord; + QMember member = QMember.member; BooleanBuilder builder = new BooleanBuilder(); if (bookId != null) builder.and(bookLoanRecord.book.id.eq(bookId)); @@ -40,7 +42,7 @@ public Page<BookLoanRecordResponseDto> findByConditions(Long bookId, String borr bookLoanRecord.book.title, bookLoanRecord.book.imageUrl, bookLoanRecord.borrowerId, - bookLoanRecord.borrowerName, + member.name.as("borrowerName"), bookLoanRecord.borrowedAt, bookLoanRecord.returnedAt, bookLoanRecord.dueDate, @@ -48,6 +50,7 @@ public Page<BookLoanRecordResponseDto> findByConditions(Long bookId, String borr bookLoanRecord.status )) .from(bookLoanRecord) + .leftJoin(member).on(bookLoanRecord.borrowerId.eq(member.id)) .where(builder) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) @@ -56,6 +59,7 @@ public Page<BookLoanRecordResponseDto> findByConditions(Long bookId, String borr long total = queryFactory .selectFrom(bookLoanRecord) + .leftJoin(member).on(bookLoanRecord.borrowerId.eq(member.id)) .where(builder) .fetchCount(); @@ -65,6 +69,7 @@ public Page<BookLoanRecordResponseDto> findByConditions(Long bookId, String borr @Override public Page<BookLoanRecordOverdueResponseDto> findOverdueBookLoanRecords(Pageable pageable) { QBookLoanRecord bookLoanRecord = QBookLoanRecord.bookLoanRecord; + QMember member = QMember.member; LocalDateTime now = LocalDateTime.now(); @@ -74,12 +79,13 @@ public Page<BookLoanRecordOverdueResponseDto> findOverdueBookLoanRecords(Pageabl bookLoanRecord.book.id, bookLoanRecord.book.title, bookLoanRecord.borrowerId, - bookLoanRecord.borrowerName, + member.name.as("borrowerName"), bookLoanRecord.borrowedAt, bookLoanRecord.dueDate, bookLoanRecord.status )) .from(bookLoanRecord) + .leftJoin(member).on(bookLoanRecord.borrowerId.eq(member.id)) .where(bookLoanRecord.status.eq(BookLoanStatus.APPROVED) .and(bookLoanRecord.dueDate.lt(now))) .offset(pageable.getOffset()) @@ -89,6 +95,7 @@ public Page<BookLoanRecordOverdueResponseDto> findOverdueBookLoanRecords(Pageabl long total = queryFactory .selectFrom(bookLoanRecord) + .leftJoin(member).on(bookLoanRecord.borrowerId.eq(member.id)) .where(bookLoanRecord.status.eq(BookLoanStatus.APPROVED) .and(bookLoanRecord.dueDate.lt(now))) .fetchCount(); diff --git a/src/main/java/page/clab/api/domain/book/domain/Book.java b/src/main/java/page/clab/api/domain/book/domain/Book.java index 640154bed..470fe25b0 100644 --- a/src/main/java/page/clab/api/domain/book/domain/Book.java +++ b/src/main/java/page/clab/api/domain/book/domain/Book.java @@ -57,9 +57,6 @@ public class Book extends BaseEntity { @Column(name = "member_id") private String borrowerId; - @Column(name = "member_name") - private String borrowerName; - @Version private Long version; @@ -72,8 +69,8 @@ public void update(BookUpdateRequestDto requestDto) { Optional.ofNullable(requestDto.getReviewLinks()).ifPresent(this::setReviewLinks); } - public void updateIsDeleted(Boolean isDeleted) { - this.isDeleted = isDeleted; + public void delete() { + this.isDeleted = true; } public boolean isBorrower(String borrowerId) { diff --git a/src/main/java/page/clab/api/domain/book/domain/BookLoanRecord.java b/src/main/java/page/clab/api/domain/book/domain/BookLoanRecord.java index aeed93507..5888493dd 100644 --- a/src/main/java/page/clab/api/domain/book/domain/BookLoanRecord.java +++ b/src/main/java/page/clab/api/domain/book/domain/BookLoanRecord.java @@ -19,7 +19,7 @@ import page.clab.api.domain.book.exception.LoanNotPendingException; import page.clab.api.domain.book.exception.LoanSuspensionException; import page.clab.api.domain.book.exception.OverdueException; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.BookBorrowerInfoDto; import page.clab.api.global.common.domain.BaseEntity; import java.time.LocalDateTime; @@ -44,9 +44,6 @@ public class BookLoanRecord extends BaseEntity { @Column(name = "member_id", nullable = false) private String borrowerId; - @Column(name = "member_name", nullable = false) - private String borrowerName; - private LocalDateTime borrowedAt; private LocalDateTime returnedAt; @@ -58,24 +55,23 @@ public class BookLoanRecord extends BaseEntity { @Enumerated(EnumType.STRING) private BookLoanStatus status; - public static BookLoanRecord create(Book book, Member borrower) { + public static BookLoanRecord create(Book book, BookBorrowerInfoDto borrowerInfo) { return BookLoanRecord.builder() .book(book) - .borrowerId(borrower.getId()) - .borrowerName(borrower.getName()) + .borrowerId(borrowerInfo.getMemberId()) .loanExtensionCount(0L) .status(BookLoanStatus.PENDING) .build(); } - public void markAsReturned(Member borrower) { + public void markAsReturned(BookBorrowerInfoDto borrowerInfo) { if (this.returnedAt != null) { throw new BookAlreadyReturnedException("이미 반납된 도서입니다."); } this.returnedAt = LocalDateTime.now(); if (isOverdue(returnedAt)) { long overdueDays = ChronoUnit.DAYS.between(this.dueDate, this.returnedAt); - borrower.handleOverdueAndSuspension(overdueDays); + borrowerInfo.handleOverdueAndSuspension(overdueDays); } this.status = BookLoanStatus.RETURNED; } @@ -84,13 +80,12 @@ private boolean isOverdue(LocalDateTime returnedAt) { return returnedAt.isAfter(this.dueDate); } - public void extendLoan(Member borrower) { + public void extendLoan(BookBorrowerInfoDto borrowerInfo) { final long MAX_EXTENSIONS = 2; LocalDateTime now = LocalDateTime.now(); - if (borrower.getLoanSuspensionDate() != null && now.isBefore(borrower.getLoanSuspensionDate())) { - throw new LoanSuspensionException("대출 정지 중입니다. 연장할 수 없습니다."); - } + borrowerInfo.checkLoanSuspension(); + if (now.isAfter(this.dueDate)) { throw new LoanSuspensionException("연체 중인 도서는 연장할 수 없습니다."); } diff --git a/src/main/java/page/clab/api/domain/book/dto/response/BookDetailsResponseDto.java b/src/main/java/page/clab/api/domain/book/dto/response/BookDetailsResponseDto.java index a5f69adf9..2318c623c 100644 --- a/src/main/java/page/clab/api/domain/book/dto/response/BookDetailsResponseDto.java +++ b/src/main/java/page/clab/api/domain/book/dto/response/BookDetailsResponseDto.java @@ -35,11 +35,11 @@ public class BookDetailsResponseDto { private LocalDateTime updatedAt; - public static BookDetailsResponseDto toDto(Book book, LocalDateTime dueDate) { + public static BookDetailsResponseDto toDto(Book book, String borrowerName, LocalDateTime dueDate) { return BookDetailsResponseDto.builder() .id(book.getId()) .borrowerId(book.getBorrowerId() == null ? null : book.getBorrowerId()) - .borrowerName(book.getBorrowerName() == null ? null : book.getBorrowerName()) + .borrowerName(book.getBorrowerId() == null ? null : borrowerName) .category(book.getCategory()) .title(book.getTitle()) .author(book.getAuthor()) diff --git a/src/main/java/page/clab/api/domain/book/dto/response/BookResponseDto.java b/src/main/java/page/clab/api/domain/book/dto/response/BookResponseDto.java index df642cb19..8dce5e41b 100644 --- a/src/main/java/page/clab/api/domain/book/dto/response/BookResponseDto.java +++ b/src/main/java/page/clab/api/domain/book/dto/response/BookResponseDto.java @@ -32,11 +32,11 @@ public class BookResponseDto { private LocalDateTime updatedAt; - public static BookResponseDto toDto(Book book, LocalDateTime dueDate) { + public static BookResponseDto toDto(Book book, String borrowerName, LocalDateTime dueDate) { return BookResponseDto.builder() .id(book.getId()) .borrowerId(book.getBorrowerId() == null ? null : book.getBorrowerId()) - .borrowerName(book.getBorrowerName() == null ? null : book.getBorrowerName()) + .borrowerName(book.getBorrowerId() == null ? null : borrowerName) .category(book.getCategory()) .title(book.getTitle()) .author(book.getAuthor()) diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java index d67c6e769..7bd195939 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -2,15 +2,15 @@ import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.response.MemberResponseDto; +import page.clab.api.domain.member.dto.shared.BookBorrowerInfoDto; import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; +import java.time.LocalDateTime; import java.util.List; public interface MemberLookupService { - boolean existsMemberById(String memberId); - Member getMemberById(String memberId); Member getMemberByIdOrThrow(String memberId); @@ -35,4 +35,8 @@ public interface MemberLookupService { MemberDetailedInfoDto getCurrentMemberDetailedInfo(); + BookBorrowerInfoDto getCurrentMemberBorrowerInfo(); + + void updateLoanSuspensionDate(String memberId, LocalDateTime loanSuspensionDate); + } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java index 42985f56e..8c993c277 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -5,11 +5,13 @@ import page.clab.api.domain.member.dao.MemberRepository; import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.response.MemberResponseDto; +import page.clab.api.domain.member.dto.shared.BookBorrowerInfoDto; import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.global.auth.util.AuthUtil; import page.clab.api.global.exception.NotFoundException; +import java.time.LocalDateTime; import java.util.List; @Service @@ -18,11 +20,6 @@ public class MemberLookupServiceImpl implements MemberLookupService { private final MemberRepository memberRepository; - @Override - public boolean existsMemberById(String memberId) { - return memberRepository.existsById(memberId); - } - @Override public Member getMemberById(String memberId) { return memberRepository.findById(memberId) @@ -105,4 +102,18 @@ public MemberDetailedInfoDto getCurrentMemberDetailedInfo() { .orElseThrow(() -> new NotFoundException("[Member] id: " + currentMemberId + "에 해당하는 멤버가 존재하지 않습니다.")); } + @Override + public BookBorrowerInfoDto getCurrentMemberBorrowerInfo() { + String currentMemberId = getCurrentMemberId(); + return memberRepository.findById(currentMemberId) + .map(BookBorrowerInfoDto::create) + .orElseThrow(() -> new NotFoundException("[Member] id: " + currentMemberId + "에 해당하는 멤버가 존재하지 않습니다.")); + } + + public void updateLoanSuspensionDate(String memberId, LocalDateTime loanSuspensionDate) { + Member member = getMemberById(memberId); + member.updateLoanSuspensionDate(loanSuspensionDate); + memberRepository.save(member); + } + } diff --git a/src/main/java/page/clab/api/domain/member/domain/Member.java b/src/main/java/page/clab/api/domain/member/domain/Member.java index bdb172ee8..e48c2bc4a 100644 --- a/src/main/java/page/clab/api/domain/member/domain/Member.java +++ b/src/main/java/page/clab/api/domain/member/domain/Member.java @@ -23,7 +23,6 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; -import page.clab.api.domain.book.exception.LoanSuspensionException; import page.clab.api.domain.member.dto.request.MemberUpdateRequestDto; import page.clab.api.global.common.domain.BaseEntity; import page.clab.api.global.exception.PermissionDeniedException; @@ -218,25 +217,12 @@ public void updateLastLoginTime() { lastLoginTime = LocalDateTime.now(); } - public void clearImageUrl() { - this.imageUrl = null; - } - - public void checkLoanSuspension() { - if (loanSuspensionDate != null && LocalDateTime.now().isBefore(loanSuspensionDate)) { - throw new LoanSuspensionException("대출 정지 중입니다. 대출 정지일까지는 책을 대출할 수 없습니다."); - } + public void updateLoanSuspensionDate(LocalDateTime loanSuspensionDate) { + this.loanSuspensionDate = loanSuspensionDate; } - public void handleOverdueAndSuspension(long overdueDays) { - if (overdueDays > 0) { - LocalDateTime currentDate = LocalDateTime.now(); - if (loanSuspensionDate == null || loanSuspensionDate.isBefore(currentDate)) { - loanSuspensionDate = LocalDateTime.now().plusDays(overdueDays * 7);; - } else { - loanSuspensionDate = loanSuspensionDate.plusDays(overdueDays * 7); - } - } + public void clearImageUrl() { + this.imageUrl = null; } } diff --git a/src/main/java/page/clab/api/domain/member/dto/shared/BookBorrowerInfoDto.java b/src/main/java/page/clab/api/domain/member/dto/shared/BookBorrowerInfoDto.java new file mode 100644 index 000000000..fad0b24ce --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/dto/shared/BookBorrowerInfoDto.java @@ -0,0 +1,45 @@ +package page.clab.api.domain.member.dto.shared; + +import lombok.Builder; +import lombok.Getter; +import page.clab.api.domain.book.exception.LoanSuspensionException; +import page.clab.api.domain.member.domain.Member; + +import java.time.LocalDateTime; + +@Getter +@Builder +public class BookBorrowerInfoDto { + + private String memberId; + + private String memberName; + + private LocalDateTime loanSuspensionDate; + + public static BookBorrowerInfoDto create(Member member) { + return BookBorrowerInfoDto.builder() + .memberId(member.getId()) + .memberName(member.getName()) + .loanSuspensionDate(member.getLoanSuspensionDate()) + .build(); + } + + public void handleOverdueAndSuspension(long overdueDays) { + if (overdueDays > 0) { + LocalDateTime currentDate = LocalDateTime.now(); + if (loanSuspensionDate == null || loanSuspensionDate.isBefore(currentDate)) { + loanSuspensionDate = LocalDateTime.now().plusDays(overdueDays * 7); + } else { + loanSuspensionDate = loanSuspensionDate.plusDays(overdueDays * 7); + } + } + } + + public void checkLoanSuspension() { + if (loanSuspensionDate != null && LocalDateTime.now().isBefore(loanSuspensionDate)) { + throw new LoanSuspensionException("대출 정지 중입니다. 대출 정지일까지는 책을 대출할 수 없습니다."); + } + } + +} From 0ec40565d2c13e378511a4e214bebd68745d7a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 12:03:28 +0900 Subject: [PATCH 36/47] =?UTF-8?q?refactor(Comment):=20Member=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../comment/application/CommentService.java | 100 ++++++++---------- .../domain/comment/dao/CommentRepository.java | 3 +- .../api/domain/comment/domain/Comment.java | 24 ++--- .../dto/request/CommentRequestDto.java | 5 +- .../dto/response/CommentMyResponseDto.java | 8 +- .../dto/response/CommentResponseDto.java | 22 ++-- .../response/DeletedCommentResponseDto.java | 17 +-- .../application/MemberLookupService.java | 2 + .../application/MemberLookupServiceImpl.java | 7 ++ 9 files changed, 88 insertions(+), 100 deletions(-) diff --git a/src/main/java/page/clab/api/domain/comment/application/CommentService.java b/src/main/java/page/clab/api/domain/comment/application/CommentService.java index adef5f5f7..19e233a29 100644 --- a/src/main/java/page/clab/api/domain/comment/application/CommentService.java +++ b/src/main/java/page/clab/api/domain/comment/application/CommentService.java @@ -2,8 +2,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.hibernate.Hibernate; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -19,14 +19,14 @@ import page.clab.api.domain.comment.dto.response.CommentResponseDto; import page.clab.api.domain.comment.dto.response.DeletedCommentResponseDto; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.domain.notification.application.NotificationService; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; import page.clab.api.global.exception.PermissionDeniedException; import page.clab.api.global.validation.ValidationService; -import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -57,40 +57,43 @@ public Long createComment(Long parentId, Long boardId, CommentRequestDto request @Transactional(readOnly = true) public PagedResponseDto<CommentResponseDto> getAllComments(Long boardId, Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); + String currentMemberId = memberLookupService.getCurrentMemberId(); Page<Comment> comments = getCommentByBoardIdAndParentIsNull(boardId, pageable); - comments.forEach(comment -> { - Hibernate.initialize(comment.getChildren()); - sortChildrenComments(comment); - }); - Page<CommentResponseDto> commentDtos = comments.map(comment -> toCommentResponseDto(comment, currentMember)); - return new PagedResponseDto<>(commentDtos); + List<CommentResponseDto> commentDtos = comments.stream() + .map(comment -> toCommentResponseDtoWithMemberInfo(comment, currentMemberId)) + .toList(); + return new PagedResponseDto<>(new PageImpl<>(commentDtos, pageable, comments.getTotalElements())); } @Transactional(readOnly = true) public PagedResponseDto<CommentMyResponseDto> getMyComments(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); - Page<Comment> comments = getCommentByWriter(currentMember, pageable); - List<CommentMyResponseDto> dtos = comments - .map(comment -> toCommentMyResponseDto(comment, currentMember)) - .stream() + String currentMemberId = memberLookupService.getCurrentMemberId(); + Page<Comment> comments = getCommentByWriterId(currentMemberId, pageable); + List<CommentMyResponseDto> dtos = comments.stream() + .map(comment -> toCommentMyResponseDto(comment, currentMemberId)) .filter(Objects::nonNull) .toList(); - return new PagedResponseDto<>(dtos, pageable, dtos.size()); + return new PagedResponseDto<>(new PageImpl<>(dtos, pageable, comments.getTotalElements())); } @Transactional(readOnly = true) public PagedResponseDto<DeletedCommentResponseDto> getDeletedComments(Long boardId, Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); + String currentMemberId = memberLookupService.getCurrentMemberId(); Page<Comment> comments = commentRepository.findAllByIsDeletedTrueAndBoardId(boardId, pageable); - return new PagedResponseDto<>(comments.map(comment -> DeletedCommentResponseDto.toDto(comment, currentMember.getId()))); + List<DeletedCommentResponseDto> deletedCommentDtos = comments.stream() + .map(comment -> { + MemberDetailedInfoDto memberInfo = memberLookupService.getMemberDetailedInfoById(comment.getWriterId()); + return DeletedCommentResponseDto.toDto(comment, memberInfo, comment.isOwner(currentMemberId)); + }) + .toList(); + return new PagedResponseDto<>(new PageImpl<>(deletedCommentDtos, pageable, comments.getTotalElements())); } @Transactional public Long updateComment(Long commentId, CommentUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto memberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Comment comment = getCommentByIdOrThrow(commentId); - comment.validateAccessPermission(currentMember); + comment.validateAccessPermission(memberInfo); comment.update(requestDto); validationService.checkValid(comment); commentRepository.save(comment); @@ -98,25 +101,25 @@ public Long updateComment(Long commentId, CommentUpdateRequestDto requestDto) th } public Long deleteComment(Long commentId) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto memberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Comment comment = getCommentByIdOrThrow(commentId); - comment.validateAccessPermission(currentMember); - comment.updateIsDeleted(); + comment.validateAccessPermission(memberInfo); + comment.delete(); commentRepository.save(comment); return comment.getBoard().getId(); } @Transactional public Long toggleLikeStatus(Long commentId) { - Member currentMember = memberLookupService.getCurrentMember(); + String currentMemberId = memberLookupService.getCurrentMemberId(); Comment comment = getCommentByIdOrThrow(commentId); - Optional<CommentLike> commentLikeOpt = commentLikeRepository.findByCommentIdAndMemberId(comment.getId(), currentMember.getId()); + Optional<CommentLike> commentLikeOpt = commentLikeRepository.findByCommentIdAndMemberId(comment.getId(), currentMemberId); if (commentLikeOpt.isPresent()) { comment.decrementLikes(); commentLikeRepository.delete(commentLikeOpt.get()); } else { comment.incrementLikes(); - CommentLike newLike = CommentLike.create(currentMember.getId(), comment.getId()); + CommentLike newLike = CommentLike.create(currentMemberId, comment.getId()); commentLikeRepository.save(newLike); } return comment.getLikes(); @@ -131,15 +134,15 @@ private Page<Comment> getCommentByBoardIdAndParentIsNull(Long boardId, Pageable return commentRepository.findAllByBoardIdAndParentIsNull(boardId, pageable); } - private Page<Comment> getCommentByWriter(Member member, Pageable pageable) { - return commentRepository.findAllByWriter(member, pageable); + private Page<Comment> getCommentByWriterId(String memberId, Pageable pageable) { + return commentRepository.findAllByWriterId(memberId, pageable); } private Comment createAndStoreComment(Long parentId, Long boardId, CommentRequestDto requestDto) { - Member currentMember = memberLookupService.getCurrentMember(); + String currentMemberId = memberLookupService.getCurrentMemberId(); Board board = boardService.getBoardByIdOrThrow(boardId); Comment parent = findParentComment(parentId); - Comment comment = CommentRequestDto.toEntity(requestDto, board, currentMember, parent); + Comment comment = CommentRequestDto.toEntity(requestDto, board, currentMemberId, parent); if (parent != null) { parent.addChildComment(comment); } @@ -153,37 +156,28 @@ private Comment findParentComment(Long parentId) { private void sendNotificationForNewComment(Comment comment) { Board board = comment.getBoard(); - Member boardOwner = memberLookupService.getMemberById(board.getMemberId()); - String notificationMessage = String.format("[%s] %s님이 게시글에 댓글을 남겼습니다.", board.getTitle(), comment.getWriterName()); - notificationService.sendNotificationToMember(boardOwner, notificationMessage); + MemberBasicInfoDto memberInfo = memberLookupService.getMemberBasicInfoById(comment.getWriterId()); + String notificationMessage = String.format("[%s] %s님이 게시글에 댓글을 남겼습니다.", board.getTitle(), memberInfo.getMemberName()); + notificationService.sendNotificationToMember(board.getMemberId(), notificationMessage); } - private CommentResponseDto toCommentResponseDto(Comment comment, Member currentMember) { - Boolean hasLikeByMe = checkLikeStatus(comment.getId(), currentMember.getId()); - CommentResponseDto responseDto = CommentResponseDto.toDto(comment, currentMember.getId()); - responseDto.getChildren().forEach(childDto -> setLikeStatusForChildren(childDto, currentMember)); - if (!responseDto.getIsDeleted()) { - responseDto.setHasLikeByMe(hasLikeByMe); - } - return responseDto; + private CommentResponseDto toCommentResponseDtoWithMemberInfo(Comment comment, String currentMemberId) { + MemberDetailedInfoDto memberInfo = memberLookupService.getMemberDetailedInfoById(comment.getWriterId()); + List<CommentResponseDto> childrenDtos = comment.getChildren().stream() + .map(child -> toCommentResponseDtoWithMemberInfo(child, currentMemberId)) + .toList(); + boolean isOwner = comment.isOwner(currentMemberId); + return CommentResponseDto.toDto(comment, memberInfo, isOwner, childrenDtos); } private boolean checkLikeStatus(Long commentId, String memberId) { return commentLikeRepository.existsByCommentIdAndMemberId(commentId, memberId); } - private void setLikeStatusForChildren(CommentResponseDto responseDto, Member member) { - responseDto.setHasLikeByMe(checkLikeStatus(responseDto.getId(), member.getId())); - responseDto.getChildren().forEach(childDto -> setLikeStatusForChildren(childDto, member)); - } - - private CommentMyResponseDto toCommentMyResponseDto(Comment comment, Member currentMember) { - boolean hasLikeByMe = checkLikeStatus(comment.getId(), currentMember.getId()); - return CommentMyResponseDto.toDto(comment, hasLikeByMe); - } - - private void sortChildrenComments(Comment comment) { - comment.getChildren().sort(Comparator.comparing(Comment::getCreatedAt)); + private CommentMyResponseDto toCommentMyResponseDto(Comment comment, String currentMemberId) { + boolean hasLikeByMe = checkLikeStatus(comment.getId(), currentMemberId); + MemberDetailedInfoDto memberInfo = memberLookupService.getMemberDetailedInfoById(comment.getWriterId()); + return CommentMyResponseDto.toDto(comment, memberInfo, hasLikeByMe); } } \ No newline at end of file diff --git a/src/main/java/page/clab/api/domain/comment/dao/CommentRepository.java b/src/main/java/page/clab/api/domain/comment/dao/CommentRepository.java index 1a2f2d416..0a34975de 100644 --- a/src/main/java/page/clab/api/domain/comment/dao/CommentRepository.java +++ b/src/main/java/page/clab/api/domain/comment/dao/CommentRepository.java @@ -8,14 +8,13 @@ import org.springframework.stereotype.Repository; import page.clab.api.domain.board.domain.Board; import page.clab.api.domain.comment.domain.Comment; -import page.clab.api.domain.member.domain.Member; @Repository public interface CommentRepository extends JpaRepository<Comment, Long> { Page<Comment> findAllByBoardIdAndParentIsNull(Long boardId, Pageable pageable); - Page<Comment> findAllByWriter(Member member, Pageable pageable); + Page<Comment> findAllByWriterId(String memberId, Pageable pageable); Long countByBoard(Board board); diff --git a/src/main/java/page/clab/api/domain/comment/domain/Comment.java b/src/main/java/page/clab/api/domain/comment/domain/Comment.java index 87ab10288..2bbfaae42 100644 --- a/src/main/java/page/clab/api/domain/comment/domain/Comment.java +++ b/src/main/java/page/clab/api/domain/comment/domain/Comment.java @@ -9,7 +9,6 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; -import jakarta.persistence.OrderBy; import jakarta.validation.constraints.Size; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -19,7 +18,7 @@ import lombok.Setter; import page.clab.api.domain.board.domain.Board; import page.clab.api.domain.comment.dto.request.CommentUpdateRequestDto; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.global.common.domain.BaseEntity; import page.clab.api.global.exception.PermissionDeniedException; @@ -43,9 +42,8 @@ public class Comment extends BaseEntity { @JoinColumn(name = "board_id") private Board board; - @ManyToOne - @JoinColumn(name = "member_id") - private Member writer; + @Column(name = "member_id", nullable = false) + private String writerId; @Column(nullable = false) private String nickname; @@ -79,20 +77,12 @@ public void addChildComment(Comment child) { child.setParent(this); } - public String getWriterName() { - return this.wantAnonymous ? this.nickname : this.writer.getName(); - } - - public boolean isOwner(Member member) { - return this.writer.isSameMember(member); - } - public boolean isOwner(String memberId) { - return this.writer.isSameMember(memberId); + return this.writerId.equals(memberId); } - public void validateAccessPermission(Member member) throws PermissionDeniedException { - if (!isOwner(member) && !member.isAdminRole()) { + public void validateAccessPermission(MemberDetailedInfoDto memberInfo) throws PermissionDeniedException { + if (!isOwner(memberInfo.getMemberId()) && !memberInfo.isAdminRole()) { throw new PermissionDeniedException("해당 댓글을 수정/삭제할 권한이 없습니다."); } } @@ -107,7 +97,7 @@ public void decrementLikes() { } } - public void updateIsDeleted(){ + public void delete() { this.isDeleted = true; } diff --git a/src/main/java/page/clab/api/domain/comment/dto/request/CommentRequestDto.java b/src/main/java/page/clab/api/domain/comment/dto/request/CommentRequestDto.java index 8879451d7..b4e0ef1d6 100644 --- a/src/main/java/page/clab/api/domain/comment/dto/request/CommentRequestDto.java +++ b/src/main/java/page/clab/api/domain/comment/dto/request/CommentRequestDto.java @@ -6,7 +6,6 @@ import lombok.Setter; import page.clab.api.domain.board.domain.Board; import page.clab.api.domain.comment.domain.Comment; -import page.clab.api.domain.member.domain.Member; import page.clab.api.global.util.RandomNicknameUtil; @Getter @@ -21,10 +20,10 @@ public class CommentRequestDto { @Schema(description = "익명 사용 여부", example = "false", required = true) private boolean wantAnonymous; - public static Comment toEntity(CommentRequestDto requestDto, Board board, Member member, Comment parent) { + public static Comment toEntity(CommentRequestDto requestDto, Board board, String writerId, Comment parent) { return Comment.builder() .board(board) - .writer(member) + .writerId(writerId) .nickname(RandomNicknameUtil.makeRandomNickname()) .content(requestDto.getContent()) .parent(parent) diff --git a/src/main/java/page/clab/api/domain/comment/dto/response/CommentMyResponseDto.java b/src/main/java/page/clab/api/domain/comment/dto/response/CommentMyResponseDto.java index 327c2b3b2..e359abfd8 100644 --- a/src/main/java/page/clab/api/domain/comment/dto/response/CommentMyResponseDto.java +++ b/src/main/java/page/clab/api/domain/comment/dto/response/CommentMyResponseDto.java @@ -2,8 +2,8 @@ import lombok.Builder; import lombok.Getter; -import page.clab.api.domain.board.domain.BoardCategory; import page.clab.api.domain.comment.domain.Comment; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import java.time.LocalDateTime; @@ -29,7 +29,7 @@ public class CommentMyResponseDto { private LocalDateTime createdAt; - public static CommentMyResponseDto toDto(Comment comment, boolean hasLikeByMe) { + public static CommentMyResponseDto toDto(Comment comment, MemberDetailedInfoDto memberInfo, boolean hasLikeByMe) { if (comment.getBoard() == null || comment.getIsDeleted()) { return null; } @@ -37,8 +37,8 @@ public static CommentMyResponseDto toDto(Comment comment, boolean hasLikeByMe) { .id(comment.getId()) .boardId(comment.getBoard().getId()) .boardCategory(comment.getBoard().getCategory().getKey()) - .writer(comment.isWantAnonymous() ? comment.getNickname() : comment.getWriter().getName()) - .writerImageUrl(comment.isWantAnonymous() ? null : comment.getWriter().getImageUrl()) + .writer(comment.isWantAnonymous() ? comment.getNickname() : memberInfo.getMemberName()) + .writerImageUrl(comment.isWantAnonymous() ? null : memberInfo.getImageUrl()) .content(comment.getContent()) .likes(comment.getLikes()) .hasLikeByMe(hasLikeByMe) diff --git a/src/main/java/page/clab/api/domain/comment/dto/response/CommentResponseDto.java b/src/main/java/page/clab/api/domain/comment/dto/response/CommentResponseDto.java index b11f029f5..966c9d17d 100644 --- a/src/main/java/page/clab/api/domain/comment/dto/response/CommentResponseDto.java +++ b/src/main/java/page/clab/api/domain/comment/dto/response/CommentResponseDto.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.Setter; import page.clab.api.domain.comment.domain.Comment; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import java.time.LocalDateTime; import java.util.List; @@ -39,33 +40,28 @@ public class CommentResponseDto { private LocalDateTime createdAt; - public static CommentResponseDto toDto(Comment comment, String currentMemberId) { + public static CommentResponseDto toDto(Comment comment, MemberDetailedInfoDto memberInfo, boolean isOwner, List<CommentResponseDto> children) { if (comment.getIsDeleted()) { return CommentResponseDto.builder() .id(comment.getId()) .isDeleted(true) - .children(comment.getChildren().stream() - .map(child -> CommentResponseDto.toDto(child, currentMemberId)) - .toList()) + .children(children) .createdAt(comment.getCreatedAt()) .build(); } return CommentResponseDto.builder() .id(comment.getId()) .isDeleted(false) - .writerId(comment.isWantAnonymous() ? null : comment.getWriter().getId()) - .writerName(comment.isWantAnonymous() ? comment.getNickname() : comment.getWriter().getName()) - .writerImageUrl(comment.isWantAnonymous() ? null : comment.getWriter().getImageUrl()) - .writerRoleLevel(comment.isWantAnonymous() ? null : comment.getWriter().getRole().toRoleLevel()) + .writerId(comment.isWantAnonymous() ? null : comment.getWriterId()) + .writerName(comment.isWantAnonymous() ? comment.getNickname() : memberInfo.getMemberName()) + .writerImageUrl(comment.isWantAnonymous() ? null : memberInfo.getImageUrl()) + .writerRoleLevel(comment.isWantAnonymous() ? null : memberInfo.getRoleLevel()) .content(comment.getContent()) - .children(comment.getChildren().stream() - .map(child -> CommentResponseDto.toDto(child, currentMemberId)) - .toList()) + .children(children) .likes(comment.getLikes()) - .isOwner(comment.isOwner(currentMemberId)) + .isOwner(isOwner) .createdAt(comment.getCreatedAt()) .build(); - } } diff --git a/src/main/java/page/clab/api/domain/comment/dto/response/DeletedCommentResponseDto.java b/src/main/java/page/clab/api/domain/comment/dto/response/DeletedCommentResponseDto.java index 2a94dfc4f..d4d9b60b3 100644 --- a/src/main/java/page/clab/api/domain/comment/dto/response/DeletedCommentResponseDto.java +++ b/src/main/java/page/clab/api/domain/comment/dto/response/DeletedCommentResponseDto.java @@ -1,12 +1,13 @@ package page.clab.api.domain.comment.dto.response; import com.fasterxml.jackson.annotation.JsonProperty; -import java.time.LocalDateTime; -import java.util.List; import lombok.Builder; import lombok.Getter; import lombok.Setter; import page.clab.api.domain.comment.domain.Comment; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; + +import java.time.LocalDateTime; @Getter @Setter @@ -32,16 +33,16 @@ public class DeletedCommentResponseDto { private LocalDateTime createdAt; - public static DeletedCommentResponseDto toDto(Comment comment, String currentMemberId) { + public static DeletedCommentResponseDto toDto(Comment comment, MemberDetailedInfoDto memberInfo, boolean isOwner) { return DeletedCommentResponseDto.builder() .id(comment.getId()) - .writerId(comment.isWantAnonymous() ? null : comment.getWriter().getId()) - .writerName(comment.isWantAnonymous() ? comment.getNickname() : comment.getWriter().getName()) - .writerImageUrl(comment.isWantAnonymous() ? null : comment.getWriter().getImageUrl()) - .writerRoleLevel(comment.isWantAnonymous() ? null : comment.getWriter().getRole().toRoleLevel()) + .writerId(comment.isWantAnonymous() ? null : memberInfo.getMemberId()) + .writerName(comment.isWantAnonymous() ? comment.getNickname() : memberInfo.getMemberName()) + .writerImageUrl(comment.isWantAnonymous() ? null : memberInfo.getImageUrl()) + .writerRoleLevel(comment.isWantAnonymous() ? null : memberInfo.getRoleLevel()) .content(comment.getContent()) .likes(comment.getLikes()) - .isOwner(comment.isOwner(currentMemberId)) + .isOwner(isOwner) .createdAt(comment.getCreatedAt()) .build(); } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java index 7bd195939..b02a343cf 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -33,6 +33,8 @@ public interface MemberLookupService { MemberBasicInfoDto getCurrentMemberBasicInfo(); + MemberDetailedInfoDto getMemberDetailedInfoById(String memberId); + MemberDetailedInfoDto getCurrentMemberDetailedInfo(); BookBorrowerInfoDto getCurrentMemberBorrowerInfo(); diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java index 8c993c277..d83eb004a 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -94,6 +94,13 @@ public MemberBasicInfoDto getCurrentMemberBasicInfo() { .orElseThrow(() -> new NotFoundException("[Member] id: " + currentMemberId + "에 해당하는 멤버가 존재하지 않습니다.")); } + @Override + public MemberDetailedInfoDto getMemberDetailedInfoById(String memberId) { + return memberRepository.findById(memberId) + .map(MemberDetailedInfoDto::create) + .orElseThrow(() -> new NotFoundException("[Member] id: " + memberId + "에 해당하는 멤버가 존재하지 않습니다.")); + } + @Override public MemberDetailedInfoDto getCurrentMemberDetailedInfo() { String currentMemberId = getCurrentMemberId(); From 9415198af7620ce9840c4213035d0e53d5044633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 12:34:14 +0900 Subject: [PATCH 37/47] =?UTF-8?q?feat(Comment):=20EventProcessor=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/CommentEventProcessor.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/java/page/clab/api/domain/comment/application/CommentEventProcessor.java diff --git a/src/main/java/page/clab/api/domain/comment/application/CommentEventProcessor.java b/src/main/java/page/clab/api/domain/comment/application/CommentEventProcessor.java new file mode 100644 index 000000000..5f0bfcac7 --- /dev/null +++ b/src/main/java/page/clab/api/domain/comment/application/CommentEventProcessor.java @@ -0,0 +1,34 @@ +package page.clab.api.domain.comment.application; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.event.MemberEventProcessor; +import page.clab.api.domain.member.event.MemberEventProcessorRegistry; + +@Component +@RequiredArgsConstructor +public class CommentEventProcessor implements MemberEventProcessor { + + private final MemberEventProcessorRegistry processorRegistry; + + @PostConstruct + public void init() { + processorRegistry.registerProcessor(this); + } + + @Override + @Transactional + public void processMemberDeleted(Member member) { + // do nothing + } + + @Override + @Transactional + public void processMemberUpdated(Member member) { + // do nothing + } + +} From 7f620c9c108f0518954027f14589d61ac683b93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 12:59:59 +0900 Subject: [PATCH 38/47] =?UTF-8?q?refactor(Donation):=20Member=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/DonationEventProcessor.java | 34 ++++++++++++++ .../donation/application/DonationService.java | 44 +++++++++---------- .../donation/dao/DonationRepository.java | 3 +- .../donation/dao/DonationRepositoryImpl.java | 8 ++-- .../api/domain/donation/domain/Donation.java | 15 ++++--- .../dto/request/DonationRequestDto.java | 5 +-- .../dto/response/DonationResponseDto.java | 10 ++--- .../dto/shared/MemberDetailedInfoDto.java | 4 ++ 8 files changed, 81 insertions(+), 42 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/donation/application/DonationEventProcessor.java diff --git a/src/main/java/page/clab/api/domain/donation/application/DonationEventProcessor.java b/src/main/java/page/clab/api/domain/donation/application/DonationEventProcessor.java new file mode 100644 index 000000000..d2cff3110 --- /dev/null +++ b/src/main/java/page/clab/api/domain/donation/application/DonationEventProcessor.java @@ -0,0 +1,34 @@ +package page.clab.api.domain.donation.application; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.event.MemberEventProcessor; +import page.clab.api.domain.member.event.MemberEventProcessorRegistry; + +@Component +@RequiredArgsConstructor +public class DonationEventProcessor implements MemberEventProcessor { + + private final MemberEventProcessorRegistry processorRegistry; + + @PostConstruct + public void init() { + processorRegistry.registerProcessor(this); + } + + @Override + @Transactional + public void processMemberDeleted(Member member) { + // do nothing + } + + @Override + @Transactional + public void processMemberUpdated(Member member) { + // do nothing + } + +} diff --git a/src/main/java/page/clab/api/domain/donation/application/DonationService.java b/src/main/java/page/clab/api/domain/donation/application/DonationService.java index 5073239e2..136d21b6a 100644 --- a/src/main/java/page/clab/api/domain/donation/application/DonationService.java +++ b/src/main/java/page/clab/api/domain/donation/application/DonationService.java @@ -11,7 +11,8 @@ import page.clab.api.domain.donation.dto.request.DonationUpdateRequestDto; import page.clab.api.domain.donation.dto.response.DonationResponseDto; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.exception.NotFoundException; import page.clab.api.global.exception.PermissionDeniedException; @@ -31,8 +32,8 @@ public class DonationService { @Transactional public Long createDonation(DonationRequestDto requestDto) { - Member currentMember = memberLookupService.getCurrentMember(); - Donation donation = DonationRequestDto.toEntity(requestDto, currentMember); + String currentMemberId = memberLookupService.getCurrentMemberId(); + Donation donation = DonationRequestDto.toEntity(requestDto, currentMemberId); validationService.checkValid(donation); return donationRepository.save(donation).getId(); } @@ -40,36 +41,45 @@ public Long createDonation(DonationRequestDto requestDto) { @Transactional(readOnly = true) public PagedResponseDto<DonationResponseDto> getDonationsByConditions(String memberId, String name, LocalDate startDate, LocalDate endDate, Pageable pageable) { Page<Donation> donations = donationRepository.findByConditions(memberId, name, startDate, endDate, pageable); - return new PagedResponseDto<>(donations.map(DonationResponseDto::toDto)); + return new PagedResponseDto<>(donations.map(donation -> { + MemberBasicInfoDto memberInfo = memberLookupService.getMemberBasicInfoById(donation.getMemberId()); + return DonationResponseDto.toDto(donation, memberInfo.getMemberName()); + })); } @Transactional(readOnly = true) public PagedResponseDto<DonationResponseDto> getMyDonations(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); - Page<Donation> donations = getDonationsByDonor(currentMember, pageable); - return new PagedResponseDto<>(donations.map(DonationResponseDto::toDto)); + String currentMemberId = memberLookupService.getCurrentMemberId(); + Page<Donation> donations = donationRepository.findByMemberId(currentMemberId, pageable); + return new PagedResponseDto<>(donations.map(donation -> { + MemberBasicInfoDto memberInfo = memberLookupService.getMemberBasicInfoById(donation.getMemberId()); + return DonationResponseDto.toDto(donation, memberInfo.getMemberName()); + })); } @Transactional(readOnly = true) public PagedResponseDto<DonationResponseDto> getDeletedDonations(Pageable pageable) { Page<Donation> donations = donationRepository.findAllByIsDeletedTrue(pageable); - return new PagedResponseDto<>(donations.map(DonationResponseDto::toDto)); + return new PagedResponseDto<>(donations.map(donation -> { + MemberBasicInfoDto memberInfo = memberLookupService.getMemberBasicInfoById(donation.getMemberId()); + return DonationResponseDto.toDto(donation, memberInfo.getMemberName()); + })); } @Transactional public Long updateDonation(Long donationId, DonationUpdateRequestDto donationUpdateRequestDto) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Donation donation = getDonationByIdOrThrow(donationId); - validateDonationUpdatePermission(currentMember); + donation.validateAccessPermission(currentMemberInfo.isSuperAdminRole()); donation.update(donationUpdateRequestDto); validationService.checkValid(donation); return donationRepository.save(donation).getId(); } public Long deleteDonation(Long donationId) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); Donation donation = getDonationByIdOrThrow(donationId); - validateDonationUpdatePermission(currentMember); + donation.validateAccessPermission(currentMemberInfo.isSuperAdminRole()); donationRepository.delete(donation); return donation.getId(); } @@ -79,14 +89,4 @@ private Donation getDonationByIdOrThrow(Long donationId) { .orElseThrow(() -> new NotFoundException("해당 후원 정보가 존재하지 않습니다.")); } - private Page<Donation> getDonationsByDonor(Member member, Pageable pageable) { - return donationRepository.findByDonor(member, pageable); - } - - private void validateDonationUpdatePermission(Member member) throws PermissionDeniedException { - if (!member.isSuperAdminRole()) { - throw new PermissionDeniedException("해당 후원 정보를 수정할 권한이 없습니다."); - } - } - } \ No newline at end of file diff --git a/src/main/java/page/clab/api/domain/donation/dao/DonationRepository.java b/src/main/java/page/clab/api/domain/donation/dao/DonationRepository.java index c6a37ac68..e8c5184eb 100644 --- a/src/main/java/page/clab/api/domain/donation/dao/DonationRepository.java +++ b/src/main/java/page/clab/api/domain/donation/dao/DonationRepository.java @@ -7,13 +7,12 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.querydsl.QuerydslPredicateExecutor; import page.clab.api.domain.donation.domain.Donation; -import page.clab.api.domain.member.domain.Member; public interface DonationRepository extends JpaRepository<Donation, Long>, DonationRepositoryCustom, QuerydslPredicateExecutor<Donation> { Page<Donation> findAllByOrderByCreatedAtDesc(Pageable pageable); - Page<Donation> findByDonor(Member member, Pageable pageable); + Page<Donation> findByMemberId(String memberId, Pageable pageable); @Query(value = "SELECT d.* FROM donation d WHERE d.is_deleted = true", nativeQuery = true) Page<Donation> findAllByIsDeletedTrue(Pageable pageable); diff --git a/src/main/java/page/clab/api/domain/donation/dao/DonationRepositoryImpl.java b/src/main/java/page/clab/api/domain/donation/dao/DonationRepositoryImpl.java index 08c8fd1e6..352cec50e 100644 --- a/src/main/java/page/clab/api/domain/donation/dao/DonationRepositoryImpl.java +++ b/src/main/java/page/clab/api/domain/donation/dao/DonationRepositoryImpl.java @@ -10,10 +10,10 @@ import page.clab.api.domain.donation.domain.Donation; import page.clab.api.domain.donation.domain.QDonation; import page.clab.api.domain.member.domain.QMember; +import page.clab.api.global.util.OrderSpecifierUtil; import java.time.LocalDate; import java.util.List; -import page.clab.api.global.util.OrderSpecifierUtil; @Repository @RequiredArgsConstructor @@ -27,14 +27,14 @@ public Page<Donation> findByConditions(String memberId, String name, LocalDate s QMember member = QMember.member; BooleanBuilder builder = new BooleanBuilder(); - if (memberId != null && !memberId.isBlank()) builder.and(donation.donor.id.eq(memberId)); + if (memberId != null && !memberId.isBlank()) builder.and(donation.memberId.eq(memberId)); if (name != null && !name.isBlank()) builder.and(member.name.containsIgnoreCase(name)); if (startDate != null) builder.and(donation.createdAt.goe(startDate.atStartOfDay())); if (endDate != null) builder.and(donation.createdAt.loe(endDate.plusDays(1).atStartOfDay())); List<Donation> results = queryFactory .selectFrom(donation) - .leftJoin(donation.donor, member) + .leftJoin(member).on(donation.memberId.eq(member.id)) .where(builder) .orderBy(OrderSpecifierUtil.getOrderSpecifiers(pageable, donation)) .offset(pageable.getOffset()) @@ -43,7 +43,7 @@ public Page<Donation> findByConditions(String memberId, String name, LocalDate s long count = queryFactory .selectFrom(donation) - .leftJoin(donation.donor, member) + .leftJoin(member).on(donation.memberId.eq(member.id)) .where(builder) .fetchCount(); diff --git a/src/main/java/page/clab/api/domain/donation/domain/Donation.java b/src/main/java/page/clab/api/domain/donation/domain/Donation.java index 26f8c2081..22ce7000a 100644 --- a/src/main/java/page/clab/api/domain/donation/domain/Donation.java +++ b/src/main/java/page/clab/api/domain/donation/domain/Donation.java @@ -5,8 +5,6 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Size; import lombok.AccessLevel; @@ -18,8 +16,8 @@ import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; import page.clab.api.domain.donation.dto.request.DonationUpdateRequestDto; -import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.domain.BaseEntity; +import page.clab.api.global.exception.PermissionDeniedException; import java.util.Optional; @@ -37,9 +35,8 @@ public class Donation extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - @JoinColumn(name = "member_id", nullable = false) - private Member donor; + @Column(name = "member_id", nullable = false) + private String memberId; @Column(nullable = false) @Min(value = 1, message = "{min.donation.amount}") @@ -54,4 +51,10 @@ public void update(DonationUpdateRequestDto donationUpdateRequestDto) { Optional.ofNullable(donationUpdateRequestDto.getMessage()).ifPresent(this::setMessage); } + public void validateAccessPermission(boolean isSuperAdmin) throws PermissionDeniedException { + if (!isSuperAdmin) { + throw new PermissionDeniedException("해당 후원 정보를 수정할 권한이 없습니다."); + } + } + } \ No newline at end of file diff --git a/src/main/java/page/clab/api/domain/donation/dto/request/DonationRequestDto.java b/src/main/java/page/clab/api/domain/donation/dto/request/DonationRequestDto.java index b17733320..bf2606fb5 100644 --- a/src/main/java/page/clab/api/domain/donation/dto/request/DonationRequestDto.java +++ b/src/main/java/page/clab/api/domain/donation/dto/request/DonationRequestDto.java @@ -5,7 +5,6 @@ import lombok.Getter; import lombok.Setter; import page.clab.api.domain.donation.domain.Donation; -import page.clab.api.domain.member.domain.Member; @Getter @Setter @@ -19,9 +18,9 @@ public class DonationRequestDto { @Schema(description = "후원 메시지", example = "대회 상금 일부 후원", required = true) private String message; - public static Donation toEntity(DonationRequestDto requestDto, Member member) { + public static Donation toEntity(DonationRequestDto requestDto, String memberId) { return Donation.builder() - .donor(member) + .memberId(memberId) .amount(requestDto.getAmount()) .message(requestDto.getMessage()) .build(); diff --git a/src/main/java/page/clab/api/domain/donation/dto/response/DonationResponseDto.java b/src/main/java/page/clab/api/domain/donation/dto/response/DonationResponseDto.java index f953ee30d..6e871273d 100644 --- a/src/main/java/page/clab/api/domain/donation/dto/response/DonationResponseDto.java +++ b/src/main/java/page/clab/api/domain/donation/dto/response/DonationResponseDto.java @@ -12,9 +12,9 @@ public class DonationResponseDto { private Long id; - private String donorId; + private String memberId; - private String name; + private String memberName; private Double amount; @@ -22,11 +22,11 @@ public class DonationResponseDto { private LocalDateTime createdAt; - public static DonationResponseDto toDto(Donation donation) { + public static DonationResponseDto toDto(Donation donation, String memberName) { return DonationResponseDto.builder() .id(donation.getId()) - .donorId(donation.getDonor().getId()) - .name(donation.getDonor().getName()) + .memberId(donation.getMemberId()) + .memberName(memberName) .amount(donation.getAmount()) .message(donation.getMessage()) .createdAt(donation.getCreatedAt()) diff --git a/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java b/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java index be5b1c3c7..7eb443dc2 100644 --- a/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java +++ b/src/main/java/page/clab/api/domain/member/dto/shared/MemberDetailedInfoDto.java @@ -32,4 +32,8 @@ public boolean isAdminRole() { return roleLevel >= 2; } + public boolean isSuperAdminRole() { + return roleLevel == 3; + } + } From fc2414c10291a6b0292987835038323c7cb96a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 13:54:27 +0900 Subject: [PATCH 39/47] =?UTF-8?q?refactor(AccountLockInfo):=20Member=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20?= =?UTF-8?q?=EC=A7=81=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/AccountLockInfoService.java | 61 +++++++++++-------- .../login/dao/AccountLockInfoRepository.java | 3 +- .../domain/login/domain/AccountLockInfo.java | 13 ++-- .../response/AccountLockInfoResponseDto.java | 6 +- 4 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/main/java/page/clab/api/domain/login/application/AccountLockInfoService.java b/src/main/java/page/clab/api/domain/login/application/AccountLockInfoService.java index 49cdebda2..0a5a02cab 100644 --- a/src/main/java/page/clab/api/domain/login/application/AccountLockInfoService.java +++ b/src/main/java/page/clab/api/domain/login/application/AccountLockInfoService.java @@ -14,7 +14,7 @@ import page.clab.api.domain.login.exception.LoginFaliedException; import page.clab.api.domain.login.exception.MemberLockedException; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.global.common.dto.PagedResponseDto; import page.clab.api.global.common.slack.application.SlackService; import page.clab.api.global.common.slack.domain.SecurityAlertType; @@ -42,20 +42,20 @@ public class AccountLockInfoService { @Transactional public Long banMemberById(HttpServletRequest request, String memberId) { - Member member = memberLookupService.getMemberById(memberId); - AccountLockInfo accountLockInfo = ensureAccountLockInfo(member); + MemberBasicInfoDto memberInfo = memberLookupService.getMemberBasicInfoById(memberId); + AccountLockInfo accountLockInfo = ensureAccountLockInfo(memberInfo.getMemberId()); accountLockInfo.banPermanently(); redisTokenService.deleteRedisTokenByMemberId(memberId); - slackService.sendSecurityAlertNotification(request, SecurityAlertType.MEMBER_BANNED, "ID: " + member.getId() + ", Name: " + member.getName()); + sendSlackBanNotification(request, memberId); return accountLockInfoRepository.save(accountLockInfo).getId(); } @Transactional public Long unbanMemberById(HttpServletRequest request, String memberId) { - Member member = memberLookupService.getMemberById(memberId); - AccountLockInfo accountLockInfo = ensureAccountLockInfo(member); + MemberBasicInfoDto memberInfo = memberLookupService.getMemberBasicInfoById(memberId); + AccountLockInfo accountLockInfo = ensureAccountLockInfo(memberInfo.getMemberId()); accountLockInfo.unban(); - slackService.sendSecurityAlertNotification(request, SecurityAlertType.MEMBER_UNBANNED, "ID: " + member.getId() + ", Name: " + member.getName()); + sendSlackUnbanNotification(request, memberId); return accountLockInfoRepository.save(accountLockInfo).getId(); } @@ -63,12 +63,16 @@ public Long unbanMemberById(HttpServletRequest request, String memberId) { public PagedResponseDto<AccountLockInfoResponseDto> getBanMembers(Pageable pageable) { LocalDateTime banDate = LocalDateTime.of(9999, 12, 31, 23, 59); Page<AccountLockInfo> banMembers = accountLockInfoRepository.findByLockUntil(banDate, pageable); - return new PagedResponseDto<>(banMembers.map(AccountLockInfoResponseDto::toDto)); + return new PagedResponseDto<>(banMembers.map(accountLockInfo -> { + String memberName = memberLookupService.getMemberBasicInfoById(accountLockInfo.getMemberId()).getMemberName(); + return AccountLockInfoResponseDto.toDto(accountLockInfo, memberName); + })); } @Transactional public void handleAccountLockInfo(String memberId) throws MemberLockedException, LoginFaliedException { - AccountLockInfo accountLockInfo = ensureAccountLockInfoForMemberId(memberId); + ensureMemberExists(memberId); + AccountLockInfo accountLockInfo = ensureAccountLockInfo(memberId); validateAccountLockStatus(accountLockInfo); accountLockInfo.unlockAccount(); accountLockInfoRepository.save(accountLockInfo); @@ -76,34 +80,32 @@ public void handleAccountLockInfo(String memberId) throws MemberLockedException, @Transactional public void handleLoginFailure(HttpServletRequest request, String memberId) throws MemberLockedException, LoginFaliedException { - Member member = memberLookupService.getMemberById(memberId); - AccountLockInfo accountLockInfo = ensureAccountLockInfoForMemberId(memberId); + ensureMemberExists(memberId); + AccountLockInfo accountLockInfo = ensureAccountLockInfo(memberId); validateAccountLockStatus(accountLockInfo); accountLockInfo.incrementLoginFailCount(); if (accountLockInfo.shouldBeLocked(maxLoginFailures)) { accountLockInfo.lockAccount(lockDurationMinutes); - sendSlackMessage(request, member); + sendSlackLoginFailureNotification(request, memberId); } accountLockInfoRepository.save(accountLockInfo); } - public AccountLockInfo createAccountLockInfo(Member member) { - AccountLockInfo accountLockInfo = AccountLockInfo.create(member); + public AccountLockInfo createAccountLockInfo(String memberId) { + AccountLockInfo accountLockInfo = AccountLockInfo.create(memberId); accountLockInfoRepository.save(accountLockInfo); return accountLockInfo; } - private AccountLockInfo ensureAccountLockInfo(Member member) { - return accountLockInfoRepository.findByMember(member) - .orElseGet(() -> createAccountLockInfo(member)); + private AccountLockInfo ensureAccountLockInfo(String memberId) { + return accountLockInfoRepository.findByMemberId(memberId) + .orElseGet(() -> createAccountLockInfo(memberId)); } - private AccountLockInfo ensureAccountLockInfoForMemberId(String memberId) throws LoginFaliedException { - Member member = memberLookupService.getMemberById(memberId); - if (member == null) { + private void ensureMemberExists(String memberId) throws LoginFaliedException { + if (memberLookupService.getMemberById(memberId) == null) { throw new LoginFaliedException(); } - return ensureAccountLockInfo(member); } private void validateAccountLockStatus(AccountLockInfo accountLockInfo) throws MemberLockedException { @@ -112,9 +114,20 @@ private void validateAccountLockStatus(AccountLockInfo accountLockInfo) throws M } } - private void sendSlackMessage(HttpServletRequest request, Member member) { - if (member.isAdminRole()) { - request.setAttribute("member", member.getId() + " " + member.getName()); + private void sendSlackBanNotification(HttpServletRequest request, String memberId) { + String memberName = memberLookupService.getMemberBasicInfoById(memberId).getMemberName(); + slackService.sendSecurityAlertNotification(request, SecurityAlertType.MEMBER_BANNED, "ID: " + memberId + ", Name: " + memberName); + } + + private void sendSlackUnbanNotification(HttpServletRequest request, String memberId) { + String memberName = memberLookupService.getMemberBasicInfoById(memberId).getMemberName(); + slackService.sendSecurityAlertNotification(request, SecurityAlertType.MEMBER_UNBANNED, "ID: " + memberId + ", Name: " + memberName); + } + + private void sendSlackLoginFailureNotification(HttpServletRequest request, String memberId) { + String memberName = memberLookupService.getMemberBasicInfoById(memberId).getMemberName(); + if (memberLookupService.getMemberDetailedInfoById(memberId).isAdminRole()) { + request.setAttribute("member", memberId + " " + memberName); slackService.sendSecurityAlertNotification(request, SecurityAlertType.REPEATED_LOGIN_FAILURES, "로그인 실패 횟수 초과로 계정이 잠겼습니다."); } } diff --git a/src/main/java/page/clab/api/domain/login/dao/AccountLockInfoRepository.java b/src/main/java/page/clab/api/domain/login/dao/AccountLockInfoRepository.java index 4a03c6786..a56947d4a 100644 --- a/src/main/java/page/clab/api/domain/login/dao/AccountLockInfoRepository.java +++ b/src/main/java/page/clab/api/domain/login/dao/AccountLockInfoRepository.java @@ -5,7 +5,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import page.clab.api.domain.login.domain.AccountLockInfo; -import page.clab.api.domain.member.domain.Member; import java.time.LocalDateTime; import java.util.Optional; @@ -13,7 +12,7 @@ @Repository public interface AccountLockInfoRepository extends JpaRepository<AccountLockInfo, Long> { - Optional<AccountLockInfo> findByMember(Member member); + Optional<AccountLockInfo> findByMemberId(String memberId); Page<AccountLockInfo> findByLockUntil(LocalDateTime banDate, Pageable pageable); diff --git a/src/main/java/page/clab/api/domain/login/domain/AccountLockInfo.java b/src/main/java/page/clab/api/domain/login/domain/AccountLockInfo.java index 9ef54330a..aaf418aca 100644 --- a/src/main/java/page/clab/api/domain/login/domain/AccountLockInfo.java +++ b/src/main/java/page/clab/api/domain/login/domain/AccountLockInfo.java @@ -1,18 +1,16 @@ package page.clab.api.domain.login.domain; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.OneToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.domain.BaseEntity; import java.time.LocalDateTime; @@ -29,9 +27,8 @@ public class AccountLockInfo extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne - @JoinColumn(name = "member_id") - private Member member; + @Column(name = "member_id", nullable = false) + private String memberId; private Long loginFailCount; @@ -39,9 +36,9 @@ public class AccountLockInfo extends BaseEntity { private LocalDateTime lockUntil; - public static AccountLockInfo create(Member member) { + public static AccountLockInfo create(String memberId) { return AccountLockInfo.builder() - .member(member) + .memberId(memberId) .loginFailCount(0L) .isLock(false) .lockUntil(null) diff --git a/src/main/java/page/clab/api/domain/login/dto/response/AccountLockInfoResponseDto.java b/src/main/java/page/clab/api/domain/login/dto/response/AccountLockInfoResponseDto.java index e7fbf00fe..7b94a7d18 100644 --- a/src/main/java/page/clab/api/domain/login/dto/response/AccountLockInfoResponseDto.java +++ b/src/main/java/page/clab/api/domain/login/dto/response/AccountLockInfoResponseDto.java @@ -12,10 +12,10 @@ public class AccountLockInfoResponseDto { private String name; - public static AccountLockInfoResponseDto toDto(AccountLockInfo accountLockInfo) { + public static AccountLockInfoResponseDto toDto(AccountLockInfo accountLockInfo, String memberName) { return AccountLockInfoResponseDto.builder() - .id(accountLockInfo.getMember().getId()) - .name(accountLockInfo.getMember().getName()) + .id(accountLockInfo.getMemberId()) + .name(memberName) .build(); } From b35782abcbf9d03376f8fd7ce409221ec09bf206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 14:26:12 +0900 Subject: [PATCH 40/47] =?UTF-8?q?refactor(Login):=20Member=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/application/LoginService.java | 28 +++++++------- .../application/MemberLookupService.java | 5 +++ .../application/MemberLookupServiceImpl.java | 17 ++++++++- .../member/dto/shared/LoginMemberInfoDto.java | 37 +++++++++++++++++++ .../slack/application/SlackService.java | 4 +- .../slack/application/SlackServiceHelper.java | 10 ++--- 6 files changed, 78 insertions(+), 23 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/member/dto/shared/LoginMemberInfoDto.java diff --git a/src/main/java/page/clab/api/domain/login/application/LoginService.java b/src/main/java/page/clab/api/domain/login/application/LoginService.java index f9a243ef0..bc66213c7 100644 --- a/src/main/java/page/clab/api/domain/login/application/LoginService.java +++ b/src/main/java/page/clab/api/domain/login/application/LoginService.java @@ -21,7 +21,7 @@ import page.clab.api.domain.login.exception.LoginFaliedException; import page.clab.api.domain.login.exception.MemberLockedException; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.LoginMemberInfoDto; import page.clab.api.global.auth.exception.TokenForgeryException; import page.clab.api.global.auth.exception.TokenMisuseException; import page.clab.api.global.auth.jwt.JwtTokenProvider; @@ -57,15 +57,15 @@ public class LoginService { public LoginResult login(HttpServletRequest request, LoginRequestDto requestDto) throws LoginFaliedException, MemberLockedException { authenticateAndCheckStatus(request, requestDto); logLoginAttempt(request, requestDto.getId(), true); - Member loginMember = memberLookupService.getMemberByIdOrThrow(requestDto.getId()); - loginMember.updateLastLoginTime(); + LoginMemberInfoDto loginMember = memberLookupService.getLoginMemberInfoById(requestDto.getId()); + memberLookupService.updateLastLoginTime(requestDto.getId()); return generateLoginResult(loginMember); } @Transactional public LoginResult authenticator(HttpServletRequest request, TwoFactorAuthenticationRequestDto twoFactorAuthenticationRequestDto) throws LoginFaliedException, MemberLockedException { String memberId = twoFactorAuthenticationRequestDto.getMemberId(); - Member loginMember = memberLookupService.getMemberById(memberId); + LoginMemberInfoDto loginMember = memberLookupService.getLoginMemberInfoById(memberId); String totp = twoFactorAuthenticationRequestDto.getTotp(); accountLockInfoService.handleAccountLockInfo(memberId); @@ -82,9 +82,8 @@ public String resetAuthenticator(String memberId) { } public String revoke(String memberId) { - Member member = memberLookupService.getMemberById(memberId); redisTokenService.deleteRedisTokenByMemberId(memberId); - return member.getId(); + return memberId; } @Transactional @@ -123,10 +122,10 @@ private void logLoginAttempt(HttpServletRequest request, String memberId, boolea loginAttemptLogService.createLoginAttemptLog(request, memberId, result); } - private LoginResult generateLoginResult(Member loginMember) { - String memberId = loginMember.getId(); + private LoginResult generateLoginResult(LoginMemberInfoDto loginMember) { + String memberId = loginMember.getMemberId(); String header; - boolean isOtpEnabled = Optional.ofNullable(loginMember.getIsOtpEnabled()).orElse(false); + boolean isOtpEnabled = Optional.of(loginMember.isOtpEnabled()).orElse(false); if (isOtpEnabled || loginMember.isAdminRole()) { if (!authenticatorService.isAuthenticatorExist(memberId)) { String secretKey = authenticatorService.generateSecretKey(memberId); @@ -150,14 +149,14 @@ private void verifyTwoFactorAuthentication(String memberId, String totp, HttpSer loginAttemptLogService.createLoginAttemptLog(request, memberId, LoginAttemptResult.TOTP); } - private TokenInfo generateAndSaveToken(Member member) { - TokenInfo tokenInfo = jwtTokenProvider.generateToken(member.getId(), member.getRole()); + private TokenInfo generateAndSaveToken(LoginMemberInfoDto memberInfo) { + TokenInfo tokenInfo = jwtTokenProvider.generateToken(memberInfo.getMemberId(), memberInfo.getRole()); String clientIpAddress = HttpReqResUtil.getClientIpAddressIfServletRequestExist(); - redisTokenService.saveRedisToken(member.getId(), member.getRole(), tokenInfo, clientIpAddress); + redisTokenService.saveRedisToken(memberInfo.getMemberId(), memberInfo.getRole(), tokenInfo, clientIpAddress); return tokenInfo; } - private void sendAdminLoginNotification(HttpServletRequest request, Member loginMember) { + private void sendAdminLoginNotification(HttpServletRequest request, LoginMemberInfoDto loginMember) { if (loginMember.isSuperAdminRole()) { slackService.sendAdminLoginNotification(request, loginMember); } @@ -165,8 +164,7 @@ private void sendAdminLoginNotification(HttpServletRequest request, Member login private void validateMemberExistence(Authentication authentication) { String id = authentication.getName(); - Member member = memberLookupService.getMemberById(id); - if (member == null) { + if (memberLookupService.getMemberById(id) == null) { throw new TokenForgeryException("존재하지 않는 회원에 대한 토큰입니다."); } } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java index b02a343cf..11b09e06a 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -3,6 +3,7 @@ import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.response.MemberResponseDto; import page.clab.api.domain.member.dto.shared.BookBorrowerInfoDto; +import page.clab.api.domain.member.dto.shared.LoginMemberInfoDto; import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; @@ -39,6 +40,10 @@ public interface MemberLookupService { BookBorrowerInfoDto getCurrentMemberBorrowerInfo(); + LoginMemberInfoDto getLoginMemberInfoById(String memberId); + void updateLoanSuspensionDate(String memberId, LocalDateTime loanSuspensionDate); + void updateLastLoginTime(String id); + } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java index d83eb004a..a8431c998 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -6,6 +6,7 @@ import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.dto.response.MemberResponseDto; import page.clab.api.domain.member.dto.shared.BookBorrowerInfoDto; +import page.clab.api.domain.member.dto.shared.LoginMemberInfoDto; import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.global.auth.util.AuthUtil; @@ -117,10 +118,24 @@ public BookBorrowerInfoDto getCurrentMemberBorrowerInfo() { .orElseThrow(() -> new NotFoundException("[Member] id: " + currentMemberId + "에 해당하는 멤버가 존재하지 않습니다.")); } + @Override + public LoginMemberInfoDto getLoginMemberInfoById(String memberId) { + return memberRepository.findById(memberId) + .map(LoginMemberInfoDto::create) + .orElseThrow(() -> new NotFoundException("[Member] id: " + memberId + "에 해당하는 멤버가 존재하지 않습니다.")); + } + public void updateLoanSuspensionDate(String memberId, LocalDateTime loanSuspensionDate) { - Member member = getMemberById(memberId); + Member member = getMemberByIdOrThrow(memberId); member.updateLoanSuspensionDate(loanSuspensionDate); memberRepository.save(member); } + @Override + public void updateLastLoginTime(String id) { + Member member = getMemberByIdOrThrow(id); + member.updateLastLoginTime(); + memberRepository.save(member); + } + } diff --git a/src/main/java/page/clab/api/domain/member/dto/shared/LoginMemberInfoDto.java b/src/main/java/page/clab/api/domain/member/dto/shared/LoginMemberInfoDto.java new file mode 100644 index 000000000..0ab964849 --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/dto/shared/LoginMemberInfoDto.java @@ -0,0 +1,37 @@ +package page.clab.api.domain.member.dto.shared; + +import lombok.Builder; +import lombok.Getter; +import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.domain.Role; + +@Getter +@Builder +public class LoginMemberInfoDto { + + private String memberId; + + private String memberName; + + private Role role; + + private boolean isOtpEnabled; + + public static LoginMemberInfoDto create(Member member) { + return LoginMemberInfoDto.builder() + .memberId(member.getId()) + .memberName(member.getName()) + .role(member.getRole()) + .isOtpEnabled(member.getIsOtpEnabled()) + .build(); + } + + public boolean isAdminRole() { + return role.toRoleLevel() >= 2; + } + + public boolean isSuperAdminRole() { + return role.toRoleLevel() == 3; + } + +} diff --git a/src/main/java/page/clab/api/global/common/slack/application/SlackService.java b/src/main/java/page/clab/api/global/common/slack/application/SlackService.java index 5f2c1a966..f792c595d 100644 --- a/src/main/java/page/clab/api/global/common/slack/application/SlackService.java +++ b/src/main/java/page/clab/api/global/common/slack/application/SlackService.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Service; import page.clab.api.domain.application.dto.request.ApplicationRequestDto; import page.clab.api.domain.board.domain.SlackBoardInfo; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.LoginMemberInfoDto; import page.clab.api.global.common.slack.domain.GeneralAlertType; import page.clab.api.global.common.slack.domain.SecurityAlertType; import page.clab.api.global.common.slack.event.NotificationEvent; @@ -29,7 +29,7 @@ public void sendSecurityAlertNotification(HttpServletRequest request, SecurityAl eventPublisher.publishEvent(new NotificationEvent(this, alertType, request, additionalMessage)); } - public void sendAdminLoginNotification(HttpServletRequest request, Member loginMember) { + public void sendAdminLoginNotification(HttpServletRequest request, LoginMemberInfoDto loginMember) { eventPublisher.publishEvent(new NotificationEvent(this, GeneralAlertType.ADMIN_LOGIN, request, loginMember)); } diff --git a/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java b/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java index 67902c100..ebd6dc4cc 100644 --- a/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java +++ b/src/main/java/page/clab/api/global/common/slack/application/SlackServiceHelper.java @@ -22,7 +22,7 @@ import org.springframework.stereotype.Component; import page.clab.api.domain.application.dto.request.ApplicationRequestDto; import page.clab.api.domain.board.domain.SlackBoardInfo; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.LoginMemberInfoDto; import page.clab.api.global.common.slack.domain.AlertType; import page.clab.api.global.common.slack.domain.GeneralAlertType; import page.clab.api.global.common.slack.domain.SecurityAlertType; @@ -103,8 +103,8 @@ public List<LayoutBlock> createBlocks(AlertType alertType, HttpServletRequest re } else if (alertType instanceof GeneralAlertType) { switch ((GeneralAlertType) alertType) { case ADMIN_LOGIN: - if (additionalData instanceof Member) { - return createAdminLoginBlocks(request, (Member) additionalData); + if (additionalData instanceof LoginMemberInfoDto) { + return createAdminLoginBlocks(request, (LoginMemberInfoDto) additionalData); } break; case APPLICATION_CREATED: @@ -169,14 +169,14 @@ private List<LayoutBlock> createSecurityAlertBlocks(HttpServletRequest request, ); } - private List<LayoutBlock> createAdminLoginBlocks(HttpServletRequest request, Member loginMember) { + private List<LayoutBlock> createAdminLoginBlocks(HttpServletRequest request, LoginMemberInfoDto loginMember) { String clientIpAddress = HttpReqResUtil.getClientIpAddressIfServletRequestExist(); String location = getLocation(request); return Arrays.asList( section(section -> section.text(markdownText(String.format(":mechanic: *%s Login*", loginMember.getRole().getDescription())))), section(section -> section.fields(Arrays.asList( - markdownText("*User:*\n" + loginMember.getId() + " " + loginMember.getName()), + markdownText("*User:*\n" + loginMember.getMemberId() + " " + loginMember.getMemberName()), markdownText("*IP Address:*\n" + clientIpAddress), markdownText("*Location:*\n" + location) ))) From ce7fa67e4c956b3e7f89cb28162666dfe744dc76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 14:59:12 +0900 Subject: [PATCH 41/47] =?UTF-8?q?refactor(Event):=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../blog/application/BlogEventProcessor.java | 40 ------------------- .../book/application/BookEventProcessor.java | 34 ---------------- .../application/CommentEventProcessor.java | 34 ---------------- .../application/DonationEventProcessor.java | 34 ---------------- 4 files changed, 142 deletions(-) delete mode 100644 src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java delete mode 100644 src/main/java/page/clab/api/domain/book/application/BookEventProcessor.java delete mode 100644 src/main/java/page/clab/api/domain/comment/application/CommentEventProcessor.java delete mode 100644 src/main/java/page/clab/api/domain/donation/application/DonationEventProcessor.java diff --git a/src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java b/src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java deleted file mode 100644 index bd1a1d131..000000000 --- a/src/main/java/page/clab/api/domain/blog/application/BlogEventProcessor.java +++ /dev/null @@ -1,40 +0,0 @@ -package page.clab.api.domain.blog.application; - -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.blog.dao.BlogRepository; -import page.clab.api.domain.blog.domain.Blog; -import page.clab.api.domain.member.domain.Member; -import page.clab.api.domain.member.event.MemberEventProcessor; -import page.clab.api.domain.member.event.MemberEventProcessorRegistry; - -import java.util.List; - -@Component -@RequiredArgsConstructor -public class BlogEventProcessor implements MemberEventProcessor { - - private final BlogRepository blogRepository; - - private final MemberEventProcessorRegistry processorRegistry; - - @PostConstruct - public void init() { - processorRegistry.registerProcessor(this); - } - - @Override - @Transactional - public void processMemberDeleted(Member member) { - List<Blog> blogs = blogRepository.findByMemberId(member.getId()); - blogs.forEach(Blog::delete); - blogRepository.saveAll(blogs); - } - - @Override - public void processMemberUpdated(Member member) { - // do nothing - } -} diff --git a/src/main/java/page/clab/api/domain/book/application/BookEventProcessor.java b/src/main/java/page/clab/api/domain/book/application/BookEventProcessor.java deleted file mode 100644 index 45af568a8..000000000 --- a/src/main/java/page/clab/api/domain/book/application/BookEventProcessor.java +++ /dev/null @@ -1,34 +0,0 @@ -package page.clab.api.domain.book.application; - -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.domain.Member; -import page.clab.api.domain.member.event.MemberEventProcessor; -import page.clab.api.domain.member.event.MemberEventProcessorRegistry; - -@Component -@RequiredArgsConstructor -public class BookEventProcessor implements MemberEventProcessor { - - private final MemberEventProcessorRegistry processorRegistry; - - @PostConstruct - public void init() { - processorRegistry.registerProcessor(this); - } - - @Override - @Transactional - public void processMemberDeleted(Member member) { - // do nothing - } - - @Override - @Transactional - public void processMemberUpdated(Member member) { - // do nothing - } - -} diff --git a/src/main/java/page/clab/api/domain/comment/application/CommentEventProcessor.java b/src/main/java/page/clab/api/domain/comment/application/CommentEventProcessor.java deleted file mode 100644 index 5f0bfcac7..000000000 --- a/src/main/java/page/clab/api/domain/comment/application/CommentEventProcessor.java +++ /dev/null @@ -1,34 +0,0 @@ -package page.clab.api.domain.comment.application; - -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.domain.Member; -import page.clab.api.domain.member.event.MemberEventProcessor; -import page.clab.api.domain.member.event.MemberEventProcessorRegistry; - -@Component -@RequiredArgsConstructor -public class CommentEventProcessor implements MemberEventProcessor { - - private final MemberEventProcessorRegistry processorRegistry; - - @PostConstruct - public void init() { - processorRegistry.registerProcessor(this); - } - - @Override - @Transactional - public void processMemberDeleted(Member member) { - // do nothing - } - - @Override - @Transactional - public void processMemberUpdated(Member member) { - // do nothing - } - -} diff --git a/src/main/java/page/clab/api/domain/donation/application/DonationEventProcessor.java b/src/main/java/page/clab/api/domain/donation/application/DonationEventProcessor.java deleted file mode 100644 index d2cff3110..000000000 --- a/src/main/java/page/clab/api/domain/donation/application/DonationEventProcessor.java +++ /dev/null @@ -1,34 +0,0 @@ -package page.clab.api.domain.donation.application; - -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.domain.Member; -import page.clab.api.domain.member.event.MemberEventProcessor; -import page.clab.api.domain.member.event.MemberEventProcessorRegistry; - -@Component -@RequiredArgsConstructor -public class DonationEventProcessor implements MemberEventProcessor { - - private final MemberEventProcessorRegistry processorRegistry; - - @PostConstruct - public void init() { - processorRegistry.registerProcessor(this); - } - - @Override - @Transactional - public void processMemberDeleted(Member member) { - // do nothing - } - - @Override - @Transactional - public void processMemberUpdated(Member member) { - // do nothing - } - -} From 0fa465f8d8fb0411d156457b132c74ec827a6edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 15:01:16 +0900 Subject: [PATCH 42/47] =?UTF-8?q?refactor(MembershipFee):=20Member=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20?= =?UTF-8?q?=EC=A7=81=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/MembershipFeeService.java | 33 +++++++++++-------- .../dao/MembershipFeeRepositoryImpl.java | 22 ++++++------- .../membershipFee/domain/MembershipFee.java | 21 ++++++------ .../dto/request/MembershipFeeRequestDto.java | 5 ++- .../response/MembershipFeeResponseDto.java | 8 ++--- 5 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/main/java/page/clab/api/domain/membershipFee/application/MembershipFeeService.java b/src/main/java/page/clab/api/domain/membershipFee/application/MembershipFeeService.java index 50466da4c..cb9afee66 100644 --- a/src/main/java/page/clab/api/domain/membershipFee/application/MembershipFeeService.java +++ b/src/main/java/page/clab/api/domain/membershipFee/application/MembershipFeeService.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.domain.membershipFee.dao.MembershipFeeRepository; import page.clab.api.domain.membershipFee.domain.MembershipFee; import page.clab.api.domain.membershipFee.domain.MembershipFeeStatus; @@ -33,8 +33,8 @@ public class MembershipFeeService { @Transactional public Long createMembershipFee(MembershipFeeRequestDto requestDto) { - Member currentMember = memberLookupService.getCurrentMember(); - MembershipFee membershipFee = MembershipFeeRequestDto.toEntity(requestDto, currentMember); + String currentMemberId = memberLookupService.getCurrentMemberId(); + MembershipFee membershipFee = MembershipFeeRequestDto.toEntity(requestDto, currentMemberId); validationService.checkValid(membershipFee); notificationService.sendNotificationToAdmins("새로운 회비 내역이 등록되었습니다."); return membershipFeeRepository.save(membershipFee).getId(); @@ -42,35 +42,40 @@ public Long createMembershipFee(MembershipFeeRequestDto requestDto) { @Transactional(readOnly = true) public PagedResponseDto<MembershipFeeResponseDto> getMembershipFeesByConditions(String memberId, String memberName, String category, MembershipFeeStatus status, Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); - boolean isAdminOrSuper = currentMember.isAdminRole(); + boolean isAdminRole = memberLookupService.getCurrentMemberDetailedInfo().isAdminRole(); Page<MembershipFee> membershipFeesPage = membershipFeeRepository.findByConditions(memberId, memberName, category, status, pageable); - return new PagedResponseDto<>(membershipFeesPage.map(membershipFee -> MembershipFeeResponseDto.toDto(membershipFee, isAdminOrSuper))); + return new PagedResponseDto<>(membershipFeesPage.map(membershipFee -> { + String applicantName = memberLookupService.getMemberBasicInfoById(membershipFee.getMemberId()).getMemberName(); + return MembershipFeeResponseDto.toDto(membershipFee, applicantName, isAdminRole); + })); } @Transactional(readOnly = true) public PagedResponseDto<MembershipFeeResponseDto> getDeletedMembershipFees(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); - boolean isAdminOrSuper = currentMember.isAdminRole(); + boolean isAdminRole = memberLookupService.getCurrentMemberDetailedInfo().isAdminRole(); Page<MembershipFee> membershipFees = membershipFeeRepository.findAllByIsDeletedTrue(pageable); - return new PagedResponseDto<>(membershipFees.map(membershipFee -> MembershipFeeResponseDto.toDto(membershipFee, isAdminOrSuper))); + return new PagedResponseDto<>(membershipFees.map(membershipFee -> { + String applicantName = memberLookupService.getMemberBasicInfoById(membershipFee.getMemberId()).getMemberName(); + return MembershipFeeResponseDto.toDto(membershipFee, applicantName, isAdminRole); + })); } @Transactional public Long updateMembershipFee(Long membershipFeeId, MembershipFeeUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); MembershipFee membershipFee = getMembershipFeeByIdOrThrow(membershipFeeId); - membershipFee.validateAccessPermission(currentMember); + membershipFee.validateAccessPermission(currentMemberInfo); membershipFee.update(requestDto); validationService.checkValid(membershipFee); return membershipFeeRepository.save(membershipFee).getId(); } public Long deleteMembershipFee(Long membershipFeeId) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); MembershipFee membershipFee = getMembershipFeeByIdOrThrow(membershipFeeId); - membershipFee.validateAccessPermission(currentMember); - membershipFeeRepository.delete(membershipFee); + membershipFee.validateAccessPermission(currentMemberInfo); + membershipFee.delete(); + membershipFeeRepository.save(membershipFee); return membershipFee.getId(); } diff --git a/src/main/java/page/clab/api/domain/membershipFee/dao/MembershipFeeRepositoryImpl.java b/src/main/java/page/clab/api/domain/membershipFee/dao/MembershipFeeRepositoryImpl.java index df59dc1ce..430717414 100644 --- a/src/main/java/page/clab/api/domain/membershipFee/dao/MembershipFeeRepositoryImpl.java +++ b/src/main/java/page/clab/api/domain/membershipFee/dao/MembershipFeeRepositoryImpl.java @@ -23,25 +23,25 @@ public class MembershipFeeRepositoryImpl implements MembershipFeeRepositoryCusto @Override public Page<MembershipFee> findByConditions(String memberId, String memberName, String category, MembershipFeeStatus status, Pageable pageable) { - QMembershipFee qMembershipFee = QMembershipFee.membershipFee; - QMember qMember = QMember.member; + QMembershipFee membershipFee = QMembershipFee.membershipFee; + QMember member = QMember.member; BooleanBuilder builder = new BooleanBuilder(); - if (memberId != null && !memberId.isEmpty()) builder.and(qMembershipFee.applicant.id.eq(memberId)); - if (memberName != null && !memberName.isEmpty()) builder.and(qMember.name.eq(memberName)); - if (category != null && !category.isEmpty()) builder.and(qMembershipFee.category.eq(category)); - if (status != null) builder.and(qMembershipFee.status.eq(status)); + if (memberId != null && !memberId.isEmpty()) builder.and(membershipFee.memberId.eq(memberId)); + if (memberName != null && !memberName.isEmpty()) builder.and(member.name.eq(memberName)); + if (category != null && !category.isEmpty()) builder.and(membershipFee.category.eq(category)); + if (status != null) builder.and(membershipFee.status.eq(status)); - List<MembershipFee> membershipFees = queryFactory.selectFrom(qMembershipFee) - .leftJoin(qMembershipFee.applicant, qMember) + List<MembershipFee> membershipFees = queryFactory.selectFrom(membershipFee) + .leftJoin(member).on(membershipFee.memberId.eq(member.id)) .where(builder) - .orderBy(OrderSpecifierUtil.getOrderSpecifiers(pageable, qMembershipFee)) + .orderBy(OrderSpecifierUtil.getOrderSpecifiers(pageable, membershipFee)) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) .fetch(); - long count = queryFactory.selectFrom(qMembershipFee) - .leftJoin(qMembershipFee.applicant, qMember) + long count = queryFactory.selectFrom(membershipFee) + .leftJoin(member).on(membershipFee.memberId.eq(member.id)) .where(builder) .fetchCount(); diff --git a/src/main/java/page/clab/api/domain/membershipFee/domain/MembershipFee.java b/src/main/java/page/clab/api/domain/membershipFee/domain/MembershipFee.java index da52ea1d1..61a5f7e17 100644 --- a/src/main/java/page/clab/api/domain/membershipFee/domain/MembershipFee.java +++ b/src/main/java/page/clab/api/domain/membershipFee/domain/MembershipFee.java @@ -7,8 +7,6 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; import jakarta.validation.constraints.Size; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -18,7 +16,7 @@ import lombok.Setter; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.domain.membershipFee.dto.request.MembershipFeeUpdateRequestDto; import page.clab.api.global.common.domain.BaseEntity; import page.clab.api.global.exception.PermissionDeniedException; @@ -39,9 +37,8 @@ public class MembershipFee extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - @JoinColumn(name = "member_id") - private Member applicant; + @Column(name = "member_id", nullable = false) + private String memberId; @Column(nullable = false) @Size(min = 1, message = "{size.membershipFee.category}") @@ -71,12 +68,16 @@ public void update(MembershipFeeUpdateRequestDto membershipFeeUpdateRequestDto) Optional.ofNullable(membershipFeeUpdateRequestDto.getStatus()).ifPresent(this::setStatus); } - public boolean isOwner(Member member) { - return this.applicant.isSameMember(member); + public void delete() { + this.isDeleted = true; } - public void validateAccessPermission(Member member) throws PermissionDeniedException { - if (!isOwner(member) && !member.isAdminRole()) { + public boolean isOwner(String memberId) { + return this.memberId.equals(memberId); + } + + public void validateAccessPermission(MemberDetailedInfoDto memberInfo) throws PermissionDeniedException { + if (!isOwner(memberInfo.getMemberId()) && !memberInfo.isAdminRole()) { throw new PermissionDeniedException("해당 회비를 수정/삭제할 권한이 없습니다."); } } diff --git a/src/main/java/page/clab/api/domain/membershipFee/dto/request/MembershipFeeRequestDto.java b/src/main/java/page/clab/api/domain/membershipFee/dto/request/MembershipFeeRequestDto.java index f073d7e10..cdceaa408 100644 --- a/src/main/java/page/clab/api/domain/membershipFee/dto/request/MembershipFeeRequestDto.java +++ b/src/main/java/page/clab/api/domain/membershipFee/dto/request/MembershipFeeRequestDto.java @@ -4,7 +4,6 @@ import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.membershipFee.domain.MembershipFee; import page.clab.api.domain.membershipFee.domain.MembershipFeeStatus; @@ -30,9 +29,9 @@ public class MembershipFeeRequestDto { @Schema(description = "증빙 사진", example = "https://images.chosun.com/resizer/mcbrEkwTr5YKQZ89QPO9hmdb0iE=/616x0/smart/cloudfront-ap-northeast-1.images.arcpublishing.com/chosun/LPCZYYKZ4FFIJPDD344FSGCLCY.jpg") private String imageUrl; - public static MembershipFee toEntity(MembershipFeeRequestDto requestDto, Member member) { + public static MembershipFee toEntity(MembershipFeeRequestDto requestDto, String memberId) { return MembershipFee.builder() - .applicant(member) + .memberId(memberId) .category(requestDto.getCategory()) .account(requestDto.getAccount()) .amount(requestDto.getAmount()) diff --git a/src/main/java/page/clab/api/domain/membershipFee/dto/response/MembershipFeeResponseDto.java b/src/main/java/page/clab/api/domain/membershipFee/dto/response/MembershipFeeResponseDto.java index 1ec870dd2..05b375bd8 100644 --- a/src/main/java/page/clab/api/domain/membershipFee/dto/response/MembershipFeeResponseDto.java +++ b/src/main/java/page/clab/api/domain/membershipFee/dto/response/MembershipFeeResponseDto.java @@ -31,13 +31,13 @@ public class MembershipFeeResponseDto { private LocalDateTime createdAt; - public static MembershipFeeResponseDto toDto(MembershipFee membershipFee, boolean isAdminOrSuper) { + public static MembershipFeeResponseDto toDto(MembershipFee membershipFee, String memberName, boolean isAdminRole) { return MembershipFeeResponseDto.builder() .id(membershipFee.getId()) - .memberId(membershipFee.getApplicant().getId()) - .memberName(membershipFee.getApplicant().getName()) + .memberId(membershipFee.getMemberId()) + .memberName(memberName) .category(membershipFee.getCategory()) - .account(isAdminOrSuper ? membershipFee.getAccount() : null) + .account(isAdminRole ? membershipFee.getAccount() : null) .amount(membershipFee.getAmount()) .content(membershipFee.getContent()) .imageUrl(membershipFee.getImageUrl()) From 63a0448cf4ece6d89a103cd36fb26f0860a54278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 15:31:15 +0900 Subject: [PATCH 43/47] =?UTF-8?q?refactor(Notification):=20Member=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20?= =?UTF-8?q?=EC=A7=81=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ActivityGroupAdminService.java | 8 ++-- .../ActivityGroupBoardService.java | 4 +- .../ActivityGroupMemberService.java | 2 +- .../application/MemberLookupService.java | 6 ++- .../application/MemberLookupServiceImpl.java | 13 +++++- .../NotificationEventProcessor.java | 41 ++++++++++++++++++ .../application/NotificationService.java | 42 ++++++++----------- .../dao/NotificationRepository.java | 7 +++- .../notification/domain/Notification.java | 26 ++++++------ .../dto/request/NotificationRequestDto.java | 5 +-- 10 files changed, 101 insertions(+), 53 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java diff --git a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupAdminService.java b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupAdminService.java index 6a9182b35..3b891a165 100644 --- a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupAdminService.java +++ b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupAdminService.java @@ -62,7 +62,7 @@ public Long createActivityGroup(ActivityGroupRequestDto requestDto) { validationService.checkValid(groupLeader); activityGroupMemberService.save(groupLeader); - notificationService.sendNotificationToMember(currentMember, "활동 그룹 생성이 완료되었습니다. 활동 승인이 완료되면 활동 그룹을 이용할 수 있습니다."); + notificationService.sendNotificationToMember(currentMember.getId(), "활동 그룹 생성이 완료되었습니다. 활동 승인이 완료되면 활동 그룹을 이용할 수 있습니다."); return activityGroup.getId(); } @@ -87,7 +87,7 @@ public Long manageActivityGroup(Long activityGroupId, ActivityGroupStatus status GroupMember groupLeader = activityGroupMemberService.getGroupMemberByActivityGroupIdAndRole(activityGroupId, ActivityGroupRole.LEADER); if (groupLeader != null) { - notificationService.sendNotificationToMember(groupLeader.getMember(), "활동 그룹이 [" + status.getDescription() + "] 상태로 변경되었습니다."); + notificationService.sendNotificationToMember(groupLeader.getMember().getId(), "활동 그룹이 [" + status.getDescription() + "] 상태로 변경되었습니다."); } return activityGroup.getId(); } @@ -110,7 +110,7 @@ public Long deleteActivityGroup(Long activityGroupId) { activityGroupRepository.delete(activityGroup); if (groupLeader != null) { - notificationService.sendNotificationToMember(groupLeader.getMember(), "활동 그룹 [" + activityGroup.getName() + "]이 삭제되었습니다."); + notificationService.sendNotificationToMember(groupLeader.getMember().getId(), "활동 그룹 [" + activityGroup.getName() + "]이 삭제되었습니다."); } return activityGroup.getId(); } @@ -180,7 +180,7 @@ public String manageGroupMemberStatus(Long activityGroupId, String memberId, Gro groupMember.updateStatus(status); activityGroupMemberService.save(groupMember); - notificationService.sendNotificationToMember(member, "활동 그룹 신청이 [" + status.getDescription() + "] 상태로 변경되었습니다."); + notificationService.sendNotificationToMember(member.getId(), "활동 그룹 신청이 [" + status.getDescription() + "] 상태로 변경되었습니다."); return groupMember.getMember().getId(); } diff --git a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupBoardService.java b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupBoardService.java index e855dfcd9..433375682 100644 --- a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupBoardService.java +++ b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupBoardService.java @@ -203,13 +203,13 @@ private void notifyMembersAboutNewBoard(Long activityGroupId, ActivityGroup acti groupMembers .forEach(gMember -> { if (!gMember.isOwner(member)) { - notificationService.sendNotificationToMember(gMember.getMember(), "[" + activityGroup.getName() + "] " + member.getName() + "님이 새 게시글을 등록하였습니다."); + notificationService.sendNotificationToMember(gMember.getMember().getId(), "[" + activityGroup.getName() + "] " + member.getName() + "님이 새 게시글을 등록하였습니다."); } }); } else { GroupMember groupLeader = activityGroupMemberService.getGroupMemberByActivityGroupIdAndRole(activityGroupId, ActivityGroupRole.LEADER); if (groupLeader != null) { - notificationService.sendNotificationToMember(groupLeader.getMember(), "[" + activityGroup.getName() + "] " + member.getName() + "님이 새 게시글을 등록하였습니다."); + notificationService.sendNotificationToMember(groupLeader.getMember().getId(), "[" + activityGroup.getName() + "] " + member.getName() + "님이 새 게시글을 등록하였습니다."); } } } diff --git a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupMemberService.java b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupMemberService.java index 1a29b50c0..300b02596 100644 --- a/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupMemberService.java +++ b/src/main/java/page/clab/api/domain/activityGroup/application/ActivityGroupMemberService.java @@ -149,7 +149,7 @@ public Long applyActivityGroup(Long activityGroupId, ApplyFormRequestDto formReq GroupMember groupLeader = getGroupMemberByActivityGroupIdAndRole(activityGroup.getId(), ActivityGroupRole.LEADER); if (groupLeader != null) { - notificationService.sendNotificationToMember(groupLeader.getMember(), "[" + activityGroup.getName() + "] " + currentMember.getName() + "님이 활동 참가 신청을 하였습니다."); + notificationService.sendNotificationToMember(groupLeader.getMember().getId(), "[" + activityGroup.getName() + "] " + currentMember.getName() + "님이 활동 참가 신청을 하였습니다."); } return activityGroup.getId(); } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java index 11b09e06a..3aad095f3 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -12,6 +12,8 @@ public interface MemberLookupService { + void ensureMemberExists(String memberId); + Member getMemberById(String memberId); Member getMemberByIdOrThrow(String memberId); @@ -26,9 +28,9 @@ public interface MemberLookupService { List<Member> findAllMembers(); - List<Member> getAdmins(); + List<String> getAdminIds(); - List<Member> getSuperAdmins(); + List<String> getSuperAdminIds(); MemberBasicInfoDto getMemberBasicInfoById(String memberId); diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java index a8431c998..3274b0864 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -21,6 +21,13 @@ public class MemberLookupServiceImpl implements MemberLookupService { private final MemberRepository memberRepository; + @Override + public void ensureMemberExists(String memberId) { + if (!memberRepository.existsById(memberId)) { + throw new NotFoundException("[Member] id: " + memberId + "에 해당하는 멤버가 존재하지 않습니다."); + } + } + @Override public Member getMemberById(String memberId) { return memberRepository.findById(memberId) @@ -65,18 +72,20 @@ public List<Member> findAllMembers() { } @Override - public List<Member> getAdmins() { + public List<String> getAdminIds() { return memberRepository.findAll() .stream() .filter(Member::isAdminRole) + .map(Member::getId) .toList(); } @Override - public List<Member> getSuperAdmins() { + public List<String> getSuperAdminIds() { return memberRepository.findAll() .stream() .filter(Member::isSuperAdminRole) + .map(Member::getId) .toList(); } diff --git a/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java b/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java new file mode 100644 index 000000000..c2e28269f --- /dev/null +++ b/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java @@ -0,0 +1,41 @@ +package page.clab.api.domain.notification.application; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.event.MemberEventProcessor; +import page.clab.api.domain.member.event.MemberEventProcessorRegistry; +import page.clab.api.domain.notification.dao.NotificationRepository; +import page.clab.api.domain.notification.domain.Notification; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class NotificationEventProcessor implements MemberEventProcessor { + + private final NotificationRepository notificationRepository; + + private final MemberEventProcessorRegistry processorRegistry; + + @PostConstruct + public void init() { + processorRegistry.registerProcessor(this); + } + + @Override + @Transactional + public void processMemberDeleted(Member member) { + List<Notification> notifications = notificationRepository.findByMemberId(member.getId()); + notifications.forEach(Notification::delete); + notificationRepository.saveAll(notifications); + } + + @Override + public void processMemberUpdated(Member member) { + // do nothing + } + +} diff --git a/src/main/java/page/clab/api/domain/notification/application/NotificationService.java b/src/main/java/page/clab/api/domain/notification/application/NotificationService.java index ffbed68f6..abc8c9981 100644 --- a/src/main/java/page/clab/api/domain/notification/application/NotificationService.java +++ b/src/main/java/page/clab/api/domain/notification/application/NotificationService.java @@ -6,7 +6,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.dao.NotificationRepository; import page.clab.api.domain.notification.domain.Notification; import page.clab.api.domain.notification.dto.request.NotificationRequestDto; @@ -31,16 +30,16 @@ public class NotificationService { @Transactional public Long createNotification(NotificationRequestDto requestDto) { - Member member = memberLookupService.getMemberByIdOrThrow(requestDto.getMemberId()); - Notification notification = NotificationRequestDto.toEntity(requestDto, member); + memberLookupService.ensureMemberExists(requestDto.getMemberId()); + Notification notification = NotificationRequestDto.toEntity(requestDto); validationService.checkValid(notification); return notificationRepository.save(notification).getId(); } @Transactional(readOnly = true) public PagedResponseDto<NotificationResponseDto> getNotifications(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); - Page<Notification> notifications = getNotificationByMember(currentMember, pageable); + String currentMemberId = memberLookupService.getCurrentMemberId(); + Page<Notification> notifications = getNotificationByMemberId(currentMemberId, pageable); return new PagedResponseDto<>(notifications.map(NotificationResponseDto::toDto)); } @@ -50,51 +49,46 @@ public PagedResponseDto<NotificationResponseDto> getDeletedNotifications(Pageabl return new PagedResponseDto<>(notifications.map(NotificationResponseDto::toDto)); } + @Transactional public Long deleteNotification(Long notificationId) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + String currentMemberId = memberLookupService.getCurrentMemberId(); Notification notification = getNotificationByIdOrThrow(notificationId); - notification.validateAccessPermission(currentMember); + notification.validateAccessPermission(currentMemberId); notificationRepository.delete(notification); return notification.getId(); } public void sendNotificationToAllMembers(String content) { List<Notification> notifications = memberLookupService.findAllMembers().stream() - .map(member -> Notification.create(member, content)) + .map(member -> Notification.create(member.getId(), content)) .toList(); notificationRepository.saveAll(notifications); } - public void sendNotificationToMember(Member member, String content) { - Notification notification = Notification.create(member, content); + public void sendNotificationToMember(String memberId, String content) { + memberLookupService.ensureMemberExists(memberId); + Notification notification = Notification.create(memberId, content); notificationRepository.save(notification); } public void sendNotificationToMembers(List<String> memberIds, String content) { List<Notification> notifications = memberIds.stream() - .map(memberLookupService::getMemberByIdOrThrow) - .map(member -> Notification.create(member, content)) + .map(memberId -> Notification.create(memberId, content)) .toList(); notificationRepository.saveAll(notifications); } - public void sendNotificationToMember(String memberId, String content) { - Member member = memberLookupService.getMemberByIdOrThrow(memberId); - Notification notification = Notification.create(member, content); - notificationRepository.save(notification); - } - public void sendNotificationToAdmins(String content) { - sendNotificationToSpecificRole(memberLookupService::getAdmins, content); + sendNotificationToSpecificRole(memberLookupService::getAdminIds, content); } public void sendNotificationToSuperAdmins(String content) { - sendNotificationToSpecificRole(memberLookupService::getSuperAdmins, content); + sendNotificationToSpecificRole(memberLookupService::getSuperAdminIds, content); } - private void sendNotificationToSpecificRole(Supplier<List<Member>> memberSupplier, String content) { + private void sendNotificationToSpecificRole(Supplier<List<String>> memberSupplier, String content) { List<Notification> notifications = memberSupplier.get().stream() - .map(member -> Notification.create(member, content)) + .map(memberId -> Notification.create(memberId, content)) .toList(); notificationRepository.saveAll(notifications); } @@ -104,8 +98,8 @@ private Notification getNotificationByIdOrThrow(Long notificationId) { .orElseThrow(() -> new NotFoundException("존재하지 않는 알림입니다.")); } - private Page<Notification> getNotificationByMember(Member member, Pageable pageable) { - return notificationRepository.findByMember(member, pageable); + private Page<Notification> getNotificationByMemberId(String memberId, Pageable pageable) { + return notificationRepository.findByMemberId(memberId, pageable); } } diff --git a/src/main/java/page/clab/api/domain/notification/dao/NotificationRepository.java b/src/main/java/page/clab/api/domain/notification/dao/NotificationRepository.java index b4769b491..d6e05e87d 100644 --- a/src/main/java/page/clab/api/domain/notification/dao/NotificationRepository.java +++ b/src/main/java/page/clab/api/domain/notification/dao/NotificationRepository.java @@ -4,12 +4,15 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.domain.Notification; +import java.util.List; + public interface NotificationRepository extends JpaRepository<Notification, Long> { - Page<Notification> findByMember(Member member, Pageable pageable); + Page<Notification> findByMemberId(String memberId, Pageable pageable); + + List<Notification> findByMemberId(String memberId); @Query(value = "SELECT n.* FROM notification n WHERE n.is_deleted = true", nativeQuery = true) Page<Notification> findAllByIsDeletedTrue(Pageable pageable); diff --git a/src/main/java/page/clab/api/domain/notification/domain/Notification.java b/src/main/java/page/clab/api/domain/notification/domain/Notification.java index 9892018e3..058b4e865 100644 --- a/src/main/java/page/clab/api/domain/notification/domain/Notification.java +++ b/src/main/java/page/clab/api/domain/notification/domain/Notification.java @@ -5,8 +5,6 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; import jakarta.validation.constraints.Size; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -16,7 +14,6 @@ import lombok.Setter; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; -import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.domain.BaseEntity; import page.clab.api.global.exception.PermissionDeniedException; @@ -34,27 +31,30 @@ public class Notification extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "member_id", nullable = false) + private String memberId; + @Column(nullable = false) @Size(min = 1, max = 1000, message = "{size.notification.content}") private String content; - @ManyToOne() - @JoinColumn(name = "member_id") - private Member member; - - public static Notification create(Member member, String content) { + public static Notification create(String memberId, String content) { return Notification.builder() + .memberId(memberId) .content(content) - .member(member) .build(); } - public boolean isOwner(Member member) { - return this.member.isSameMember(member); + public void delete() { + this.isDeleted = true; + } + + public boolean isOwner(String memberId) { + return this.memberId.equals(memberId); } - public void validateAccessPermission(Member member) throws PermissionDeniedException { - if (!isOwner(member)) { + public void validateAccessPermission(String memberId) throws PermissionDeniedException { + if (!isOwner(memberId)) { throw new PermissionDeniedException("해당 알림을 수정/삭제할 권한이 없습니다."); } } diff --git a/src/main/java/page/clab/api/domain/notification/dto/request/NotificationRequestDto.java b/src/main/java/page/clab/api/domain/notification/dto/request/NotificationRequestDto.java index 6c45b03f8..63746229d 100644 --- a/src/main/java/page/clab/api/domain/notification/dto/request/NotificationRequestDto.java +++ b/src/main/java/page/clab/api/domain/notification/dto/request/NotificationRequestDto.java @@ -4,7 +4,6 @@ import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.notification.domain.Notification; @Getter @@ -19,10 +18,10 @@ public class NotificationRequestDto { @Schema(description = "내용", example = "알림 내용", required = true) private String content; - public static Notification toEntity(NotificationRequestDto requestDto, Member member) { + public static Notification toEntity(NotificationRequestDto requestDto) { return Notification.builder() .content(requestDto.getContent()) - .member(member) + .memberId(requestDto.getMemberId()) .build(); } From 2b4dee1ae613ce89f37a4dcbe9b74082092d3b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 15:54:07 +0900 Subject: [PATCH 44/47] =?UTF-8?q?refactor(Position):=20Member=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/MemberLookupService.java | 3 ++ .../application/MemberLookupServiceImpl.java | 9 ++++ .../member/application/MemberService.java | 4 +- .../dto/shared/MemberPositionInfoDto.java | 34 +++++++++++++++ .../application/PositionEventProcessor.java | 41 +++++++++++++++++++ .../position/application/PositionService.java | 27 ++++++------ .../position/dao/PositionRepository.java | 7 ++-- .../api/domain/position/domain/Position.java | 16 ++++---- .../dto/request/PositionRequestDto.java | 3 +- .../dto/response/PositionMyResponseDto.java | 15 ++++--- .../dto/response/PositionResponseDto.java | 15 ++++--- 11 files changed, 131 insertions(+), 43 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/member/dto/shared/MemberPositionInfoDto.java create mode 100644 src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java index 3aad095f3..85bf69667 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupService.java @@ -6,6 +6,7 @@ import page.clab.api.domain.member.dto.shared.LoginMemberInfoDto; import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; +import page.clab.api.domain.member.dto.shared.MemberPositionInfoDto; import java.time.LocalDateTime; import java.util.List; @@ -44,6 +45,8 @@ public interface MemberLookupService { LoginMemberInfoDto getLoginMemberInfoById(String memberId); + MemberPositionInfoDto getCurrentMemberPositionInfo(); + void updateLoanSuspensionDate(String memberId, LocalDateTime loanSuspensionDate); void updateLastLoginTime(String id); diff --git a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java index 3274b0864..cec61a678 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberLookupServiceImpl.java @@ -9,6 +9,7 @@ import page.clab.api.domain.member.dto.shared.LoginMemberInfoDto; import page.clab.api.domain.member.dto.shared.MemberBasicInfoDto; import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; +import page.clab.api.domain.member.dto.shared.MemberPositionInfoDto; import page.clab.api.global.auth.util.AuthUtil; import page.clab.api.global.exception.NotFoundException; @@ -134,6 +135,14 @@ public LoginMemberInfoDto getLoginMemberInfoById(String memberId) { .orElseThrow(() -> new NotFoundException("[Member] id: " + memberId + "에 해당하는 멤버가 존재하지 않습니다.")); } + @Override + public MemberPositionInfoDto getCurrentMemberPositionInfo() { + String currentMemberId = getCurrentMemberId(); + return memberRepository.findById(currentMemberId) + .map(MemberPositionInfoDto::create) + .orElseThrow(() -> new NotFoundException("[Member] id: " + currentMemberId + "에 해당하는 멤버가 존재하지 않습니다.")); + } + public void updateLoanSuspensionDate(String memberId, LocalDateTime loanSuspensionDate) { Member member = getMemberByIdOrThrow(memberId); member.updateLoanSuspensionDate(loanSuspensionDate); diff --git a/src/main/java/page/clab/api/domain/member/application/MemberService.java b/src/main/java/page/clab/api/domain/member/application/MemberService.java index 820fdb6b2..7b9e54c5c 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberService.java @@ -203,10 +203,10 @@ private void checkMemberUniqueness(MemberRequestDto requestDto) { } public void createPositionByMember(Member member) { - if (positionRepository.findByMemberAndYearAndPositionType(member, String.valueOf(LocalDate.now().getYear()), PositionType.MEMBER).isPresent()) { + if (positionRepository.findByMemberIdAndYearAndPositionType(member.getId(), String.valueOf(LocalDate.now().getYear()), PositionType.MEMBER).isPresent()) { return; } - Position position = Position.create(member); + Position position = Position.create(member.getId()); positionRepository.save(position); } diff --git a/src/main/java/page/clab/api/domain/member/dto/shared/MemberPositionInfoDto.java b/src/main/java/page/clab/api/domain/member/dto/shared/MemberPositionInfoDto.java new file mode 100644 index 000000000..90053d6f5 --- /dev/null +++ b/src/main/java/page/clab/api/domain/member/dto/shared/MemberPositionInfoDto.java @@ -0,0 +1,34 @@ +package page.clab.api.domain.member.dto.shared; + +import lombok.Builder; +import lombok.Getter; +import page.clab.api.domain.member.domain.Member; + +@Getter +@Builder +public class MemberPositionInfoDto { + + private String memberId; + + private String memberName; + + private String email; + + private String imageUrl; + + private String interests; + + private String githubUrl; + + public static MemberPositionInfoDto create(Member member) { + return MemberPositionInfoDto.builder() + .memberId(member.getId()) + .memberName(member.getName()) + .email(member.getEmail()) + .imageUrl(member.getImageUrl()) + .interests(member.getInterests()) + .githubUrl(member.getGithubUrl()) + .build(); + } + +} diff --git a/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java b/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java new file mode 100644 index 000000000..fea0e96be --- /dev/null +++ b/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java @@ -0,0 +1,41 @@ +package page.clab.api.domain.position.application; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.event.MemberEventProcessor; +import page.clab.api.domain.member.event.MemberEventProcessorRegistry; +import page.clab.api.domain.position.dao.PositionRepository; +import page.clab.api.domain.position.domain.Position; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class PositionEventProcessor implements MemberEventProcessor { + + private final PositionRepository positionRepository; + + private final MemberEventProcessorRegistry processorRegistry; + + @PostConstruct + public void init() { + processorRegistry.registerProcessor(this); + } + + @Override + @Transactional + public void processMemberDeleted(Member member) { + List<Position> positions = positionRepository.findByMemberId(member.getId()); + positions.forEach(Position::delete); + positionRepository.saveAll(positions); + } + + @Override + public void processMemberUpdated(Member member) { + // do nothing + } + +} diff --git a/src/main/java/page/clab/api/domain/position/application/PositionService.java b/src/main/java/page/clab/api/domain/position/application/PositionService.java index 22eb51f6a..f2b4f512d 100644 --- a/src/main/java/page/clab/api/domain/position/application/PositionService.java +++ b/src/main/java/page/clab/api/domain/position/application/PositionService.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberPositionInfoDto; import page.clab.api.domain.position.dao.PositionRepository; import page.clab.api.domain.position.domain.Position; import page.clab.api.domain.position.domain.PositionType; @@ -28,8 +28,8 @@ public class PositionService { @Transactional public Long createPosition(PositionRequestDto requestDto) { - Member member = memberLookupService.getMemberByIdOrThrow(requestDto.getMemberId()); - return positionRepository.findByMemberAndYearAndPositionType(member, requestDto.getYear(), requestDto.getPositionType()) + memberLookupService.ensureMemberExists(requestDto.getMemberId()); + return positionRepository.findByMemberIdAndYearAndPositionType(requestDto.getMemberId(), requestDto.getYear(), requestDto.getPositionType()) .map(Position::getId) .orElseGet(() -> { Position position = PositionRequestDto.toEntity(requestDto); @@ -39,30 +39,33 @@ public Long createPosition(PositionRequestDto requestDto) { @Transactional(readOnly = true) public PagedResponseDto<PositionResponseDto> getPositionsByConditions(String year, PositionType positionType, Pageable pageable) { + MemberPositionInfoDto currentMemberInfo = memberLookupService.getCurrentMemberPositionInfo(); Page<Position> positions = positionRepository.findByConditions(year, positionType, pageable); - return new PagedResponseDto<>(positions.map(PositionResponseDto::toDto)); + return new PagedResponseDto<>(positions.map(position -> PositionResponseDto.toDto(position, currentMemberInfo))); } @Transactional(readOnly = true) public PositionMyResponseDto getMyPositionsByYear(String year) { - Member currentMember = memberLookupService.getCurrentMember(); - List<Position> positions = getPositionsByMemberAndYear(currentMember, year); + MemberPositionInfoDto currentMemberInfo = memberLookupService.getCurrentMemberPositionInfo(); + List<Position> positions = getPositionsByMemberIdAndYear(currentMemberInfo.getMemberId(), year); if (positions.isEmpty()) { throw new NotFoundException("해당 멤버의 " + year + "년도 직책이 존재하지 않습니다."); } - return PositionMyResponseDto.toDto(positions); + return PositionMyResponseDto.toDto(positions, currentMemberInfo); } @Transactional(readOnly = true) public PagedResponseDto<PositionResponseDto> getDeletedPositions(Pageable pageable) { + MemberPositionInfoDto currentMemberInfo = memberLookupService.getCurrentMemberPositionInfo(); Page<Position> positions = positionRepository.findAllByIsDeletedTrue(pageable); - return new PagedResponseDto<>(positions.map(PositionResponseDto::toDto)); + return new PagedResponseDto<>(positions.map(position -> PositionResponseDto.toDto(position, currentMemberInfo))); } + @Transactional public Long deletePosition(Long positionId) { Position position = getPositionsByIdOrThrow(positionId); - positionRepository.delete(position); - return position.getId(); + position.delete(); + return positionRepository.save(position).getId(); } private Position getPositionsByIdOrThrow(Long positionId) { @@ -70,8 +73,8 @@ private Position getPositionsByIdOrThrow(Long positionId) { .orElseThrow(() -> new NotFoundException("해당 운영진이 존재하지 않습니다.")); } - private List<Position> getPositionsByMemberAndYear(Member member, String year) { - return positionRepository.findAllByMemberAndYearOrderByPositionTypeAsc(member, year); + private List<Position> getPositionsByMemberIdAndYear(String memberId, String year) { + return positionRepository.findAllByMemberIdAndYearOrderByPositionTypeAsc(memberId, year); } } diff --git a/src/main/java/page/clab/api/domain/position/dao/PositionRepository.java b/src/main/java/page/clab/api/domain/position/dao/PositionRepository.java index a4dc9333a..a9c2dc836 100644 --- a/src/main/java/page/clab/api/domain/position/dao/PositionRepository.java +++ b/src/main/java/page/clab/api/domain/position/dao/PositionRepository.java @@ -5,7 +5,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.querydsl.QuerydslPredicateExecutor; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.position.domain.Position; import page.clab.api.domain.position.domain.PositionType; @@ -14,9 +13,11 @@ public interface PositionRepository extends JpaRepository<Position, Long>, PositionRepositoryCustom, QuerydslPredicateExecutor<Position> { - Optional<Position> findByMemberAndYearAndPositionType(Member member, String year, PositionType positionType); + List<Position> findByMemberId(String id); - List<Position> findAllByMemberAndYearOrderByPositionTypeAsc(Member member, String year); + Optional<Position> findByMemberIdAndYearAndPositionType(String memberId, String year, PositionType positionType); + + List<Position> findAllByMemberIdAndYearOrderByPositionTypeAsc(String memberId, String year); @Query(value = "SELECT p.* FROM \"position\" p WHERE p.is_deleted = true", nativeQuery = true) Page<Position> findAllByIsDeletedTrue(Pageable pageable); diff --git a/src/main/java/page/clab/api/domain/position/domain/Position.java b/src/main/java/page/clab/api/domain/position/domain/Position.java index 16cd0541e..4b7af2799 100644 --- a/src/main/java/page/clab/api/domain/position/domain/Position.java +++ b/src/main/java/page/clab/api/domain/position/domain/Position.java @@ -5,8 +5,6 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -15,7 +13,6 @@ import lombok.Setter; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; -import page.clab.api.domain.member.domain.Member; import page.clab.api.global.common.domain.BaseEntity; import java.time.LocalDate; @@ -34,9 +31,8 @@ public class Position extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - @JoinColumn(name = "member_id", nullable = false) - private Member member; + @Column(name = "member_id", nullable = false) + private String memberId; @Column(nullable = false) private PositionType positionType; @@ -44,12 +40,16 @@ public class Position extends BaseEntity { @Column(nullable = false) private String year; - public static Position create(Member member) { + public static Position create(String memberId) { return Position.builder() - .member(member) + .memberId(memberId) .positionType(PositionType.MEMBER) .year(String.valueOf(LocalDate.now().getYear())) .build(); } + public void delete() { + this.isDeleted = true; + } + } diff --git a/src/main/java/page/clab/api/domain/position/dto/request/PositionRequestDto.java b/src/main/java/page/clab/api/domain/position/dto/request/PositionRequestDto.java index 1b1d07f32..9c653eb93 100644 --- a/src/main/java/page/clab/api/domain/position/dto/request/PositionRequestDto.java +++ b/src/main/java/page/clab/api/domain/position/dto/request/PositionRequestDto.java @@ -4,7 +4,6 @@ import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.position.domain.Position; import page.clab.api.domain.position.domain.PositionType; @@ -26,7 +25,7 @@ public class PositionRequestDto { public static Position toEntity(PositionRequestDto positionRequestDto) { return Position.builder() - .member(Member.builder().id(positionRequestDto.getMemberId()).build()) + .memberId(positionRequestDto.getMemberId()) .positionType(positionRequestDto.getPositionType()) .year(positionRequestDto.getYear()) .build(); diff --git a/src/main/java/page/clab/api/domain/position/dto/response/PositionMyResponseDto.java b/src/main/java/page/clab/api/domain/position/dto/response/PositionMyResponseDto.java index cf33beadb..95ad6ad80 100644 --- a/src/main/java/page/clab/api/domain/position/dto/response/PositionMyResponseDto.java +++ b/src/main/java/page/clab/api/domain/position/dto/response/PositionMyResponseDto.java @@ -2,7 +2,7 @@ import lombok.Builder; import lombok.Getter; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberPositionInfoDto; import page.clab.api.domain.position.domain.Position; import page.clab.api.domain.position.domain.PositionType; @@ -28,19 +28,18 @@ public class PositionMyResponseDto { private Map<String, List<PositionType>> positionTypes; - public static PositionMyResponseDto toDto(List<Position> positions) { - Member member = positions.getFirst().getMember(); + public static PositionMyResponseDto toDto(List<Position> positions, MemberPositionInfoDto memberInfo) { Map<String, List<PositionType>> positionTypesByYear = positions.stream() .collect(Collectors.groupingBy( Position::getYear, Collectors.mapping(Position::getPositionType, Collectors.toList()) )); return PositionMyResponseDto.builder() - .name(member.getName()) - .email(member.getEmail()) - .imageUrl(member.getImageUrl()) - .interests(member.getInterests()) - .githubUrl(member.getGithubUrl()) + .name(memberInfo.getMemberName()) + .email(memberInfo.getEmail()) + .imageUrl(memberInfo.getImageUrl()) + .interests(memberInfo.getInterests()) + .githubUrl(memberInfo.getGithubUrl()) .positionTypes(positionTypesByYear) .build(); } diff --git a/src/main/java/page/clab/api/domain/position/dto/response/PositionResponseDto.java b/src/main/java/page/clab/api/domain/position/dto/response/PositionResponseDto.java index 30341d5b9..e09ab0715 100644 --- a/src/main/java/page/clab/api/domain/position/dto/response/PositionResponseDto.java +++ b/src/main/java/page/clab/api/domain/position/dto/response/PositionResponseDto.java @@ -2,7 +2,7 @@ import lombok.Builder; import lombok.Getter; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberPositionInfoDto; import page.clab.api.domain.position.domain.Position; import page.clab.api.domain.position.domain.PositionType; @@ -26,15 +26,14 @@ public class PositionResponseDto { private String year; - public static PositionResponseDto toDto(Position position) { - Member member = position.getMember(); + public static PositionResponseDto toDto(Position position, MemberPositionInfoDto memberInfo) { return PositionResponseDto.builder() .id(position.getId()) - .name(member.getName()) - .email(member.getEmail()) - .imageUrl(member.getImageUrl()) - .interests(member.getInterests()) - .githubUrl(member.getGithubUrl()) + .name(memberInfo.getMemberName()) + .email(memberInfo.getEmail()) + .imageUrl(memberInfo.getImageUrl()) + .interests(memberInfo.getInterests()) + .githubUrl(memberInfo.getGithubUrl()) .positionType(position.getPositionType()) .year(position.getYear()) .build(); From 534f0b7be607c72ee5c22bcfd7364af27ac05ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 16:14:43 +0900 Subject: [PATCH 45/47] =?UTF-8?q?refactor(WorkExperience):=20Member=20?= =?UTF-8?q?=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20?= =?UTF-8?q?=EC=A7=81=EC=A0=91=20=EC=B0=B8=EC=A1=B0=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EA=B3=A0,=20=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20DTO=EB=A1=9C=20=EC=A3=BC=EA=B3=A0=EB=B0=9B?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WorkExperienceEventProcessor.java | 40 +++++++++++++++++++ .../application/WorkExperienceService.java | 26 ++++++------ .../dao/WorkExperienceRepository.java | 7 +++- .../workExperience/domain/WorkExperience.java | 19 +++++---- .../dto/request/WorkExperienceRequestDto.java | 5 +-- 5 files changed, 71 insertions(+), 26 deletions(-) create mode 100644 src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java diff --git a/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java b/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java new file mode 100644 index 000000000..0a9a38e73 --- /dev/null +++ b/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java @@ -0,0 +1,40 @@ +package page.clab.api.domain.workExperience.application; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.event.MemberEventProcessor; +import page.clab.api.domain.member.event.MemberEventProcessorRegistry; +import page.clab.api.domain.workExperience.dao.WorkExperienceRepository; +import page.clab.api.domain.workExperience.domain.WorkExperience; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class WorkExperienceEventProcessor implements MemberEventProcessor { + + private final WorkExperienceRepository workExperienceRepository; + + private final MemberEventProcessorRegistry processorRegistry; + + @PostConstruct + public void init() { + processorRegistry.registerProcessor(this); + } + + @Override + @Transactional + public void processMemberDeleted(Member member) { + List<WorkExperience> workExperiences = workExperienceRepository.findByMemberId(member.getId()); + workExperiences.forEach(WorkExperience::delete); + workExperienceRepository.saveAll(workExperiences); + } + + @Override + public void processMemberUpdated(Member member) { + // do nothing + } +} diff --git a/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceService.java b/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceService.java index 7c094dd6a..ed5ec7997 100644 --- a/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceService.java +++ b/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceService.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.member.application.MemberLookupService; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.domain.workExperience.dao.WorkExperienceRepository; import page.clab.api.domain.workExperience.domain.WorkExperience; import page.clab.api.domain.workExperience.dto.request.WorkExperienceRequestDto; @@ -29,23 +29,22 @@ public class WorkExperienceService { @Transactional public Long createWorkExperience(WorkExperienceRequestDto requestDto) { - Member currentMember = memberLookupService.getCurrentMember(); - WorkExperience workExperience = WorkExperienceRequestDto.toEntity(requestDto, currentMember); + String currentMemberId = memberLookupService.getCurrentMemberId(); + WorkExperience workExperience = WorkExperienceRequestDto.toEntity(requestDto, currentMemberId); validationService.checkValid(workExperience); return workExperienceRepository.save(workExperience).getId(); } @Transactional(readOnly = true) public PagedResponseDto<WorkExperienceResponseDto> getMyWorkExperience(Pageable pageable) { - Member currentMember = memberLookupService.getCurrentMember(); - Page<WorkExperience> workExperiences = workExperienceRepository.findAllByMember(currentMember, pageable); + String currentMemberId = memberLookupService.getCurrentMemberId(); + Page<WorkExperience> workExperiences = workExperienceRepository.findByMemberId(currentMemberId, pageable); return new PagedResponseDto<>(workExperiences.map(WorkExperienceResponseDto::toDto)); } @Transactional(readOnly = true) public PagedResponseDto<WorkExperienceResponseDto> getWorkExperiencesByConditions(String memberId, Pageable pageable) { - Member member = memberLookupService.getMemberByIdOrThrow(memberId); - Page<WorkExperience> workExperiences = workExperienceRepository.findAllByMember(member, pageable); + Page<WorkExperience> workExperiences = workExperienceRepository.findByMemberId(memberId, pageable); return new PagedResponseDto<>(workExperiences.map(WorkExperienceResponseDto::toDto)); } @@ -57,20 +56,21 @@ public PagedResponseDto<WorkExperienceResponseDto> getDeletedWorkExperiences(Pag @Transactional public Long updateWorkExperience(Long workExperienceId, WorkExperienceUpdateRequestDto requestDto) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); WorkExperience workExperience = getWorkExperienceByIdOrThrow(workExperienceId); - workExperience.validateAccessPermission(currentMember); + workExperience.validateAccessPermission(currentMemberInfo); workExperience.update(requestDto); validationService.checkValid(workExperience); return workExperienceRepository.save(workExperience).getId(); } + @Transactional public Long deleteWorkExperience(Long workExperienceId) throws PermissionDeniedException { - Member currentMember = memberLookupService.getCurrentMember(); + MemberDetailedInfoDto currentMemberInfo = memberLookupService.getCurrentMemberDetailedInfo(); WorkExperience workExperience = getWorkExperienceByIdOrThrow(workExperienceId); - workExperience.validateAccessPermission(currentMember); - workExperienceRepository.deleteById(workExperienceId); - return workExperience.getId(); + workExperience.validateAccessPermission(currentMemberInfo); + workExperience.delete(); + return workExperienceRepository.save(workExperience).getId(); } private WorkExperience getWorkExperienceByIdOrThrow(Long workExperienceId) { diff --git a/src/main/java/page/clab/api/domain/workExperience/dao/WorkExperienceRepository.java b/src/main/java/page/clab/api/domain/workExperience/dao/WorkExperienceRepository.java index f8106d8b0..d059f4368 100644 --- a/src/main/java/page/clab/api/domain/workExperience/dao/WorkExperienceRepository.java +++ b/src/main/java/page/clab/api/domain/workExperience/dao/WorkExperienceRepository.java @@ -5,13 +5,16 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.workExperience.domain.WorkExperience; +import java.util.List; + @Repository public interface WorkExperienceRepository extends JpaRepository<WorkExperience, Long> { - Page<WorkExperience> findAllByMember(Member member, Pageable pageable); + Page<WorkExperience> findByMemberId(String memberId, Pageable pageable); + + List<WorkExperience> findByMemberId(String memberId); @Query(value = "SELECT w.* FROM work_experience w WHERE w.is_deleted = true", nativeQuery = true) Page<WorkExperience> findAllByIsDeletedTrue(Pageable pageable); diff --git a/src/main/java/page/clab/api/domain/workExperience/domain/WorkExperience.java b/src/main/java/page/clab/api/domain/workExperience/domain/WorkExperience.java index b74f05ecd..fe1e7f3f1 100644 --- a/src/main/java/page/clab/api/domain/workExperience/domain/WorkExperience.java +++ b/src/main/java/page/clab/api/domain/workExperience/domain/WorkExperience.java @@ -5,7 +5,6 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; import jakarta.validation.constraints.Size; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -15,7 +14,7 @@ import lombok.Setter; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; -import page.clab.api.domain.member.domain.Member; +import page.clab.api.domain.member.dto.shared.MemberDetailedInfoDto; import page.clab.api.domain.workExperience.dto.request.WorkExperienceUpdateRequestDto; import page.clab.api.global.common.domain.BaseEntity; import page.clab.api.global.exception.PermissionDeniedException; @@ -51,8 +50,8 @@ public class WorkExperience extends BaseEntity { @Column(nullable = false) private LocalDate endDate; - @ManyToOne - private Member member; + @Column(name = "member_id", nullable = false) + private String memberId; public void update(WorkExperienceUpdateRequestDto workExperienceUpdateRequestDto) { Optional.ofNullable(workExperienceUpdateRequestDto.getCompanyName()).ifPresent(this::setCompanyName); @@ -61,12 +60,16 @@ public void update(WorkExperienceUpdateRequestDto workExperienceUpdateRequestDto Optional.ofNullable(workExperienceUpdateRequestDto.getEndDate()).ifPresent(this::setEndDate); } - public boolean isOwner(Member member) { - return this.member.isSameMember(member); + public void delete() { + this.isDeleted = true; } - public void validateAccessPermission(Member member) throws PermissionDeniedException { - if (!isOwner(member) && !member.isSuperAdminRole()) { + public boolean isOwner(String memberId) { + return this.memberId.equals(memberId); + } + + public void validateAccessPermission(MemberDetailedInfoDto memberInfo) throws PermissionDeniedException { + if (!isOwner(memberInfo.getMemberId()) && !memberInfo.isSuperAdminRole()) { throw new PermissionDeniedException("해당 경력사항을 수정/삭제할 권한이 없습니다."); } } diff --git a/src/main/java/page/clab/api/domain/workExperience/dto/request/WorkExperienceRequestDto.java b/src/main/java/page/clab/api/domain/workExperience/dto/request/WorkExperienceRequestDto.java index febf392b4..1ef63b519 100644 --- a/src/main/java/page/clab/api/domain/workExperience/dto/request/WorkExperienceRequestDto.java +++ b/src/main/java/page/clab/api/domain/workExperience/dto/request/WorkExperienceRequestDto.java @@ -4,7 +4,6 @@ import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.workExperience.domain.WorkExperience; import java.time.LocalDate; @@ -29,13 +28,13 @@ public class WorkExperienceRequestDto { @Schema(description = "종료일", example = "2023-12-31", required = true) private LocalDate endDate; - public static WorkExperience toEntity(WorkExperienceRequestDto requestDto, Member member) { + public static WorkExperience toEntity(WorkExperienceRequestDto requestDto, String memberId) { return WorkExperience.builder() .companyName(requestDto.getCompanyName()) .position(requestDto.getPosition()) .startDate(requestDto.getStartDate()) .endDate(requestDto.getEndDate()) - .member(member) + .memberId(memberId) .build(); } From 6a719fe924f762ce63f65108698946a27b4b19fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 16:15:53 +0900 Subject: [PATCH 46/47] =?UTF-8?q?refactor(EventProcessor):=20=EB=A9=94?= =?UTF-8?q?=EC=86=8C=EB=93=9C=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/domain/accuse/application/AccuseEventProcessor.java | 2 +- .../clab/api/domain/award/application/AwardEventProcessor.java | 2 +- .../clab/api/domain/board/application/BoardEventProcessor.java | 2 +- .../api/domain/member/event/MemberEventProcessorRegistry.java | 2 +- .../notification/application/NotificationEventProcessor.java | 2 +- .../api/domain/position/application/PositionEventProcessor.java | 2 +- .../application/WorkExperienceEventProcessor.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java index 6dab8da72..54d599d70 100644 --- a/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java @@ -22,7 +22,7 @@ public class AccuseEventProcessor implements MemberEventProcessor { @PostConstruct public void init() { - processorRegistry.registerProcessor(this); + processorRegistry.register(this); } @Override diff --git a/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java b/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java index 2372393aa..ef57a40fa 100644 --- a/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java +++ b/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java @@ -22,7 +22,7 @@ public class AwardEventProcessor implements MemberEventProcessor { @PostConstruct public void init() { - processorRegistry.registerProcessor(this); + processorRegistry.register(this); } @Override diff --git a/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java b/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java index e7ffa7a03..8fd70117f 100644 --- a/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java +++ b/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java @@ -22,7 +22,7 @@ public class BoardEventProcessor implements MemberEventProcessor { @PostConstruct public void init() { - processorRegistry.registerProcessor(this); + processorRegistry.register(this); } @Override diff --git a/src/main/java/page/clab/api/domain/member/event/MemberEventProcessorRegistry.java b/src/main/java/page/clab/api/domain/member/event/MemberEventProcessorRegistry.java index 90f9098a5..2a7c542f1 100644 --- a/src/main/java/page/clab/api/domain/member/event/MemberEventProcessorRegistry.java +++ b/src/main/java/page/clab/api/domain/member/event/MemberEventProcessorRegistry.java @@ -11,7 +11,7 @@ public class MemberEventProcessorRegistry { private final List<MemberEventProcessor> processors = new ArrayList<>(); - public void registerProcessor(MemberEventProcessor processor) { + public void register(MemberEventProcessor processor) { processors.add(processor); } diff --git a/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java b/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java index c2e28269f..48f5c5146 100644 --- a/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java +++ b/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java @@ -22,7 +22,7 @@ public class NotificationEventProcessor implements MemberEventProcessor { @PostConstruct public void init() { - processorRegistry.registerProcessor(this); + processorRegistry.register(this); } @Override diff --git a/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java b/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java index fea0e96be..0754debd9 100644 --- a/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java +++ b/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java @@ -22,7 +22,7 @@ public class PositionEventProcessor implements MemberEventProcessor { @PostConstruct public void init() { - processorRegistry.registerProcessor(this); + processorRegistry.register(this); } @Override diff --git a/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java b/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java index 0a9a38e73..4741e575c 100644 --- a/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java +++ b/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java @@ -22,7 +22,7 @@ public class WorkExperienceEventProcessor implements MemberEventProcessor { @PostConstruct public void init() { - processorRegistry.registerProcessor(this); + processorRegistry.register(this); } @Override From ac42e208261f8042f68a74142569ea5a3101ab2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=9C=EA=B4=80=ED=9D=AC?= <noop103@naver.com> Date: Wed, 26 Jun 2024 16:21:33 +0900 Subject: [PATCH 47/47] =?UTF-8?q?refactor(EventProcessor):=20Member=20?= =?UTF-8?q?=EC=88=98=EC=A0=95/=EC=82=AD=EC=A0=9C=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=EC=97=90=20=EB=8C=80=ED=95=B4=20=EC=B5=9C=EC=86=8C?= =?UTF-8?q?=ED=95=9C=EC=9D=98=20=EC=A0=95=EB=B3=B4=EB=A7=8C=20=EC=A0=84?= =?UTF-8?q?=EB=8B=AC=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/accuse/application/AccuseEventProcessor.java | 7 +++---- .../api/domain/award/application/AwardEventProcessor.java | 7 +++---- .../api/domain/board/application/BoardEventProcessor.java | 7 +++---- .../clab/api/domain/member/application/MemberService.java | 4 ++-- .../clab/api/domain/member/event/MemberDeletedEvent.java | 7 +++---- .../api/domain/member/event/MemberEventDispatcher.java | 4 ++-- .../clab/api/domain/member/event/MemberEventProcessor.java | 6 ++---- .../clab/api/domain/member/event/MemberUpdatedEvent.java | 7 +++---- .../application/NotificationEventProcessor.java | 7 +++---- .../position/application/PositionEventProcessor.java | 7 +++---- .../application/WorkExperienceEventProcessor.java | 7 +++---- 11 files changed, 30 insertions(+), 40 deletions(-) diff --git a/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java b/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java index 54d599d70..e80d22bc0 100644 --- a/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java +++ b/src/main/java/page/clab/api/domain/accuse/application/AccuseEventProcessor.java @@ -6,7 +6,6 @@ import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.accuse.dao.AccuseRepository; import page.clab.api.domain.accuse.domain.Accuse; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.event.MemberEventProcessor; import page.clab.api.domain.member.event.MemberEventProcessorRegistry; @@ -27,14 +26,14 @@ public void init() { @Override @Transactional - public void processMemberDeleted(Member member) { - List<Accuse> accuses = accuseRepository.findByMemberId(member.getId()); + public void processMemberDeleted(String memberId) { + List<Accuse> accuses = accuseRepository.findByMemberId(memberId); accuses.forEach(Accuse::delete); accuseRepository.saveAll(accuses); } @Override - public void processMemberUpdated(Member member) { + public void processMemberUpdated(String memberId) { // do nothing } diff --git a/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java b/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java index ef57a40fa..c240e2647 100644 --- a/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java +++ b/src/main/java/page/clab/api/domain/award/application/AwardEventProcessor.java @@ -6,7 +6,6 @@ import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.award.dao.AwardRepository; import page.clab.api.domain.award.domain.Award; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.event.MemberEventProcessor; import page.clab.api.domain.member.event.MemberEventProcessorRegistry; @@ -27,14 +26,14 @@ public void init() { @Override @Transactional - public void processMemberDeleted(Member member) { - List<Award> awards = awardRepository.findByMemberId(member.getId()); + public void processMemberDeleted(String memberId) { + List<Award> awards = awardRepository.findByMemberId(memberId); awards.forEach(Award::delete); awardRepository.saveAll(awards); } @Override - public void processMemberUpdated(Member member) { + public void processMemberUpdated(String memberId) { // do nothing } } diff --git a/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java b/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java index 8fd70117f..4a75bb9a8 100644 --- a/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java +++ b/src/main/java/page/clab/api/domain/board/application/BoardEventProcessor.java @@ -6,7 +6,6 @@ import org.springframework.transaction.annotation.Transactional; import page.clab.api.domain.board.dao.BoardRepository; import page.clab.api.domain.board.domain.Board; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.event.MemberEventProcessor; import page.clab.api.domain.member.event.MemberEventProcessorRegistry; @@ -27,14 +26,14 @@ public void init() { @Override @Transactional - public void processMemberDeleted(Member member) { - List<Board> boards = boardRepository.findByMemberId(member.getId()); + public void processMemberDeleted(String memberId) { + List<Board> boards = boardRepository.findByMemberId(memberId); boards.forEach(Board::delete); boardRepository.saveAll(boards); } @Override - public void processMemberUpdated(Member member) { + public void processMemberUpdated(String memberId) { // do nothing } } diff --git a/src/main/java/page/clab/api/domain/member/application/MemberService.java b/src/main/java/page/clab/api/domain/member/application/MemberService.java index 7b9e54c5c..7ef226d60 100644 --- a/src/main/java/page/clab/api/domain/member/application/MemberService.java +++ b/src/main/java/page/clab/api/domain/member/application/MemberService.java @@ -119,7 +119,7 @@ public String updateMemberInfo(String memberId, MemberUpdateRequestDto requestDt updateMember(requestDto, member); validationService.checkValid(member); memberRepository.save(member); - eventPublisher.publishEvent(new MemberUpdatedEvent(this, member)); + eventPublisher.publishEvent(new MemberUpdatedEvent(this, member.getId())); return member.getId(); } @@ -143,7 +143,7 @@ public String verifyResetMemberPassword(VerificationRequestDto requestDto) { public String deleteMember(String memberId) { Member member = memberLookupService.getMemberByIdOrThrow(memberId); memberRepository.delete(member); - eventPublisher.publishEvent(new MemberDeletedEvent(this, member)); + eventPublisher.publishEvent(new MemberDeletedEvent(this, member.getId())); return member.getId(); } diff --git a/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java b/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java index 692247e07..c9d40fa5e 100644 --- a/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java +++ b/src/main/java/page/clab/api/domain/member/event/MemberDeletedEvent.java @@ -2,16 +2,15 @@ import lombok.Getter; import org.springframework.context.ApplicationEvent; -import page.clab.api.domain.member.domain.Member; @Getter public class MemberDeletedEvent extends ApplicationEvent { - private final Member member; + private final String memberId; - public MemberDeletedEvent(Object source, Member member) { + public MemberDeletedEvent(Object source, String memberId) { super(source); - this.member = member; + this.memberId = memberId; } } diff --git a/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java b/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java index 4081107c0..76746915d 100644 --- a/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java +++ b/src/main/java/page/clab/api/domain/member/event/MemberEventDispatcher.java @@ -14,11 +14,11 @@ public class MemberEventDispatcher { @EventListener public void handleMemberDeletedEvent(MemberDeletedEvent event) { - processors.forEach(processor -> processor.processMemberDeleted(event.getMember())); + processors.forEach(processor -> processor.processMemberDeleted(event.getMemberId())); } @EventListener public void handleMemberUpdatedEvent(MemberUpdatedEvent event) { - processors.forEach(processor -> processor.processMemberUpdated(event.getMember())); + processors.forEach(processor -> processor.processMemberUpdated(event.getMemberId())); } } diff --git a/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java b/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java index 0bcb8fc4f..f3d34ca62 100644 --- a/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java +++ b/src/main/java/page/clab/api/domain/member/event/MemberEventProcessor.java @@ -1,11 +1,9 @@ package page.clab.api.domain.member.event; -import page.clab.api.domain.member.domain.Member; - public interface MemberEventProcessor { - void processMemberDeleted(Member member); + void processMemberDeleted(String memberId); - void processMemberUpdated(Member member); + void processMemberUpdated(String memberId); } diff --git a/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java b/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java index 37efe8d1b..b1bc7b142 100644 --- a/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java +++ b/src/main/java/page/clab/api/domain/member/event/MemberUpdatedEvent.java @@ -2,16 +2,15 @@ import lombok.Getter; import org.springframework.context.ApplicationEvent; -import page.clab.api.domain.member.domain.Member; @Getter public class MemberUpdatedEvent extends ApplicationEvent { - private final Member member; + private final String memberId; - public MemberUpdatedEvent(Object source, Member member) { + public MemberUpdatedEvent(Object source, String memberId) { super(source); - this.member = member; + this.memberId = memberId; } } diff --git a/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java b/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java index 48f5c5146..71b686b20 100644 --- a/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java +++ b/src/main/java/page/clab/api/domain/notification/application/NotificationEventProcessor.java @@ -4,7 +4,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.event.MemberEventProcessor; import page.clab.api.domain.member.event.MemberEventProcessorRegistry; import page.clab.api.domain.notification.dao.NotificationRepository; @@ -27,14 +26,14 @@ public void init() { @Override @Transactional - public void processMemberDeleted(Member member) { - List<Notification> notifications = notificationRepository.findByMemberId(member.getId()); + public void processMemberDeleted(String memberId) { + List<Notification> notifications = notificationRepository.findByMemberId(memberId); notifications.forEach(Notification::delete); notificationRepository.saveAll(notifications); } @Override - public void processMemberUpdated(Member member) { + public void processMemberUpdated(String memberId) { // do nothing } diff --git a/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java b/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java index 0754debd9..d4fc9c8ef 100644 --- a/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java +++ b/src/main/java/page/clab/api/domain/position/application/PositionEventProcessor.java @@ -4,7 +4,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.event.MemberEventProcessor; import page.clab.api.domain.member.event.MemberEventProcessorRegistry; import page.clab.api.domain.position.dao.PositionRepository; @@ -27,14 +26,14 @@ public void init() { @Override @Transactional - public void processMemberDeleted(Member member) { - List<Position> positions = positionRepository.findByMemberId(member.getId()); + public void processMemberDeleted(String memberId) { + List<Position> positions = positionRepository.findByMemberId(memberId); positions.forEach(Position::delete); positionRepository.saveAll(positions); } @Override - public void processMemberUpdated(Member member) { + public void processMemberUpdated(String memberId) { // do nothing } diff --git a/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java b/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java index 4741e575c..08f2dc31c 100644 --- a/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java +++ b/src/main/java/page/clab/api/domain/workExperience/application/WorkExperienceEventProcessor.java @@ -4,7 +4,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import page.clab.api.domain.member.domain.Member; import page.clab.api.domain.member.event.MemberEventProcessor; import page.clab.api.domain.member.event.MemberEventProcessorRegistry; import page.clab.api.domain.workExperience.dao.WorkExperienceRepository; @@ -27,14 +26,14 @@ public void init() { @Override @Transactional - public void processMemberDeleted(Member member) { - List<WorkExperience> workExperiences = workExperienceRepository.findByMemberId(member.getId()); + public void processMemberDeleted(String memberId) { + List<WorkExperience> workExperiences = workExperienceRepository.findByMemberId(memberId); workExperiences.forEach(WorkExperience::delete); workExperienceRepository.saveAll(workExperiences); } @Override - public void processMemberUpdated(Member member) { + public void processMemberUpdated(String memberId) { // do nothing } }