diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 000000000..4baf206ff
Binary files /dev/null and b/.DS_Store differ
diff --git a/.github/workflows/backend_dev_merge_workflow.yml b/.github/workflows/backend_dev_merge_workflow.yml
index 867e515ac..c2ce9e5b5 100644
--- a/.github/workflows/backend_dev_merge_workflow.yml
+++ b/.github/workflows/backend_dev_merge_workflow.yml
@@ -5,22 +5,54 @@ on:
- dev_backend
jobs:
- deploy:
- runs-on: naaga
+ github_actions_setting:
+ runs-on: ubuntu-latest
+
steps:
- - name: change permission
- run: |
- sudo chown -R ubuntu:ubuntu /home/ubuntu/actions-runner/naaga/2023-naaga/2023-naaga
- - name: checkout
+ - name: ๐ ํ๋ก์ ํธ ํ์ผ ๊ฐ์ ธ์ค๋ ์ค... ๐
uses: actions/checkout@v3
with:
submodules: true
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
- - name: remove
+
+ - name: โ๏ธ ๊นํ๋ธ ์ก์
์ JDK 17 ์ ์ฉ์ํค๋ ์ค... โ๏ธ
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'corretto'
+
+ - name: ๐ Gradle ์ธํ
์ค... ๐
+ uses: gradle/gradle-build-action@v2.6.0
+
+ - name: โ๏ธ Gradle ๋ก JAR ํ์ผ ํ
์คํธ ๋ฐ ๋น๋ ์ค... โ๏ธ
+ run: |
+ cd backend
+ ./gradlew clean bootJar -Dspring.profiles.active=test
+
+ - name: ๐ณ ๋์ปค ์ธํ
์ค... ๐ณ
+ uses: docker/setup-buildx-action@v2.9.1
+
+ - name: ๐ณ ๋์ปค ํ๋ธ์ ๋ก๊ทธ์ธ ์ค... ๐ณ
+ uses: docker/login-action@v1
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_ACCESSTOKEN }}
+
+ - name: ๐ณ ๋์ปค ์ด๋ฏธ์ง ๋น๋ ์ค... ๐ณ
run: |
- sudo rm -rf /home/ubuntu/2023-naaga
- - name: deploy
+ cd backend
+ docker build --platform linux/arm64/v8 -t ${{ secrets.DOCKERHUB_REPOSITORY }}/${{ secrets.DOCKERHUB_APPNAME }} -f Dockerfile-dev .
+
+ - name: ๐ณ ๋์ปค ํ๋ธ์ Push ์ค... ๐ณ
+ run: docker push ${{ secrets.DOCKERHUB_REPOSITORY }}/${{ secrets.DOCKERHUB_APPNAME }}
+
+ naaga_dev_ec2_deploy:
+ needs: github_actions_setting
+ runs-on: naaga
+
+ steps:
+ - name: ๐ ์ ์คํฌ๋ฆฝํธ ์คํ ์ค ... ๐
run: |
- sudo cp -r /home/ubuntu/actions-runner/naaga/2023-naaga/2023-naaga /home/ubuntu
cd /home/ubuntu
- sudo ./deploy.sh
+ sudo ./deploy_new.sh
+
diff --git a/.github/workflows/backend_prod_merge_workflow.yml b/.github/workflows/backend_prod_merge_workflow.yml
index 9615d5c08..93cc2c7bb 100644
--- a/.github/workflows/backend_prod_merge_workflow.yml
+++ b/.github/workflows/backend_prod_merge_workflow.yml
@@ -6,56 +6,55 @@ on:
- main
paths:
- backend/**
-
+
jobs:
- deploy:
- runs-on: naaga
+ github_actions_setting:
+ runs-on: ubuntu-latest
+
steps:
- - name: change permission
- run: |
- sudo chown -R ubuntu:ubuntu /home/ubuntu/actions-runner/naaga/2023-naaga/2023-naaga
-
- - name: checkout
+ - name: ๐ ํ๋ก์ ํธ ํ์ผ ๊ฐ์ ธ์ค๋ ์ค... ๐
uses: actions/checkout@v3
with:
submodules: true
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
-
- - name: project remove
- run: |
- sudo rm -rf /home/ubuntu/prod/2023-naaga
-
- - name: project copy
- run: |
- sudo cp -r /home/ubuntu/actions-runner/naaga/2023-naaga/2023-naaga /home/ubuntu/prod
- - name: build
+ - name: โ๏ธ ๊นํ๋ธ ์ก์
์ JDK 17 ์ ์ฉ์ํค๋ ์ค... โ๏ธ
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'corretto'
+
+ - name: ๐ Gradle ์ธํ
์ค... ๐
+ uses: gradle/gradle-build-action@v2.6.0
+
+ - name: โ๏ธ Gradle ๋ก JAR ํ์ผ ํ
์คํธ ๋ฐ ๋น๋ ์ค... โ๏ธ
run: |
- cd /home/ubuntu/prod/2023-naaga/backend
- sudo chmod +x ./gradlew
- sudo ./gradlew clean bootJar
-
- - name: transfer & run
+ cd backend
+ ./gradlew clean bootJar -Dspring.profiles.active=test
+
+ - name: ๐ณ ๋์ปค ์ธํ
์ค... ๐ณ
+ uses: docker/setup-buildx-action@v2.9.1
+
+ - name: ๐ณ ๋์ปค ํ๋ธ์ ๋ก๊ทธ์ธ ์ค... ๐ณ
+ uses: docker/login-action@v1
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_ACCESSTOKEN }}
+
+ - name: ๐ณ ๋์ปค ์ด๋ฏธ์ง ๋น๋ ์ค... ๐ณ
run: |
- cd /home/ubuntu/prod
- chmod +x ./deploy_prod.sh
- sudo ./deploy_prod.sh
+ cd backend
+ docker build --platform linux/arm64/v8 -t ${{ secrets.DOCKERHUB_REPOSITORY }}/${{ secrets.DOCKERHUB_APPNAME }} -f Dockerfile-prod .
- sync-dev_backend:
- needs: deploy
+ - name: ๐ณ ๋์ปค ํ๋ธ์ Push ์ค... ๐ณ
+ run: docker push ${{ secrets.DOCKERHUB_REPOSITORY }}/${{ secrets.DOCKERHUB_APPNAME }}
- runs-on: ubuntu-latest
+ naaga_prod_ec2_deploy:
+ needs: github_actions_setting
+ runs-on: naaga
steps:
- - name: Checkout
- uses: actions/checkout@v2
- with:
- ref: main
-
- - name: merge main -> dev_backend
- uses: devmasx/merge-branch@master
- with:
- type: now
- from_branch: main
- target_branch: dev_backend
- github_token: ${{ secrets.GITHUB_TOKEN }}
+ - name: ๐ ์ ์คํฌ๋ฆฝํธ ์คํ ์ค ... ๐
+ run: |
+ cd /home/ubuntu/prod
+ sudo ./deploy_prod.sh
diff --git a/.github/workflows/backend_rel_merge_workflow.yml b/.github/workflows/backend_rel_merge_workflow.yml
index 3ac3a3e3b..cb0cbf714 100644
--- a/.github/workflows/backend_rel_merge_workflow.yml
+++ b/.github/workflows/backend_rel_merge_workflow.yml
@@ -8,53 +8,53 @@ on:
- backend/**
jobs:
- deploy:
- runs-on: naaga
+ github_actions_setting:
+ runs-on: ubuntu-latest
+
steps:
- - name: change permission
- run: |
- sudo chown -R ubuntu:ubuntu /home/ubuntu/actions-runner/naaga/2023-naaga/2023-naaga
-
- - name: checkout
+ - name: ๐ ํ๋ก์ ํธ ํ์ผ ๊ฐ์ ธ์ค๋ ์ค... ๐
uses: actions/checkout@v3
with:
submodules: true
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
-
- - name: project remove
- run: |
- sudo rm -rf /home/ubuntu/prod/2023-naaga
-
- - name: project copy
- run: |
- sudo cp -r /home/ubuntu/actions-runner/naaga/2023-naaga/2023-naaga /home/ubuntu/prod
- - name: build
+ - name: โ๏ธ ๊นํ๋ธ ์ก์
์ JDK 17 ์ ์ฉ์ํค๋ ์ค... โ๏ธ
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'corretto'
+
+ - name: ๐ Gradle ์ธํ
์ค... ๐
+ uses: gradle/gradle-build-action@v2.6.0
+
+ - name: โ๏ธ Gradle ๋ก JAR ํ์ผ ํ
์คํธ ๋ฐ ๋น๋ ์ค... โ๏ธ
run: |
- cd /home/ubuntu/prod/2023-naaga/backend
- sudo chmod +x ./gradlew
- sudo ./gradlew clean bootJar
-
- - name: transfer & run
+ cd backend
+ ./gradlew clean bootJar -Dspring.profiles.active=test
+
+ - name: ๐ณ ๋์ปค ์ธํ
์ค... ๐ณ
+ uses: docker/setup-buildx-action@v2.9.1
+
+ - name: ๐ณ ๋์ปค ํ๋ธ์ ๋ก๊ทธ์ธ ์ค... ๐ณ
+ uses: docker/login-action@v1
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_ACCESSTOKEN }}
+
+ - name: ๐ณ ๋์ปค ์ด๋ฏธ์ง ๋น๋ ์ค... ๐ณ
run: |
- cd /home/ubuntu/prod
- chmod +x ./deploy_prod.sh
- sudo ./deploy_prod.sh
+ cd backend
+ docker build --platform linux/arm64/v8 -t ${{ secrets.DOCKERHUB_REPOSITORY }}/${{ secrets.DOCKERHUB_APPNAME }} -f Dockerfile-prod .
- sync-dev_backend:
- needs: deploy
+ - name: ๐ณ ๋์ปค ํ๋ธ์ Push ์ค... ๐ณ
+ run: docker push ${{ secrets.DOCKERHUB_REPOSITORY }}/${{ secrets.DOCKERHUB_APPNAME }}
- runs-on: ubuntu-latest
+ naaga_prod_ec2_deploy:
+ needs: github_actions_setting
+ runs-on: naaga
steps:
- - name: Checkout
- uses: actions/checkout@v2
- with:
- ref: main
-
- - name: merge release -> dev_backend
- uses: devmasx/merge-branch@master
- with:
- type: now
- target_branch: dev_backend
- github_token: ${{ secrets.GITHUB_TOKEN }}
+ - name: ๐ ์ ์คํฌ๋ฆฝํธ ์คํ ์ค ... ๐
+ run: |
+ cd /home/ubuntu/prod
+ sudo ./deploy_prod.sh
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..f7ca5d749
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 000000000..d40a26a45
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1690700433917
+
+
+ 1690700433917
+
+
+ 1691559894933
+
+
+
+ 1691559894933
+
+
+ 1691560703833
+
+
+
+ 1691560703833
+
+
+ 1691561197101
+
+
+
+ 1691561197101
+
+
+ 1691561397354
+
+
+
+ 1691561397354
+
+
+ 1691561859009
+
+
+
+ 1691561859009
+
+
+ 1691562765815
+
+
+
+ 1691562765816
+
+
+ 1691562780751
+
+
+
+ 1691562780751
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..f5c566453
--- /dev/null
+++ b/README.md
@@ -0,0 +1,16 @@
+![์ ๋ชฉ](etc/images/header.png)
+
+## ๐ ๋์๊ฐ๋ก๋ถํฐ์ ์ด๋์ฅ์ด ๋์ฐฉํ์ต๋๋ค
+
+๋ฐ๋ณต๋๋ ์ธ์คํ ํผ๋๋ฅผ ๋ณด๊ณ , ๊ฒ์์ ํ๋ฉฐ ๋ณด๋ด๋ ์ผ์์ด ์ง๋ฃจํ์ง ์์ผ์๋์?
+๊ณต๋ถ์ ์ผ์ ์น์ฌ ์ค๋ด์์ ๋ณด๋ด๋ ์๊ฐ์ด ๋ง์ ํ
๋ฐ์. ์์ ํ๋ฉด ์์ ๋ฒ์ด๋ ํ์ค ์ธ๊ณ์ ๊ฒฝํ์ ํด๋ณด๊ณ ์ถ์ง ์์ผ์ ๊ฐ์?
+
+๊ทธ๋ฐ ๋น์ ์ โ๋์๊ฐโ๋ก ์ด๋ํฉ๋๋ค.
+
+## ๐ถ๐ป ์ถ๋ฆฌ์ ๋ฐ๊ฑธ์์ ๋ง๋จ
+๋์๊ฐ๋ ํ์ค ์ธ๊ณ๋ฅผ ๋๋น๋ฉฐ ์งํ๋๋ ์ถ๋ฆฌ ๊ฒ์์
๋๋ค. ๊ฒ์์ ์์ํ๋ฉด, ๋น์ ์ฃผ๋ณ ์ด๋๊ฐ์ ์ฌ์ง์ด ์ ๊ณต๋ฉ๋๋ค. ์ฌ์ง์ด ์์ญ๋ฌ์ญํ์ฌ ๊ทธ๊ณณ์ด ์ด๋์ง ์์๋งํ๊ธฐ ์ด๋ ต๊ฒ ์ง๋ง, ์ฐ์ ๋ฐ๊ฑธ์์ ์ฎ๊ฒจ๋ณด์ธ์.
+
+
+
+
+![์์ธ ํ์ด์ง](etc/images/service%20intro.png)
diff --git a/android/app/src/main/res/drawable/rect_radius_small.xml b/android/app/src/main/res/drawable/rect_radius_small.xml
index dadcaab82..c3ca54021 100644
--- a/android/app/src/main/res/drawable/rect_radius_small.xml
+++ b/android/app/src/main/res/drawable/rect_radius_small.xml
@@ -1,5 +1,5 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/android/app/src/test/java/com/now/naaga/UploadViewModelTest.kt b/android/app/src/test/java/com/now/naaga/UploadViewModelTest.kt
index c2caee1c8..6e939569a 100644
--- a/android/app/src/test/java/com/now/naaga/UploadViewModelTest.kt
+++ b/android/app/src/test/java/com/now/naaga/UploadViewModelTest.kt
@@ -1,110 +1,110 @@
-package com.now.naaga
-
-import android.text.Editable
-import androidx.arch.core.executor.testing.InstantTaskExecutorRule
-import com.now.domain.model.Coordinate
-import com.now.domain.model.Place
-import com.now.domain.repository.PlaceRepository
-import com.now.naaga.data.throwable.DataThrowable
-import com.now.naaga.presentation.upload.UploadStatus
-import com.now.naaga.presentation.upload.UploadViewModel
-import io.mockk.coEvery
-import io.mockk.coVerify
-import io.mockk.mockk
-import junit.framework.TestCase.assertEquals
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.resetMain
-import kotlinx.coroutines.test.setMain
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-
-class UploadViewModelTest {
- private lateinit var viewModel: UploadViewModel
- private lateinit var placeRepository: PlaceRepository
-
- // ๋ผ์ด๋ธ๋ฐ์ดํฐ๊ฐ ๋ฉ์ธ ์ค๋ ๋์์ ๋์ํ๋๋ก ํจ
- @get:Rule
- val instantExecutorRule = InstantTaskExecutorRule()
-
- @OptIn(ExperimentalCoroutinesApi::class)
- @Before
- fun setup() {
- Dispatchers.setMain(UnconfinedTestDispatcher())
- placeRepository = mockk()
- viewModel = UploadViewModel(placeRepository)
- }
-
- @OptIn(ExperimentalCoroutinesApi::class)
- @After
- fun tearDown() {
- Dispatchers.resetMain()
- }
-
- private fun String.toEditable(): Editable {
- return Editable.Factory.getInstance().newEditable(this)
- }
-
- @Test
- fun `Coordinate์ด ์
๋ ฅ๋๋ฉด ๋ทฐ๋ชจ๋ธ์ Coordinate๋ ๋ฐ๋๋ค`() {
- // given
- val coordinate = Coordinate(123.4567, 37.890)
-
- // when
- viewModel.setCoordinate(coordinate)
-
- // then
- assertEquals(Coordinate(123.4567, 37.890), viewModel.coordinate.value)
- }
-
- @Test
- fun `๋ฐ์ดํฐ ์ ์ก ์ฑ๊ณต์ successUpload๊ฐ UploadStatus SUCCESS๋ค`() {
- // given
- val coordinate = Coordinate(123.4567, 37.890)
- viewModel.setCoordinate(coordinate)
-
- coEvery {
- placeRepository.postPlace(any(), any(), any(), any())
- } returns (
- Place(
- id = 1,
- name = "krrong",
- coordinate = Coordinate(37.1234, 127.1234),
- image = "https://img.segye.com/content/image/2021/07/29/20210729513138.jpg",
- description = "android",
- )
- )
-
- // when
- viewModel.postPlace()
-
- // Assert: ๊ฒฐ๊ณผ ํ์ธ
- assertEquals(UploadStatus.SUCCESS, viewModel.successUpload.getValue())
- }
-
- @Test
- fun `๋ฐ์ดํฐ ์ ์ก ์คํจ์ successUpload๊ฐ UploadStatus Fail์ด๊ณ ๋ฐํ๋ throwable์ด ์ ์ฅ๋๋ค`() {
- // given
- val coordinate = Coordinate(123.4567, 37.890)
- viewModel.setCoordinate(coordinate)
- val placeThrowable = DataThrowable.PlaceThrowable(505, "Test Failure")
- coEvery { placeRepository.postPlace(any(), any(), any(), any()) } throws placeThrowable
-
- // when
- runBlocking { viewModel.postPlace() }
-
- // then
- // placeRepository.postPlace๊ฐ ์คํ๋์๋์ง ํ์ธ
- coVerify { placeRepository.postPlace(any(), any(), any(), any()) }
-
- // successUpload๊ฐ UploadStatus.Fail ์ธ์ง ํ์ธ
- assertEquals(UploadStatus.FAIL, viewModel.successUpload.getValue())
-
- // ์๋ํ throwable์ด ์ ์ฅ๋์๋์ง ํ์ธ
- assertEquals(placeThrowable, viewModel.throwable.value)
- }
-}
+package com.now.naaga
+
+import android.text.Editable
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.now.domain.model.Coordinate
+import com.now.domain.model.Place
+import com.now.domain.repository.PlaceRepository
+import com.now.naaga.data.throwable.DataThrowable
+import com.now.naaga.presentation.upload.UploadStatus
+import com.now.naaga.presentation.upload.UploadViewModel
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.mockk
+import junit.framework.TestCase.assertEquals
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+class UploadViewModelTest {
+ private lateinit var viewModel: UploadViewModel
+ private lateinit var placeRepository: PlaceRepository
+
+ // ๋ผ์ด๋ธ๋ฐ์ดํฐ๊ฐ ๋ฉ์ธ ์ค๋ ๋์์ ๋์ํ๋๋ก ํจ
+ @get:Rule
+ val instantExecutorRule = InstantTaskExecutorRule()
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Before
+ fun setup() {
+ Dispatchers.setMain(UnconfinedTestDispatcher())
+ placeRepository = mockk()
+ viewModel = UploadViewModel(placeRepository)
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @After
+ fun tearDown() {
+ Dispatchers.resetMain()
+ }
+
+ private fun String.toEditable(): Editable {
+ return Editable.Factory.getInstance().newEditable(this)
+ }
+
+ @Test
+ fun `Coordinate์ด ์
๋ ฅ๋๋ฉด ๋ทฐ๋ชจ๋ธ์ Coordinate๋ ๋ฐ๋๋ค`() {
+ // given
+ val coordinate = Coordinate(123.4567, 37.890)
+
+ // when
+ viewModel.setCoordinate(coordinate)
+
+ // then
+ assertEquals(Coordinate(123.4567, 37.890), viewModel.coordinate.value)
+ }
+
+ @Test
+ fun `๋ฐ์ดํฐ ์ ์ก ์ฑ๊ณต์ successUpload๊ฐ UploadStatus SUCCESS๋ค`() {
+ // given
+ val coordinate = Coordinate(123.4567, 37.890)
+ viewModel.setCoordinate(coordinate)
+
+ coEvery {
+ placeRepository.postPlace(any(), any(), any(), any())
+ } returns (
+ Place(
+ id = 1,
+ name = "krrong",
+ coordinate = Coordinate(37.1234, 127.1234),
+ image = "https://img.segye.com/content/image/2021/07/29/20210729513138.jpg",
+ description = "android",
+ )
+ )
+
+ // when
+ viewModel.postPlace()
+
+ // Assert: ๊ฒฐ๊ณผ ํ์ธ
+ assertEquals(UploadStatus.SUCCESS, viewModel.successUpload.getValue())
+ }
+
+ @Test
+ fun `๋ฐ์ดํฐ ์ ์ก ์คํจ์ successUpload๊ฐ UploadStatus Fail์ด๊ณ ๋ฐํ๋ throwable์ด ์ ์ฅ๋๋ค`() {
+ // given
+ val coordinate = Coordinate(123.4567, 37.890)
+ viewModel.setCoordinate(coordinate)
+ val placeThrowable = DataThrowable.PlaceThrowable(505, "Test Failure")
+ coEvery { placeRepository.postPlace(any(), any(), any(), any()) } throws placeThrowable
+
+ // when
+ runBlocking { viewModel.postPlace() }
+
+ // then
+ // placeRepository.postPlace๊ฐ ์คํ๋์๋์ง ํ์ธ
+ coVerify { placeRepository.postPlace(any(), any(), any(), any()) }
+
+ // successUpload๊ฐ UploadStatus.Fail ์ธ์ง ํ์ธ
+ assertEquals(UploadStatus.FAIL, viewModel.successUpload.getValue())
+
+ // ์๋ํ throwable์ด ์ ์ฅ๋์๋์ง ํ์ธ
+ assertEquals(placeThrowable, viewModel.throwable.value)
+ }
+}
diff --git a/android/gradlew.bat b/android/gradlew.bat
index ac1b06f93..107acd32c 100644
--- a/android/gradlew.bat
+++ b/android/gradlew.bat
@@ -1,89 +1,89 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/backend/Dockerfile b/backend/Dockerfile-dev
similarity index 53%
rename from backend/Dockerfile
rename to backend/Dockerfile-dev
index e390d39c0..e19acaa9a 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile-dev
@@ -4,4 +4,4 @@ WORKDIR /app
COPY build/libs/*.jar /app/naaga-now.jar
-CMD ["java", "-jar", "naaga-now.jar"]
+CMD ["java", "-jar", "-Dspring.profiles.active=dev", "naaga-now.jar"]
diff --git a/backend/Dockerfile-prod b/backend/Dockerfile-prod
new file mode 100644
index 000000000..e0edca8c1
--- /dev/null
+++ b/backend/Dockerfile-prod
@@ -0,0 +1,7 @@
+FROM amazoncorretto:17
+
+WORKDIR /app
+
+COPY build/libs/*.jar /app/naaga-now.jar
+
+CMD ["java", "-jar", "-Dspring.profiles.active=prod", "naaga-now.jar"]
diff --git a/backend/build.gradle b/backend/build.gradle
index 11045f858..0b98200bc 100644
--- a/backend/build.gradle
+++ b/backend/build.gradle
@@ -18,10 +18,6 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
- runtimeOnly 'com.h2database:h2'
- runtimeOnly 'com.mysql:mysql-connector-j'
- testImplementation 'org.springframework.boot:spring-boot-starter-test'
- testImplementation 'io.rest-assured:rest-assured:5.3.1'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
@@ -30,6 +26,14 @@ dependencies {
implementation 'ch.qos.logback.contrib:logback-jackson:0.1.5'
implementation 'ch.qos.logback.contrib:logback-json-classic:0.1.5'
implementation 'net.logstash.logback:logstash-logback-encoder:6.1'
+
+ implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
+
+ runtimeOnly 'com.h2database:h2'
+ runtimeOnly 'com.mysql:mysql-connector-j'
+
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
+ testImplementation 'io.rest-assured:rest-assured:5.3.1'
}
tasks.named('test') {
diff --git a/backend/gradlew.bat b/backend/gradlew.bat
index 6689b85be..93e3f59f1 100644
--- a/backend/gradlew.bat
+++ b/backend/gradlew.bat
@@ -1,92 +1,92 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%"=="" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if %ERRORLEVEL% equ 0 goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-set EXIT_CODE=%ERRORLEVEL%
-if %EXIT_CODE% equ 0 set EXIT_CODE=1
-if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
-exit /b %EXIT_CODE%
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/backend/src/main/java/com/now/naaga/auth/application/AuthService.java b/backend/src/main/java/com/now/naaga/auth/application/AuthService.java
index 4fd9c15f7..e32c7ccab 100644
--- a/backend/src/main/java/com/now/naaga/auth/application/AuthService.java
+++ b/backend/src/main/java/com/now/naaga/auth/application/AuthService.java
@@ -1,17 +1,19 @@
package com.now.naaga.auth.application;
+import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_TOKEN;
+
import com.now.naaga.auth.application.dto.AuthCommand;
-import com.now.naaga.auth.infrastructure.dto.AuthInfo;
import com.now.naaga.auth.application.dto.RefreshTokenCommand;
import com.now.naaga.auth.domain.AuthToken;
import com.now.naaga.auth.exception.AuthException;
import com.now.naaga.auth.infrastructure.AuthClient;
+import com.now.naaga.auth.infrastructure.dto.AuthInfo;
import com.now.naaga.auth.infrastructure.dto.MemberAuth;
import com.now.naaga.auth.infrastructure.jwt.AuthTokenGenerator;
import com.now.naaga.auth.persistence.AuthRepository;
+import com.now.naaga.member.application.MemberService;
import com.now.naaga.member.application.dto.CreateMemberCommand;
import com.now.naaga.member.application.dto.DeleteMemberCommand;
-import com.now.naaga.member.application.MemberService;
import com.now.naaga.member.domain.Member;
import com.now.naaga.player.application.PlayerService;
import com.now.naaga.player.application.dto.CreatePlayerCommand;
@@ -19,8 +21,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_TOKEN;
-
@Transactional
@Service
public class AuthService {
diff --git a/backend/src/main/java/com/now/naaga/auth/domain/AuthToken.java b/backend/src/main/java/com/now/naaga/auth/domain/AuthToken.java
index 90b4bf306..58d9c0cca 100644
--- a/backend/src/main/java/com/now/naaga/auth/domain/AuthToken.java
+++ b/backend/src/main/java/com/now/naaga/auth/domain/AuthToken.java
@@ -1,8 +1,12 @@
package com.now.naaga.auth.domain;
import com.now.naaga.member.domain.Member;
-import jakarta.persistence.*;
-
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
import java.util.Objects;
@Entity
diff --git a/backend/src/main/java/com/now/naaga/auth/infrastructure/AuthClient.java b/backend/src/main/java/com/now/naaga/auth/infrastructure/AuthClient.java
index 593b2ecde..1395b99cd 100644
--- a/backend/src/main/java/com/now/naaga/auth/infrastructure/AuthClient.java
+++ b/backend/src/main/java/com/now/naaga/auth/infrastructure/AuthClient.java
@@ -1,8 +1,8 @@
package com.now.naaga.auth.infrastructure;
-import com.now.naaga.auth.infrastructure.dto.AuthInfo;
import com.now.naaga.auth.exception.AuthException;
import com.now.naaga.auth.exception.AuthExceptionType;
+import com.now.naaga.auth.infrastructure.dto.AuthInfo;
import com.now.naaga.auth.infrastructure.dto.LogoutInfo;
import com.now.naaga.auth.infrastructure.dto.UnlinkInfo;
import org.springframework.beans.factory.annotation.Value;
diff --git a/backend/src/main/java/com/now/naaga/auth/infrastructure/BearerAuthExtractor.java b/backend/src/main/java/com/now/naaga/auth/infrastructure/BearerAuthExtractor.java
index 84cee103f..4f067c548 100644
--- a/backend/src/main/java/com/now/naaga/auth/infrastructure/BearerAuthExtractor.java
+++ b/backend/src/main/java/com/now/naaga/auth/infrastructure/BearerAuthExtractor.java
@@ -1,13 +1,15 @@
package com.now.naaga.auth.infrastructure;
+import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_HEADER;
+import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_TOKEN;
+import static com.now.naaga.auth.exception.AuthExceptionType.NOT_EXIST_HEADER;
+
+import com.now.naaga.auth.exception.AuthException;
import com.now.naaga.auth.infrastructure.dto.MemberAuth;
import com.now.naaga.auth.infrastructure.jwt.JwtProvider;
-import com.now.naaga.auth.exception.AuthException;
import com.now.naaga.common.exception.InternalException;
import org.springframework.stereotype.Component;
-import static com.now.naaga.auth.exception.AuthExceptionType.*;
-
@Component
public class BearerAuthExtractor implements AuthenticationExtractor {
diff --git a/backend/src/main/java/com/now/naaga/auth/infrastructure/MemberAuthMapper.java b/backend/src/main/java/com/now/naaga/auth/infrastructure/MemberAuthMapper.java
index 20765365d..7430af987 100644
--- a/backend/src/main/java/com/now/naaga/auth/infrastructure/MemberAuthMapper.java
+++ b/backend/src/main/java/com/now/naaga/auth/infrastructure/MemberAuthMapper.java
@@ -1,13 +1,13 @@
package com.now.naaga.auth.infrastructure;
+import static com.now.naaga.common.exception.InternalExceptionType.FAIL_JSON_TO_OBJECT;
+import static com.now.naaga.common.exception.InternalExceptionType.FAIL_OBJECT_TO_JSON;
+
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.now.naaga.auth.infrastructure.dto.MemberAuth;
import com.now.naaga.common.exception.InternalException;
-import static com.now.naaga.common.exception.InternalExceptionType.FAIL_JSON_TO_OBJECT;
-import static com.now.naaga.common.exception.InternalExceptionType.FAIL_OBJECT_TO_JSON;
-
public class MemberAuthMapper {
private static final ObjectMapper objectMapper = new ObjectMapper();
diff --git a/backend/src/main/java/com/now/naaga/auth/infrastructure/dto/AuthInfo.java b/backend/src/main/java/com/now/naaga/auth/infrastructure/dto/AuthInfo.java
index 0e4d2bd1d..ecf815eb1 100644
--- a/backend/src/main/java/com/now/naaga/auth/infrastructure/dto/AuthInfo.java
+++ b/backend/src/main/java/com/now/naaga/auth/infrastructure/dto/AuthInfo.java
@@ -2,7 +2,6 @@
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
-
import java.util.Objects;
public class AuthInfo {
diff --git a/backend/src/main/java/com/now/naaga/auth/infrastructure/dto/MemberAuth.java b/backend/src/main/java/com/now/naaga/auth/infrastructure/dto/MemberAuth.java
index fdb4eb29c..74ccd1bf6 100644
--- a/backend/src/main/java/com/now/naaga/auth/infrastructure/dto/MemberAuth.java
+++ b/backend/src/main/java/com/now/naaga/auth/infrastructure/dto/MemberAuth.java
@@ -1,7 +1,6 @@
package com.now.naaga.auth.infrastructure.dto;
import com.now.naaga.auth.infrastructure.AuthType;
-
import java.util.Objects;
public class MemberAuth {
diff --git a/backend/src/main/java/com/now/naaga/auth/infrastructure/jwt/AuthTokenGenerator.java b/backend/src/main/java/com/now/naaga/auth/infrastructure/jwt/AuthTokenGenerator.java
index bdd8f1775..b5733b792 100644
--- a/backend/src/main/java/com/now/naaga/auth/infrastructure/jwt/AuthTokenGenerator.java
+++ b/backend/src/main/java/com/now/naaga/auth/infrastructure/jwt/AuthTokenGenerator.java
@@ -1,27 +1,21 @@
package com.now.naaga.auth.infrastructure.jwt;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_TOKEN_ACCESS;
+
import com.now.naaga.auth.domain.AuthToken;
import com.now.naaga.auth.exception.AuthException;
import com.now.naaga.auth.infrastructure.AuthType;
import com.now.naaga.auth.infrastructure.MemberAuthMapper;
import com.now.naaga.auth.infrastructure.dto.MemberAuth;
-import com.now.naaga.common.exception.InternalException;
-import com.now.naaga.common.exception.InternalExceptionType;
import com.now.naaga.member.domain.Member;
-import org.springframework.stereotype.Component;
-import org.springframework.validation.ObjectError;
-
import java.util.Date;
-
-import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_TOKEN_ACCESS;
+import org.springframework.stereotype.Component;
@Component
public class AuthTokenGenerator {
- private static final long ACCESS_TOKEN_EXPIRE_TIME = 1000 * 60 * 30; // 30๋ถ
- private static final long REFRESH_TOKEN_EXPIRE_TIME = 1000 * 60 * 60 * 24 * 14; // 14์ผ
+ private static final long ACCESS_TOKEN_EXPIRE_TIME = 1000 * 60 * 60 * 24 * 365 * 100; // 100๋
+ private static final long REFRESH_TOKEN_EXPIRE_TIME = 1000 * 60 * 60 * 24 * 365 * 100; // 100๋
private final JwtProvider jwtProvider;
diff --git a/backend/src/main/java/com/now/naaga/auth/infrastructure/jwt/JwtProvider.java b/backend/src/main/java/com/now/naaga/auth/infrastructure/jwt/JwtProvider.java
index b3d5c6966..175a38125 100644
--- a/backend/src/main/java/com/now/naaga/auth/infrastructure/jwt/JwtProvider.java
+++ b/backend/src/main/java/com/now/naaga/auth/infrastructure/jwt/JwtProvider.java
@@ -2,14 +2,16 @@
import com.now.naaga.auth.exception.AuthException;
import com.now.naaga.auth.exception.AuthExceptionType;
-import io.jsonwebtoken.*;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
import java.security.Key;
import java.util.Date;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
@Component
public class JwtProvider {
diff --git a/backend/src/main/java/com/now/naaga/auth/persistence/AuthRepository.java b/backend/src/main/java/com/now/naaga/auth/persistence/AuthRepository.java
index f7c5d6c1b..7be0b62f1 100644
--- a/backend/src/main/java/com/now/naaga/auth/persistence/AuthRepository.java
+++ b/backend/src/main/java/com/now/naaga/auth/persistence/AuthRepository.java
@@ -1,10 +1,8 @@
package com.now.naaga.auth.persistence;
import com.now.naaga.auth.domain.AuthToken;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-import java.util.List;
import java.util.Optional;
+import org.springframework.data.jpa.repository.JpaRepository;
public interface AuthRepository extends JpaRepository {
diff --git a/backend/src/main/java/com/now/naaga/auth/presentation/AuthController.java b/backend/src/main/java/com/now/naaga/auth/presentation/AuthController.java
index 59dca8d07..b13e39511 100644
--- a/backend/src/main/java/com/now/naaga/auth/presentation/AuthController.java
+++ b/backend/src/main/java/com/now/naaga/auth/presentation/AuthController.java
@@ -1,17 +1,21 @@
package com.now.naaga.auth.presentation;
-import com.now.naaga.auth.presentation.annotation.Auth;
import com.now.naaga.auth.application.AuthService;
import com.now.naaga.auth.application.dto.AuthCommand;
import com.now.naaga.auth.application.dto.RefreshTokenCommand;
import com.now.naaga.auth.domain.AuthToken;
import com.now.naaga.auth.infrastructure.dto.MemberAuth;
+import com.now.naaga.auth.presentation.annotation.Auth;
import com.now.naaga.auth.presentation.dto.AuthRequest;
import com.now.naaga.auth.presentation.dto.AuthResponse;
import com.now.naaga.auth.presentation.dto.RefreshTokenRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/auth")
@RestController
diff --git a/backend/src/main/java/com/now/naaga/auth/presentation/argumentresolver/MemberAuthArgumentResolver.java b/backend/src/main/java/com/now/naaga/auth/presentation/argumentresolver/MemberAuthArgumentResolver.java
index f41a9abd1..068a8eca2 100644
--- a/backend/src/main/java/com/now/naaga/auth/presentation/argumentresolver/MemberAuthArgumentResolver.java
+++ b/backend/src/main/java/com/now/naaga/auth/presentation/argumentresolver/MemberAuthArgumentResolver.java
@@ -1,9 +1,8 @@
package com.now.naaga.auth.presentation.argumentresolver;
-import com.now.naaga.auth.presentation.annotation.Auth;
import com.now.naaga.auth.infrastructure.AuthenticationExtractor;
import com.now.naaga.auth.infrastructure.dto.MemberAuth;
-import com.now.naaga.auth.presentation.dto.MemberRequest;
+import com.now.naaga.auth.presentation.annotation.Auth;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
diff --git a/backend/src/main/java/com/now/naaga/auth/presentation/argumentresolver/PlayerArgumentResolver.java b/backend/src/main/java/com/now/naaga/auth/presentation/argumentresolver/PlayerArgumentResolver.java
index 110492546..4353aefcf 100644
--- a/backend/src/main/java/com/now/naaga/auth/presentation/argumentresolver/PlayerArgumentResolver.java
+++ b/backend/src/main/java/com/now/naaga/auth/presentation/argumentresolver/PlayerArgumentResolver.java
@@ -1,8 +1,8 @@
package com.now.naaga.auth.presentation.argumentresolver;
-import com.now.naaga.auth.presentation.annotation.Auth;
import com.now.naaga.auth.infrastructure.AuthenticationExtractor;
import com.now.naaga.auth.infrastructure.dto.MemberAuth;
+import com.now.naaga.auth.presentation.annotation.Auth;
import com.now.naaga.player.application.PlayerService;
import com.now.naaga.player.domain.Player;
import com.now.naaga.player.presentation.dto.PlayerRequest;
diff --git a/backend/src/main/java/com/now/naaga/auth/presentation/interceptor/AuthInterceptor.java b/backend/src/main/java/com/now/naaga/auth/presentation/interceptor/AuthInterceptor.java
index 54cc716dd..6966a5a7c 100644
--- a/backend/src/main/java/com/now/naaga/auth/presentation/interceptor/AuthInterceptor.java
+++ b/backend/src/main/java/com/now/naaga/auth/presentation/interceptor/AuthInterceptor.java
@@ -2,7 +2,6 @@
import com.now.naaga.auth.infrastructure.AuthenticationExtractor;
import com.now.naaga.auth.infrastructure.dto.MemberAuth;
-import com.now.naaga.member.domain.Member;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
diff --git a/backend/src/main/java/com/now/naaga/auth/presentation/interceptor/ManagerAuthInterceptor.java b/backend/src/main/java/com/now/naaga/auth/presentation/interceptor/ManagerAuthInterceptor.java
index 62ffb63c4..85e20f591 100644
--- a/backend/src/main/java/com/now/naaga/auth/presentation/interceptor/ManagerAuthInterceptor.java
+++ b/backend/src/main/java/com/now/naaga/auth/presentation/interceptor/ManagerAuthInterceptor.java
@@ -1,19 +1,20 @@
package com.now.naaga.auth.presentation.interceptor;
+import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_HEADER;
+import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_MANAGER;
+import static com.now.naaga.auth.exception.AuthExceptionType.NOT_EXIST_HEADER;
+
import com.now.naaga.auth.exception.AuthException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.HttpHeaders;
-import org.springframework.stereotype.Component;
-import org.springframework.web.servlet.HandlerInterceptor;
-
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
-
-import static com.now.naaga.auth.exception.AuthExceptionType.*;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class ManagerAuthInterceptor implements HandlerInterceptor {
diff --git a/backend/src/main/java/com/now/naaga/common/config/BeanConfig.java b/backend/src/main/java/com/now/naaga/common/config/BeanConfig.java
index d6ad7c4a4..37d3d9583 100644
--- a/backend/src/main/java/com/now/naaga/common/config/BeanConfig.java
+++ b/backend/src/main/java/com/now/naaga/common/config/BeanConfig.java
@@ -1,10 +1,13 @@
package com.now.naaga.common.config;
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.now.naaga.gameresult.domain.gamescore.FailResultScorePolicy;
import com.now.naaga.gameresult.domain.gamescore.ResultScoreCalculator;
import com.now.naaga.gameresult.domain.gamescore.ResultScorePolicy;
import com.now.naaga.gameresult.domain.gamescore.SuccessResultScorePolicy;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@@ -14,6 +17,9 @@
@Configuration
public class BeanConfig {
+ @Value("${cloud.aws.region.static}")
+ private String clientRegion;
+
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
@@ -42,4 +48,11 @@ public ResultScoreCalculator gameScoreCalculator() {
);
return new ResultScoreCalculator(gameScorePolicies);
}
+
+ @Bean
+ public AmazonS3 amazonS3() {
+ return AmazonS3ClientBuilder.standard()
+ .withRegion(clientRegion)
+ .build();
+ }
}
diff --git a/backend/src/main/java/com/now/naaga/common/config/HibernateConfig.java b/backend/src/main/java/com/now/naaga/common/config/HibernateConfig.java
index f84ef50e0..26af49c82 100644
--- a/backend/src/main/java/com/now/naaga/common/config/HibernateConfig.java
+++ b/backend/src/main/java/com/now/naaga/common/config/HibernateConfig.java
@@ -1,12 +1,12 @@
package com.now.naaga.common.config;
+import static org.hibernate.cfg.AvailableSettings.STATEMENT_INSPECTOR;
+
import com.now.naaga.common.presentation.QueryInspector;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import static org.hibernate.cfg.AvailableSettings.STATEMENT_INSPECTOR;
-
@Configuration
public class HibernateConfig {
diff --git a/backend/src/main/java/com/now/naaga/common/config/WebConfig.java b/backend/src/main/java/com/now/naaga/common/config/WebConfig.java
index 5014a2bcf..20f444f03 100644
--- a/backend/src/main/java/com/now/naaga/common/config/WebConfig.java
+++ b/backend/src/main/java/com/now/naaga/common/config/WebConfig.java
@@ -59,7 +59,8 @@ private HandlerInterceptor mapAuthInterceptor() {
.excludeRequestPattern("/**", HttpMethod.OPTIONS)
.excludeRequestPattern("/temporary-places", HttpMethod.GET)
.excludeRequestPattern("/places", HttpMethod.POST)
- .excludeRequestPattern("/temporary-places/**", HttpMethod.DELETE);
+ .excludeRequestPattern("/temporary-places/**", HttpMethod.DELETE)
+ .excludeRequestPattern("/places/{placeId}/likes/count");
}
private HandlerInterceptor mapManagerAuthInterceptor() {
diff --git a/backend/src/main/java/com/now/naaga/common/domain/BaseEntity.java b/backend/src/main/java/com/now/naaga/common/domain/BaseEntity.java
index 4ee21d732..faa556bda 100644
--- a/backend/src/main/java/com/now/naaga/common/domain/BaseEntity.java
+++ b/backend/src/main/java/com/now/naaga/common/domain/BaseEntity.java
@@ -16,6 +16,7 @@ public abstract class BaseEntity {
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt;
+ // TODO: 10/19/23 ์
๋ฐ์ดํธ ์๊ฐ ์ด๋ํ
์๋๋ ๊ฒ ์์ ํ์
@LastModifiedBy
private LocalDateTime updatedAt;
diff --git a/backend/src/main/java/com/now/naaga/common/exception/CommonExceptionType.java b/backend/src/main/java/com/now/naaga/common/exception/CommonExceptionType.java
index 6d6c8e341..863526174 100644
--- a/backend/src/main/java/com/now/naaga/common/exception/CommonExceptionType.java
+++ b/backend/src/main/java/com/now/naaga/common/exception/CommonExceptionType.java
@@ -21,7 +21,12 @@ public enum CommonExceptionType implements BaseExceptionType {
HttpStatus.BAD_REQUEST,
"ํ์ผ ์ ์ฅํ๋ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค."
),
- ;
+
+ MULTIPART_FILE_NOT_EXIST(
+ 224,
+ HttpStatus.BAD_REQUEST,
+ "์ ์กํ ํ์ผ์ด ๋น์ด์์ต๋๋ค."
+ );
private final int errorCode;
private final HttpStatus httpStatus;
diff --git a/backend/src/main/java/com/now/naaga/common/infrastructure/AwsS3FileManager.java b/backend/src/main/java/com/now/naaga/common/infrastructure/AwsS3FileManager.java
new file mode 100644
index 000000000..225c4f707
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/common/infrastructure/AwsS3FileManager.java
@@ -0,0 +1,69 @@
+package com.now.naaga.common.infrastructure;
+
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.model.DeleteObjectRequest;
+import com.amazonaws.services.s3.model.ObjectMetadata;
+import com.amazonaws.services.s3.model.PutObjectRequest;
+import com.now.naaga.common.exception.CommonException;
+import com.now.naaga.common.exception.CommonExceptionType;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.UUID;
+
+@Component
+public class AwsS3FileManager {
+
+ private static final String FILE_EXTENSION_SEPARATOR = ".";
+
+ private final AmazonS3 amazonS3;
+
+ private final String bucketName;
+
+ public AwsS3FileManager(final AmazonS3 amazonS3,
+ @Value("${cloud.aws.s3.bucket}") final String bucketName) {
+ this.amazonS3 = amazonS3;
+ this.bucketName = bucketName;
+ }
+
+ public String uploadFile(final MultipartFile multipartFile) {
+ validateFileExists(multipartFile);
+ final String fileName = buildFileName(multipartFile.getOriginalFilename());
+ final ObjectMetadata objectMetadata = initializeObjectMetadata(multipartFile);
+
+ try (final InputStream inputStream = multipartFile.getInputStream()) {
+ amazonS3.putObject(new PutObjectRequest(bucketName, fileName, inputStream, objectMetadata));
+ } catch (IOException e) {
+ throw new IllegalArgumentException();
+ }
+
+ return amazonS3.getUrl(bucketName, fileName).toString();
+ }
+
+ private void validateFileExists(final MultipartFile multipartFile) {
+ if (multipartFile.isEmpty()) {
+ throw new CommonException(CommonExceptionType.MULTIPART_FILE_NOT_EXIST);
+ }
+ }
+
+ private String buildFileName(final String originalFileName) {
+ final String extension = originalFileName.substring(originalFileName.lastIndexOf(FILE_EXTENSION_SEPARATOR));
+ return UUID.randomUUID() + extension;
+ }
+
+ private ObjectMetadata initializeObjectMetadata(final MultipartFile multipartFile) {
+ final ObjectMetadata objectMetadata = new ObjectMetadata();
+ objectMetadata.setContentLength(multipartFile.getSize());
+ objectMetadata.setContentType(multipartFile.getContentType());
+ return objectMetadata;
+ }
+
+ //๋ฒ์ ์ด ์ง์ ๋ ๋ฒํท ๊ฐ์ฒด ์ญ์
+ public void deleteFile(String imageUrl) {
+ String fileName = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);
+ amazonS3.deleteObject(new DeleteObjectRequest(bucketName, fileName));
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/common/infrastructure/FileManager.java b/backend/src/main/java/com/now/naaga/common/infrastructure/FileManager.java
deleted file mode 100644
index c7a05e14a..000000000
--- a/backend/src/main/java/com/now/naaga/common/infrastructure/FileManager.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.now.naaga.common.infrastructure;
-
-import java.io.File;
-
-public interface FileManager {
-
- File save(T t);
-
- String convertToUrlPath(File file);
-}
diff --git a/backend/src/main/java/com/now/naaga/common/infrastructure/MultipartFileManager.java b/backend/src/main/java/com/now/naaga/common/infrastructure/MultipartFileManager.java
deleted file mode 100644
index 03dadefa9..000000000
--- a/backend/src/main/java/com/now/naaga/common/infrastructure/MultipartFileManager.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.now.naaga.common.infrastructure;
-
-import com.now.naaga.common.exception.CommonException;
-import com.now.naaga.common.exception.CommonExceptionType;
-import java.io.File;
-import java.io.IOException;
-import java.util.Objects;
-import java.util.UUID;
-
-import com.now.naaga.common.exception.InternalException;
-import com.now.naaga.common.exception.InternalExceptionType;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.springframework.web.multipart.MultipartFile;
-
-import static com.now.naaga.common.exception.CommonExceptionType.INVALID_REQUEST_BODY;
-import static com.now.naaga.common.exception.InternalExceptionType.FAIL_MAKE_DIRECTORY;
-
-@Component
-public class MultipartFileManager implements FileManager {
-
- private final String saveDirectory;
-
- private final String imagesUrlPrefix;
-
- public MultipartFileManager(@Value("${image.path.directory.prefix}") final String saveDirectory,
- @Value("${image.path.url.prefix}") final String imagesUrlPrefix) {
- this.saveDirectory = saveDirectory;
- this.imagesUrlPrefix = imagesUrlPrefix;
- }
-
- @Override
- public File save(final MultipartFile multipartFile) {
- final File directory = new File(saveDirectory);
- if (!directory.exists()) {
- if (directory.mkdirs()) {
- throw new InternalException(FAIL_MAKE_DIRECTORY);
- }
- }
- final String originalFilename = multipartFile.getOriginalFilename();
- if (Objects.isNull(originalFilename)) {
- throw new CommonException(INVALID_REQUEST_BODY);
- }
- final String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
- final String savedFilename = UUID.randomUUID() + extension;
- final File uploadPath = new File(saveDirectory, savedFilename);
- try {
- multipartFile.transferTo(uploadPath);
- } catch (IOException e) {
- throw new CommonException(CommonExceptionType.FILE_SAVE_ERROR);
- }
- return uploadPath;
- }
-
- @Override
- public String convertToUrlPath(final File file) {
- final String filePath = file.toString();
- final String fileNameIncludeDirectorySeparator = filePath.replaceAll(saveDirectory, "");
- return imagesUrlPrefix + fileNameIncludeDirectorySeparator;
- }
-}
diff --git a/backend/src/main/java/com/now/naaga/common/presentation/LogFilter.java b/backend/src/main/java/com/now/naaga/common/presentation/LogFilter.java
index cad62bbd7..acc69107e 100644
--- a/backend/src/main/java/com/now/naaga/common/presentation/LogFilter.java
+++ b/backend/src/main/java/com/now/naaga/common/presentation/LogFilter.java
@@ -1,16 +1,19 @@
package com.now.naaga.common.presentation;
-import jakarta.servlet.*;
+import static com.now.naaga.common.presentation.MdcToken.REQUEST_ID;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
-import java.io.IOException;
-import java.util.UUID;
-
-import static com.now.naaga.common.presentation.MdcToken.*;
-
public class LogFilter implements Filter {
private static final String LOG_FORMAT = "uri: {}, method: {}, time: {}ms, queryCount: {}";
diff --git a/backend/src/main/java/com/now/naaga/common/presentation/QueryInspector.java b/backend/src/main/java/com/now/naaga/common/presentation/QueryInspector.java
index 51e67bba3..216ea91c8 100644
--- a/backend/src/main/java/com/now/naaga/common/presentation/QueryInspector.java
+++ b/backend/src/main/java/com/now/naaga/common/presentation/QueryInspector.java
@@ -1,13 +1,10 @@
package com.now.naaga.common.presentation;
+import java.util.Objects;
import org.hibernate.resource.jdbc.spi.StatementInspector;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
-import java.util.Objects;
-
@Component
public class QueryInspector implements StatementInspector {
diff --git a/backend/src/main/java/com/now/naaga/common/presentation/interceptor/RequestMatcherInterceptor.java b/backend/src/main/java/com/now/naaga/common/presentation/interceptor/RequestMatcherInterceptor.java
index f13c7f3da..ade990797 100644
--- a/backend/src/main/java/com/now/naaga/common/presentation/interceptor/RequestMatcherInterceptor.java
+++ b/backend/src/main/java/com/now/naaga/common/presentation/interceptor/RequestMatcherInterceptor.java
@@ -2,11 +2,10 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.http.HttpMethod;
-import org.springframework.web.servlet.HandlerInterceptor;
-
import java.util.ArrayList;
import java.util.List;
+import org.springframework.http.HttpMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
public class RequestMatcherInterceptor implements HandlerInterceptor {
diff --git a/backend/src/main/java/com/now/naaga/game/application/GameService.java b/backend/src/main/java/com/now/naaga/game/application/GameService.java
index ccfde8e65..d2c4bc3ad 100644
--- a/backend/src/main/java/com/now/naaga/game/application/GameService.java
+++ b/backend/src/main/java/com/now/naaga/game/application/GameService.java
@@ -1,16 +1,29 @@
package com.now.naaga.game.application;
-import com.now.naaga.game.application.dto.*;
-import com.now.naaga.game.domain.*;
+import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
+import static com.now.naaga.game.exception.GameExceptionType.ALREADY_IN_PROGRESS;
+import static com.now.naaga.game.exception.GameExceptionType.CAN_NOT_FIND_PLACE;
+import static com.now.naaga.game.exception.GameExceptionType.NOT_EXIST;
+import static com.now.naaga.game.exception.GameExceptionType.NOT_EXIST_IN_PROGRESS;
+import static com.now.naaga.gameresult.exception.GameResultExceptionType.GAME_RESULT_NOT_EXIST;
+
+import com.now.naaga.game.application.dto.CreateGameCommand;
+import com.now.naaga.game.application.dto.CreateGameResultCommand;
+import com.now.naaga.game.application.dto.EndGameCommand;
+import com.now.naaga.game.application.dto.FindAllGamesCommand;
+import com.now.naaga.game.application.dto.FindGameByIdCommand;
+import com.now.naaga.game.application.dto.FindGameByStatusCommand;
+import com.now.naaga.game.application.dto.FindGameInProgressCommand;
+import com.now.naaga.game.domain.EndType;
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.game.domain.GameRecord;
+import com.now.naaga.game.domain.Statistic;
import com.now.naaga.game.exception.GameException;
import com.now.naaga.game.exception.GameNotFinishedException;
import com.now.naaga.game.repository.GameRepository;
-
-// TODO: 8/31/23 ์ ๊ฑฐํ ๋์ - ์ด์ ๋ฒ์๋ฅผ ๋ฒ์ด๋์ ์ผ๋จ์ ์ ๊ฑฐํ์ง ์์
import com.now.naaga.gameresult.domain.GameResult;
import com.now.naaga.gameresult.exception.GameResultException;
import com.now.naaga.gameresult.repository.GameResultRepository;
-
import com.now.naaga.place.application.PlaceService;
import com.now.naaga.place.application.dto.RecommendPlaceCommand;
import com.now.naaga.place.domain.Place;
@@ -19,32 +32,25 @@
import com.now.naaga.player.application.PlayerService;
import com.now.naaga.player.domain.Player;
import com.now.naaga.player.presentation.dto.PlayerRequest;
+import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static com.now.naaga.game.exception.GameExceptionType.*;
-
-// TODO: 8/31/23 ์ ๊ฑฐํ ๋์ - ์ด์ ๋ฒ์๋ฅผ ๋ฒ์ด๋์ ์ผ๋จ์ ์ ๊ฑฐํ์ง ์์
-import static com.now.naaga.gameresult.exception.GameResultExceptionType.GAME_RESULT_NOT_EXIST;
-
@Transactional
@Service
public class GameService {
-
+
private final GameRepository gameRepository;
-
+
// TODO: 8/31/23 ์ ๊ฑฐํ ๋์ - ์ด์ ๋ฒ์๋ฅผ ๋ฒ์ด๋์ ์ผ๋จ์ ์ ๊ฑฐํ์ง ์์
private final GameResultRepository gameResultRepository;
-
+
private final PlayerService playerService;
-
+
private final PlaceService placeService;
-
+
private final GameFinishService gameFinishService;
-
+
public GameService(final GameRepository gameRepository,
final GameResultRepository gameResultRepository,
final PlayerService playerService,
@@ -56,11 +62,11 @@ public GameService(final GameRepository gameRepository,
this.placeService = placeService;
this.gameFinishService = gameFinishService;
}
-
+
public Game createGame(final CreateGameCommand createGameCommand) {
final Player player = playerService.findPlayerById(createGameCommand.playerId());
final List gamesByStatus = gameRepository.findByPlayerIdAndGameStatus(player.getId(),
- GameStatus.IN_PROGRESS);
+ IN_PROGRESS);
if (!gamesByStatus.isEmpty()) {
throw new GameException(ALREADY_IN_PROGRESS);
}
@@ -74,79 +80,88 @@ public Game createGame(final CreateGameCommand createGameCommand) {
throw new GameException(CAN_NOT_FIND_PLACE);
}
}
-
+
@Transactional(noRollbackFor = {GameNotFinishedException.class})
public void endGame(final EndGameCommand endGameCommand) {
final Game game = gameRepository.findById(endGameCommand.gameId()).orElseThrow(() -> new GameException(NOT_EXIST));
final Player player = playerService.findPlayerById(endGameCommand.playerId());
game.validateOwner(player);
-
+
final EndType endType = endGameCommand.endType();
final Position position = endGameCommand.position();
-
+
game.endGame(position, endType);
-
+
final CreateGameResultCommand createGameResultCommand = new CreateGameResultCommand(player, game, position, endType);
gameFinishService.createGameResult(createGameResultCommand);
}
-
+
@Transactional(readOnly = true)
public Game findGameById(final FindGameByIdCommand findGameByIdCommand) {
final Player player = playerService.findPlayerById(findGameByIdCommand.playerId());
final Game game = gameRepository.findById(findGameByIdCommand.gameId())
- .orElseThrow(() -> new GameException(NOT_EXIST));
+ .orElseThrow(() -> new GameException(NOT_EXIST));
game.validateOwner(player);
return game;
}
-
+
@Transactional(readOnly = true)
public List findGamesByStatus(final FindGameByStatusCommand findGameByStatusCommand) {
Player player = playerService.findPlayerById(findGameByStatusCommand.playerId());
return gameRepository.findByPlayerIdAndGameStatus(player.getId(), findGameByStatusCommand.gameStatus());
}
-
+
@Transactional(readOnly = true)
public GameResult findGameResultByGameId(final Long gameId) {
final List gameResultsByGameId = gameResultRepository.findByGameId(gameId);
-
+
if (gameResultsByGameId.isEmpty()) {
throw new GameResultException(GAME_RESULT_NOT_EXIST);
}
-
+
return gameResultsByGameId.get(0);
}
-
+
@Transactional(readOnly = true)
public GameRecord findGameResult(final Long gameId) {
final GameResult gameResult = findGameResultByGameId(gameId);
return GameRecord.from(gameResult);
}
-
+
@Transactional(readOnly = true)
public List findAllGameResult(final PlayerRequest playerRequest) {
final Long playerId = playerRequest.playerId();
final List gameResults = gameResultRepository.findByPlayerId(playerId);
-
+
final List sortedGameResults = gameResults.stream()
- .sorted((gr1, gr2) -> gr2.getCreatedAt().compareTo(gr1.getCreatedAt()))
- .toList();
-
+ .sorted((gr1, gr2) -> gr2.getCreatedAt().compareTo(gr1.getCreatedAt()))
+ .toList();
+
return sortedGameResults.stream()
- .map(GameRecord::from)
- .toList();
+ .map(GameRecord::from)
+ .toList();
}
-
+
@Transactional(readOnly = true)
public Statistic findStatistic(final PlayerRequest playerRequest) {
final List gameResults = gameResultRepository.findByPlayerId(playerRequest.playerId());
final List gameRecords = gameResults.stream()
- .map(GameRecord::from).toList();
-
+ .map(GameRecord::from).toList();
+
return Statistic.of(gameRecords);
}
-
+
@Transactional(readOnly = true)
public List findAllGames(FindAllGamesCommand findAllGamesCommand) {
return gameRepository.findByPlayerId(findAllGamesCommand.playerId());
}
+
+ @Transactional(readOnly = true)
+ public Game findGameInProgress(final FindGameInProgressCommand findGameByStatusCommand) {
+ List gameInProgress = gameRepository.findByPlayerIdAndGameStatus(findGameByStatusCommand.playerId(), IN_PROGRESS);
+ if (gameInProgress.isEmpty()) {
+ throw new GameException(NOT_EXIST_IN_PROGRESS);
+ }
+ return gameInProgress.get(0);
+ }
}
diff --git a/backend/src/main/java/com/now/naaga/game/application/HintService.java b/backend/src/main/java/com/now/naaga/game/application/HintService.java
index cedb687c9..b4e74cc6d 100644
--- a/backend/src/main/java/com/now/naaga/game/application/HintService.java
+++ b/backend/src/main/java/com/now/naaga/game/application/HintService.java
@@ -1,5 +1,8 @@
package com.now.naaga.game.application;
+import static com.now.naaga.game.exception.GameExceptionType.HINTS_EXHAUSTED;
+import static com.now.naaga.game.exception.GameExceptionType.HINT_NOT_EXIST_IN_GAME;
+
import com.now.naaga.game.application.dto.CreateHintCommand;
import com.now.naaga.game.application.dto.FindGameByIdCommand;
import com.now.naaga.game.application.dto.FindHintByIdCommand;
@@ -13,9 +16,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import static com.now.naaga.game.exception.GameExceptionType.HINTS_EXHAUSTED;
-import static com.now.naaga.game.exception.GameExceptionType.HINT_NOT_EXIST_IN_GAME;
-
@Transactional
@Service
public class HintService {
diff --git a/backend/src/main/java/com/now/naaga/game/application/dto/FindGameInProgressCommand.java b/backend/src/main/java/com/now/naaga/game/application/dto/FindGameInProgressCommand.java
new file mode 100644
index 000000000..584933e40
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/game/application/dto/FindGameInProgressCommand.java
@@ -0,0 +1,4 @@
+package com.now.naaga.game.application.dto;
+
+public record FindGameInProgressCommand(Long playerId) {
+}
diff --git a/backend/src/main/java/com/now/naaga/game/domain/Game.java b/backend/src/main/java/com/now/naaga/game/domain/Game.java
index 2ddb4b9ae..882b74145 100644
--- a/backend/src/main/java/com/now/naaga/game/domain/Game.java
+++ b/backend/src/main/java/com/now/naaga/game/domain/Game.java
@@ -1,5 +1,14 @@
package com.now.naaga.game.domain;
+import static com.now.naaga.game.domain.EndType.ARRIVED;
+import static com.now.naaga.game.domain.EndType.GIVE_UP;
+import static com.now.naaga.game.domain.GameStatus.DONE;
+import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
+import static com.now.naaga.game.exception.GameExceptionType.ALREADY_DONE;
+import static com.now.naaga.game.exception.GameExceptionType.INACCESSIBLE_AUTHENTICATION;
+import static com.now.naaga.game.exception.GameExceptionType.NOT_ARRIVED;
+import static com.now.naaga.game.exception.GameExceptionType.NOT_DONE;
+
import com.now.naaga.common.domain.BaseEntity;
import com.now.naaga.game.exception.GameException;
import com.now.naaga.game.exception.GameExceptionType;
@@ -7,19 +16,24 @@
import com.now.naaga.place.domain.Place;
import com.now.naaga.place.domain.Position;
import com.now.naaga.player.domain.Player;
-import jakarta.persistence.*;
-
+import jakarta.persistence.AttributeOverride;
+import jakarta.persistence.AttributeOverrides;
+import jakarta.persistence.Column;
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-import static com.now.naaga.game.domain.EndType.ARRIVED;
-import static com.now.naaga.game.domain.EndType.GIVE_UP;
-import static com.now.naaga.game.domain.GameStatus.DONE;
-import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
-import static com.now.naaga.game.exception.GameExceptionType.*;
-
@Entity
public class Game extends BaseEntity {
diff --git a/backend/src/main/java/com/now/naaga/game/domain/GameResult.java b/backend/src/main/java/com/now/naaga/game/domain/GameResult.java
deleted file mode 100644
index 3ed81d94e..000000000
--- a/backend/src/main/java/com/now/naaga/game/domain/GameResult.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.now.naaga.game.domain;
-
-import com.now.naaga.common.domain.BaseEntity;
-import com.now.naaga.score.domain.Score;
-import jakarta.persistence.Embedded;
-import jakarta.persistence.Entity;
-import jakarta.persistence.EnumType;
-import jakarta.persistence.Enumerated;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.GenerationType;
-import jakarta.persistence.Id;
-import jakarta.persistence.JoinColumn;
-import jakarta.persistence.OneToOne;
-import java.util.Objects;
-
-@Entity
-public class GameResult extends BaseEntity {
-
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- @Id
- private Long id;
-
- @Enumerated(EnumType.STRING)
- private ResultType resultType;
-
- @Embedded
- private Score score;
-
- @OneToOne
- @JoinColumn(name = "game_id")
- private Game game;
-
- protected GameResult() {
- }
-
- public GameResult(final ResultType resultType,
- final Score score,
- final Game game) {
- this(null, resultType, score, game);
- }
-
- public GameResult(final Long id,
- final ResultType resultType,
- final Score score,
- final Game game) {
- this.id = id;
- this.resultType = resultType;
- this.score = score;
- this.game = game;
- }
-
- public Long getId() {
- return id;
- }
-
- public ResultType getResultType() {
- return resultType;
- }
-
- public Score getScore() {
- return score;
- }
-
- public Game getGame() {
- return game;
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- final GameResult that = (GameResult) o;
- return Objects.equals(id, that.id);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(id);
- }
-
- @Override
- public String toString() {
- return "GameResult{" +
- "id=" + id +
- ", resultType=" + resultType +
- ", score=" + score +
- ", gameId=" + game.getId() +
- '}';
- }
-}
diff --git a/backend/src/main/java/com/now/naaga/game/domain/ResultType.java b/backend/src/main/java/com/now/naaga/game/domain/ResultType.java
deleted file mode 100644
index 83ca772f1..000000000
--- a/backend/src/main/java/com/now/naaga/game/domain/ResultType.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.now.naaga.game.domain;
-
-public enum ResultType {
-
- SUCCESS,
- FAIL,
-}
diff --git a/backend/src/main/java/com/now/naaga/game/domain/Statistic.java b/backend/src/main/java/com/now/naaga/game/domain/Statistic.java
index 214bba3b9..f627145ff 100644
--- a/backend/src/main/java/com/now/naaga/game/domain/Statistic.java
+++ b/backend/src/main/java/com/now/naaga/game/domain/Statistic.java
@@ -1,11 +1,11 @@
package com.now.naaga.game.domain;
-import java.time.Duration;
-import java.util.List;
-
import static com.now.naaga.gameresult.domain.ResultType.FAIL;
import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
+import java.time.Duration;
+import java.util.List;
+
public class Statistic {
private int gameCount;
diff --git a/backend/src/main/java/com/now/naaga/game/domain/gamescore/FailGameScorePolicy.java b/backend/src/main/java/com/now/naaga/game/domain/gamescore/FailGameScorePolicy.java
deleted file mode 100644
index 66c3a6049..000000000
--- a/backend/src/main/java/com/now/naaga/game/domain/gamescore/FailGameScorePolicy.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.now.naaga.game.domain.gamescore;
-
-import com.now.naaga.game.domain.Game;
-import com.now.naaga.game.domain.ResultType;
-import com.now.naaga.score.domain.Score;
-
-import static com.now.naaga.game.domain.ResultType.FAIL;
-
-public class FailGameScorePolicy implements GameScorePolicy {
-
- @Override
- public Score calculate(final Game game) {
- return new Score(0);
- }
-
- @Override
- public boolean hasSameResultType(final ResultType resultType) {
- return resultType == FAIL;
- }
-}
diff --git a/backend/src/main/java/com/now/naaga/game/domain/gamescore/GameScoreCalculator.java b/backend/src/main/java/com/now/naaga/game/domain/gamescore/GameScoreCalculator.java
deleted file mode 100644
index 6e909e05a..000000000
--- a/backend/src/main/java/com/now/naaga/game/domain/gamescore/GameScoreCalculator.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.now.naaga.game.domain.gamescore;
-
-import com.now.naaga.common.exception.InternalException;
-import com.now.naaga.game.domain.Game;
-import com.now.naaga.game.domain.ResultType;
-import com.now.naaga.score.domain.Score;
-
-import java.util.List;
-
-import static com.now.naaga.common.exception.InternalExceptionType.FAIL_ESTABLISH_GAME_SCORE_POLICY;
-
-public class GameScoreCalculator {
-
- private final List scorePolicies;
-
- public GameScoreCalculator(final List scorePolicies) {
- this.scorePolicies = scorePolicies;
- }
-
- public Score calculate(final Game game,
- final ResultType resultType) {
- final GameScorePolicy gameScorePolicy = scorePolicies.stream()
- .filter(policy -> policy.hasSameResultType(resultType))
- .findAny()
- .orElseThrow(() -> new InternalException(FAIL_ESTABLISH_GAME_SCORE_POLICY));
- return gameScorePolicy.calculate(game);
- }
-}
diff --git a/backend/src/main/java/com/now/naaga/game/domain/gamescore/GameScorePolicy.java b/backend/src/main/java/com/now/naaga/game/domain/gamescore/GameScorePolicy.java
deleted file mode 100644
index fd669845a..000000000
--- a/backend/src/main/java/com/now/naaga/game/domain/gamescore/GameScorePolicy.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.now.naaga.game.domain.gamescore;
-
-import com.now.naaga.game.domain.Game;
-import com.now.naaga.game.domain.ResultType;
-import com.now.naaga.score.domain.Score;
-
-public interface GameScorePolicy {
-
- Score calculate(final Game game);
-
- boolean hasSameResultType(final ResultType resultType);
-}
diff --git a/backend/src/main/java/com/now/naaga/game/domain/gamescore/SuccessGameScorePolicy.java b/backend/src/main/java/com/now/naaga/game/domain/gamescore/SuccessGameScorePolicy.java
deleted file mode 100644
index 2eb1e2d54..000000000
--- a/backend/src/main/java/com/now/naaga/game/domain/gamescore/SuccessGameScorePolicy.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.now.naaga.game.domain.gamescore;
-
-import com.now.naaga.game.domain.Game;
-import com.now.naaga.game.domain.ResultType;
-import com.now.naaga.score.domain.Score;
-
-import java.time.Duration;
-import java.time.LocalDateTime;
-
-import static com.now.naaga.game.domain.Game.MAX_ATTEMPT_COUNT;
-import static com.now.naaga.game.domain.Game.MAX_HINT_COUNT;
-import static com.now.naaga.game.domain.ResultType.SUCCESS;
-
-public class SuccessGameScorePolicy implements GameScorePolicy {
-
- private static final Score BASE_SCORE = new Score(50);
- private static final double HINT_SCORE_RATIO = 0.3;
- private static final double ATTEMPT_SCORE_RATIO = 0.3;
- private static final double AVERAGE_SPEED = (double) 10 / 9;
-
- @Override
- public Score calculate(final Game game) {
- return BASE_SCORE
- .plus(calculateHintScore(game))
- .plus(calculateAttemptScore(game))
- .plus(calculateTimeScore(game));
- }
-
- @Override
- public boolean hasSameResultType(final ResultType resultType) {
- return resultType == SUCCESS;
- }
-
- private Score calculateHintScore(final Game game) {
- final int usedHintCount = game.getHints().size();
- final double maxHintScore = BASE_SCORE.getValue() * HINT_SCORE_RATIO;
- final double hintScoreValue = maxHintScore - ((maxHintScore / MAX_HINT_COUNT) * usedHintCount);
- return new Score((int) hintScoreValue);
- }
-
- private Score calculateAttemptScore(final Game game) {
- final int remainingAttempt = game.getRemainingAttempts();
- final int maxPossibleAttempts = MAX_ATTEMPT_COUNT - 1;
- final double maxAttemptScore = BASE_SCORE.getValue() * ATTEMPT_SCORE_RATIO;
- final double attemptScoreValue = maxAttemptScore / maxPossibleAttempts * remainingAttempt;
- return new Score((int) attemptScoreValue);
- }
-
- private Score calculateTimeScore(final Game game) {
- final double distance = game.findDistance();
- final long playTimeInSecond = findDurationInSecond(game);
- final double slope = AVERAGE_SPEED / (distance * BASE_SCORE.getValue());
- final double shiftX = distance / AVERAGE_SPEED;
- final double timeScoreValue = 1 / (slope * (playTimeInSecond + shiftX));
- return new Score((int) timeScoreValue);
- }
-
- private long findDurationInSecond(final Game game) {
- final LocalDateTime startTime = game.getStartTime();
- final LocalDateTime endTime = game.getEndTime();
- final Duration duration = Duration.between(startTime, endTime);
- return duration.toSeconds();
- }
-}
diff --git a/backend/src/main/java/com/now/naaga/game/exception/GameExceptionType.java b/backend/src/main/java/com/now/naaga/game/exception/GameExceptionType.java
index 87df21fa2..27bbb3b75 100644
--- a/backend/src/main/java/com/now/naaga/game/exception/GameExceptionType.java
+++ b/backend/src/main/java/com/now/naaga/game/exception/GameExceptionType.java
@@ -28,6 +28,12 @@ public enum GameExceptionType implements BaseExceptionType {
HttpStatus.BAD_REQUEST,
"๋ฐฐ์ ํ ๋ชฉ์ ์ง๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค."
),
+
+ NOT_EXIST_IN_PROGRESS(
+ 414,
+ HttpStatus.NOT_FOUND,
+ "์งํ ์ค์ธ ๊ฒ์์ด ์กด์ฌํ์ง ์์ต๋๋ค"
+ ),
NOT_ARRIVED(
415,
@@ -47,6 +53,12 @@ public enum GameExceptionType implements BaseExceptionType {
"์์ง ์ข
๋ฃ๋์ง ์์ ๊ฒ์์
๋๋ค."
),
+ NOT_REMAIN_ATTEMPTS(
+ 418,
+ HttpStatus.BAD_REQUEST,
+ "์๋ ํ์๋ฅผ ์ด๋ฏธ ๋ค ์ฌ์ฉํ ๊ฒ์์
๋๋ค"
+ ),
+
HINT_NOT_EXIST_IN_GAME(
454,
HttpStatus.NOT_FOUND,
@@ -58,12 +70,6 @@ public enum GameExceptionType implements BaseExceptionType {
HttpStatus.BAD_REQUEST,
"์ฌ์ฉํ ์ ์๋ ํํธ๋ฅผ ๋ชจ๋ ์์งํ์ต๋๋ค."
),
-
- NOT_REMAIN_ATTEMPTS(
- 418,
- HttpStatus.BAD_REQUEST,
- "์๋ ํ์๋ฅผ ์ด๋ฏธ ๋ค ์ฌ์ฉํ ๊ฒ์์
๋๋ค"
- ),
;
private final int errorCode;
diff --git a/backend/src/main/java/com/now/naaga/game/exception/GameNotArrivalException.java b/backend/src/main/java/com/now/naaga/game/exception/GameNotArrivalException.java
deleted file mode 100644
index 7ce3e9208..000000000
--- a/backend/src/main/java/com/now/naaga/game/exception/GameNotArrivalException.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.now.naaga.game.exception;
-
-public class GameNotArrivalException extends GameException{
-
- public GameNotArrivalException(GameExceptionType gameExceptionType) {
- super(gameExceptionType);
- }
-}
diff --git a/backend/src/main/java/com/now/naaga/game/presentation/GameController.java b/backend/src/main/java/com/now/naaga/game/presentation/GameController.java
index d7f55eb7a..9b5b4bfb7 100644
--- a/backend/src/main/java/com/now/naaga/game/presentation/GameController.java
+++ b/backend/src/main/java/com/now/naaga/game/presentation/GameController.java
@@ -1,24 +1,41 @@
package com.now.naaga.game.presentation;
+import static com.now.naaga.common.exception.CommonExceptionType.INVALID_REQUEST_PARAMETERS;
+
import com.now.naaga.auth.presentation.annotation.Auth;
import com.now.naaga.common.exception.CommonException;
import com.now.naaga.game.application.GameService;
import com.now.naaga.game.application.HintService;
-import com.now.naaga.game.application.dto.*;
+import com.now.naaga.game.application.dto.CreateGameCommand;
+import com.now.naaga.game.application.dto.CreateHintCommand;
+import com.now.naaga.game.application.dto.EndGameCommand;
+import com.now.naaga.game.application.dto.FindAllGamesCommand;
+import com.now.naaga.game.application.dto.FindGameByIdCommand;
+import com.now.naaga.game.application.dto.FindGameByStatusCommand;
+import com.now.naaga.game.application.dto.FindHintByIdCommand;
import com.now.naaga.game.domain.Game;
import com.now.naaga.game.domain.GameRecord;
import com.now.naaga.game.domain.Hint;
-import com.now.naaga.game.presentation.dto.*;
+import com.now.naaga.game.presentation.dto.CoordinateRequest;
+import com.now.naaga.game.presentation.dto.EndGameRequest;
+import com.now.naaga.game.presentation.dto.GameResponse;
+import com.now.naaga.game.presentation.dto.GameResultResponse;
+import com.now.naaga.game.presentation.dto.GameStatusResponse;
+import com.now.naaga.game.presentation.dto.HintResponse;
import com.now.naaga.player.presentation.dto.PlayerRequest;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
-
import java.net.URI;
import java.util.List;
import java.util.stream.Collectors;
-
-import static com.now.naaga.common.exception.CommonExceptionType.INVALID_REQUEST_PARAMETERS;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/games")
@RestController
diff --git a/backend/src/main/java/com/now/naaga/game/repository/GameRepository.java b/backend/src/main/java/com/now/naaga/game/repository/GameRepository.java
index 15423a643..d7f9b1a93 100644
--- a/backend/src/main/java/com/now/naaga/game/repository/GameRepository.java
+++ b/backend/src/main/java/com/now/naaga/game/repository/GameRepository.java
@@ -6,9 +6,9 @@
import org.springframework.data.jpa.repository.JpaRepository;
public interface GameRepository extends JpaRepository {
-
+
List findByPlayerIdAndGameStatus(final Long playerId,
final GameStatus gameStatus);
-
+
List findByPlayerId(Long playerId);
}
diff --git a/backend/src/main/java/com/now/naaga/game/repository/GameResultRepository.java b/backend/src/main/java/com/now/naaga/game/repository/GameResultRepository.java
deleted file mode 100644
index 03dc25d44..000000000
--- a/backend/src/main/java/com/now/naaga/game/repository/GameResultRepository.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.now.naaga.game.repository;
-
-import com.now.naaga.game.domain.GameResult;
-import java.util.List;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-public interface GameResultRepository extends JpaRepository {
-
- List findByGameId(final Long gameId);
-}
diff --git a/backend/src/main/java/com/now/naaga/gameresult/application/GameResultService.java b/backend/src/main/java/com/now/naaga/gameresult/application/GameResultService.java
index 010b295ad..25d739646 100644
--- a/backend/src/main/java/com/now/naaga/gameresult/application/GameResultService.java
+++ b/backend/src/main/java/com/now/naaga/gameresult/application/GameResultService.java
@@ -1,9 +1,9 @@
package com.now.naaga.gameresult.application;
+import com.now.naaga.game.application.GameFinishService;
import com.now.naaga.game.application.dto.CreateGameResultCommand;
import com.now.naaga.game.domain.EndType;
import com.now.naaga.game.domain.Game;
-import com.now.naaga.game.application.GameFinishService;
import com.now.naaga.gameresult.domain.GameResult;
import com.now.naaga.gameresult.domain.ResultType;
import com.now.naaga.gameresult.domain.gamescore.ResultScoreCalculator;
diff --git a/backend/src/main/java/com/now/naaga/gameresult/domain/GameResult.java b/backend/src/main/java/com/now/naaga/gameresult/domain/GameResult.java
index 12b8a9c01..ce6acc9e2 100644
--- a/backend/src/main/java/com/now/naaga/gameresult/domain/GameResult.java
+++ b/backend/src/main/java/com/now/naaga/gameresult/domain/GameResult.java
@@ -3,8 +3,16 @@
import com.now.naaga.common.domain.BaseEntity;
import com.now.naaga.game.domain.Game;
import com.now.naaga.score.domain.Score;
-import jakarta.persistence.*;
-
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToOne;
import java.util.Objects;
@Entity
diff --git a/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/FailResultScorePolicy.java b/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/FailResultScorePolicy.java
index 90a0457ca..5368e1217 100644
--- a/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/FailResultScorePolicy.java
+++ b/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/FailResultScorePolicy.java
@@ -1,11 +1,11 @@
package com.now.naaga.gameresult.domain.gamescore;
+import static com.now.naaga.gameresult.domain.ResultType.FAIL;
+
import com.now.naaga.game.domain.Game;
import com.now.naaga.gameresult.domain.ResultType;
import com.now.naaga.score.domain.Score;
-import static com.now.naaga.gameresult.domain.ResultType.FAIL;
-
public class FailResultScorePolicy implements ResultScorePolicy {
@Override
diff --git a/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/ResultScoreCalculator.java b/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/ResultScoreCalculator.java
index d1db814ef..c8536e948 100644
--- a/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/ResultScoreCalculator.java
+++ b/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/ResultScoreCalculator.java
@@ -1,14 +1,13 @@
package com.now.naaga.gameresult.domain.gamescore;
+import static com.now.naaga.common.exception.InternalExceptionType.FAIL_ESTABLISH_GAME_SCORE_POLICY;
+
import com.now.naaga.common.exception.InternalException;
import com.now.naaga.game.domain.Game;
import com.now.naaga.gameresult.domain.ResultType;
import com.now.naaga.score.domain.Score;
-
import java.util.List;
-import static com.now.naaga.common.exception.InternalExceptionType.FAIL_ESTABLISH_GAME_SCORE_POLICY;
-
public class ResultScoreCalculator {
private final List scorePolicies;
diff --git a/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/SuccessResultScorePolicy.java b/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/SuccessResultScorePolicy.java
index 3827c3d1e..7d5775083 100644
--- a/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/SuccessResultScorePolicy.java
+++ b/backend/src/main/java/com/now/naaga/gameresult/domain/gamescore/SuccessResultScorePolicy.java
@@ -1,16 +1,15 @@
package com.now.naaga.gameresult.domain.gamescore;
+import static com.now.naaga.game.domain.Game.MAX_ATTEMPT_COUNT;
+import static com.now.naaga.game.domain.Game.MAX_HINT_COUNT;
+import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
+
import com.now.naaga.game.domain.Game;
import com.now.naaga.gameresult.domain.ResultType;
import com.now.naaga.score.domain.Score;
-
import java.time.Duration;
import java.time.LocalDateTime;
-import static com.now.naaga.game.domain.Game.MAX_ATTEMPT_COUNT;
-import static com.now.naaga.game.domain.Game.MAX_HINT_COUNT;
-import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
-
public class SuccessResultScorePolicy implements ResultScorePolicy {
private static final Score BASE_SCORE = new Score(50);
diff --git a/backend/src/main/java/com/now/naaga/letter/application/LetterFindService.java b/backend/src/main/java/com/now/naaga/letter/application/LetterFindService.java
new file mode 100644
index 000000000..64e4e0b8b
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/application/LetterFindService.java
@@ -0,0 +1,26 @@
+package com.now.naaga.letter.application;
+
+import com.now.naaga.letter.application.dto.FindLetterByIdCommand;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.exception.LetterException;
+import com.now.naaga.letter.exception.LetterExceptionType;
+import com.now.naaga.letter.repository.LetterRepository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional(readOnly = true)
+@Service
+public class LetterFindService {
+
+ private final LetterRepository letterRepository;
+
+ public LetterFindService(final LetterRepository letterRepository) {
+ this.letterRepository = letterRepository;
+ }
+
+ public Letter findById(FindLetterByIdCommand findLetterByIdCommand) {
+ Long letterId = findLetterByIdCommand.letterId();
+ return letterRepository.findById(letterId)
+ .orElseThrow(() -> new LetterException(LetterExceptionType.NO_EXIST));
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/application/LetterService.java b/backend/src/main/java/com/now/naaga/letter/application/LetterService.java
new file mode 100644
index 000000000..2e930bbe9
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/application/LetterService.java
@@ -0,0 +1,68 @@
+package com.now.naaga.letter.application;
+
+import static com.now.naaga.letter.exception.LetterExceptionType.NO_EXIST;
+
+import com.now.naaga.letter.application.dto.CreateLetterCommand;
+import com.now.naaga.letter.application.letterlog.ReadLetterLogService;
+import com.now.naaga.letter.application.letterlog.WriteLetterLogService;
+import com.now.naaga.letter.application.letterlog.dto.LetterLogCreateCommand;
+import com.now.naaga.letter.application.letterlog.dto.WriteLetterLogCreateCommand;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.exception.LetterException;
+import com.now.naaga.letter.presentation.dto.FindNearByLetterCommand;
+import com.now.naaga.letter.presentation.dto.LetterReadCommand;
+import com.now.naaga.letter.repository.LetterRepository;
+import com.now.naaga.player.application.PlayerService;
+import com.now.naaga.player.domain.Player;
+import java.util.List;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+@Service
+public class LetterService {
+
+ private static final double LETTER_RADIUS = 0.1;
+
+ private final LetterRepository letterRepository;
+
+ private final ReadLetterLogService readLetterLogService;
+
+ private final WriteLetterLogService writeLetterLogService;
+
+ private final PlayerService playerService;
+
+ public LetterService(final LetterRepository letterRepository,
+ final ReadLetterLogService readLetterLogService,
+ final WriteLetterLogService writeLetterLogService,
+ final PlayerService playerService) {
+ this.letterRepository = letterRepository;
+ this.readLetterLogService = readLetterLogService;
+ this.writeLetterLogService = writeLetterLogService;
+ this.playerService = playerService;
+ }
+
+ public Letter findLetter(final LetterReadCommand letterReadCommand) {
+ final Player player = playerService.findPlayerById(letterReadCommand.playerId());
+ final Letter foundLetter = letterRepository.findById(letterReadCommand.letterId())
+ .orElseThrow(() -> new LetterException(NO_EXIST));
+
+ readLetterLogService.log(new LetterLogCreateCommand(player.getId(), foundLetter));
+ return foundLetter;
+ }
+
+ @Transactional(readOnly = true)
+ public List findNearByLetters(final FindNearByLetterCommand findNearByLetterCommand) {
+ return letterRepository.findLetterByPositionAndDistance(findNearByLetterCommand.position(), LETTER_RADIUS);
+ }
+
+ public Letter writeLetter(final CreateLetterCommand createLetterCommand) {
+ final Player player = playerService.findPlayerById(createLetterCommand.playerId());
+ final Letter letter = new Letter(player, createLetterCommand.position(), createLetterCommand.message());
+ letterRepository.save(letter);
+
+ final WriteLetterLogCreateCommand writeLetterLogCreateCommand = new WriteLetterLogCreateCommand(letter.getId());
+ writeLetterLogService.log(writeLetterLogCreateCommand);
+ return letter;
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/application/WriteLetterLogCreateService.java b/backend/src/main/java/com/now/naaga/letter/application/WriteLetterLogCreateService.java
new file mode 100644
index 000000000..1d999e92a
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/application/WriteLetterLogCreateService.java
@@ -0,0 +1,8 @@
+package com.now.naaga.letter.application;
+
+import com.now.naaga.letter.application.letterlog.dto.WriteLetterLogCreateCommand;
+
+public interface WriteLetterLogCreateService {
+
+ void log(WriteLetterLogCreateCommand writeLetterLogCreateCommand);
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/application/dto/CreateLetterCommand.java b/backend/src/main/java/com/now/naaga/letter/application/dto/CreateLetterCommand.java
new file mode 100644
index 000000000..f06815caf
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/application/dto/CreateLetterCommand.java
@@ -0,0 +1,19 @@
+package com.now.naaga.letter.application.dto;
+
+import com.now.naaga.letter.presentation.dto.LetterRequest;
+import com.now.naaga.place.domain.Position;
+import com.now.naaga.player.presentation.dto.PlayerRequest;
+
+public record CreateLetterCommand(Long playerId,
+ String message,
+ Position position) {
+
+ public static CreateLetterCommand of(final PlayerRequest playerRequest,
+ final LetterRequest letterRequest) {
+ final Long playerId = playerRequest.playerId();
+ final Position position = Position.of(letterRequest.latitude(), letterRequest.longitude());
+ return new CreateLetterCommand(playerId,
+ letterRequest.message(),
+ position);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/application/dto/FindLetterByIdCommand.java b/backend/src/main/java/com/now/naaga/letter/application/dto/FindLetterByIdCommand.java
new file mode 100644
index 000000000..fa52b41a1
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/application/dto/FindLetterByIdCommand.java
@@ -0,0 +1,4 @@
+package com.now.naaga.letter.application.dto;
+
+public record FindLetterByIdCommand(Long letterId) {
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/application/letterlog/ReadLetterLogService.java b/backend/src/main/java/com/now/naaga/letter/application/letterlog/ReadLetterLogService.java
new file mode 100644
index 000000000..bd780b0d2
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/application/letterlog/ReadLetterLogService.java
@@ -0,0 +1,52 @@
+package com.now.naaga.letter.application.letterlog;
+
+import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
+
+import com.now.naaga.game.application.GameService;
+import com.now.naaga.game.application.dto.FindGameByIdCommand;
+import com.now.naaga.game.application.dto.FindGameByStatusCommand;
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.game.exception.GameException;
+import com.now.naaga.game.exception.GameExceptionType;
+import com.now.naaga.letter.application.letterlog.dto.LetterByGameCommand;
+import com.now.naaga.letter.application.letterlog.dto.LetterLogCreateCommand;
+import com.now.naaga.letter.domain.letterlog.ReadLetterLog;
+import com.now.naaga.letter.repository.letterlog.ReadLetterLogRepository;
+import java.util.List;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+@Service
+public class ReadLetterLogService {
+
+ private final ReadLetterLogRepository readLetterLogRepository;
+
+ private final GameService gameService;
+
+ public ReadLetterLogService(final ReadLetterLogRepository readLetterLogRepository, final GameService gameService) {
+ this.readLetterLogRepository = readLetterLogRepository;
+ this.gameService = gameService;
+ }
+
+ public List findReadLettersByGameId(final LetterByGameCommand letterByGameCommand) {
+ final FindGameByIdCommand findGameByIdCommand = new FindGameByIdCommand(letterByGameCommand.gameId(), letterByGameCommand.playerId());
+ final Game game = gameService.findGameById(findGameByIdCommand);
+ return readLetterLogRepository.findByGameId(game.getId());
+ }
+
+ public void log(final LetterLogCreateCommand letterLogCreateCommand) {
+ final Game gameInProgress = getGameInProgress(letterLogCreateCommand.playerId());
+ final ReadLetterLog readLetterLog = new ReadLetterLog(gameInProgress, letterLogCreateCommand.letter());
+ readLetterLogRepository.save(readLetterLog);
+ }
+
+ private Game getGameInProgress(final Long playerId) {
+ final FindGameByStatusCommand findGameByStatusCommand = new FindGameByStatusCommand(playerId, IN_PROGRESS);
+ final List gamesInProgress = gameService.findGamesByStatus(findGameByStatusCommand);
+ if (gamesInProgress.isEmpty()) {
+ throw new GameException(GameExceptionType.NOT_EXIST_IN_PROGRESS);
+ }
+ return gamesInProgress.get(0);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/application/letterlog/WriteLetterLogService.java b/backend/src/main/java/com/now/naaga/letter/application/letterlog/WriteLetterLogService.java
new file mode 100644
index 000000000..c63a69839
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/application/letterlog/WriteLetterLogService.java
@@ -0,0 +1,54 @@
+package com.now.naaga.letter.application.letterlog;
+
+import com.now.naaga.game.application.GameService;
+import com.now.naaga.game.application.dto.FindGameByIdCommand;
+import com.now.naaga.game.application.dto.FindGameInProgressCommand;
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.letter.application.LetterFindService;
+import com.now.naaga.letter.application.dto.FindLetterByIdCommand;
+import com.now.naaga.letter.application.letterlog.dto.LetterByGameCommand;
+import com.now.naaga.letter.application.letterlog.dto.WriteLetterLogCreateCommand;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.domain.letterlog.WriteLetterLog;
+import com.now.naaga.letter.repository.letterlog.WriteLetterLogRepository;
+import java.util.List;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+@Service
+public class WriteLetterLogService {
+
+ private final WriteLetterLogRepository writeLetterLogRepository;
+
+ private final LetterFindService letterFindService;
+
+ private final GameService gameService;
+
+ public WriteLetterLogService(final WriteLetterLogRepository writeLetterLogRepository,
+ final LetterFindService letterFindService,
+ final GameService gameService) {
+ this.writeLetterLogRepository = writeLetterLogRepository;
+ this.letterFindService = letterFindService;
+ this.gameService = gameService;
+ }
+
+ public void log(final WriteLetterLogCreateCommand writeLetterLogCreateCommand) {
+ FindLetterByIdCommand findLetterByIdCommand = new FindLetterByIdCommand(writeLetterLogCreateCommand.letterId());
+ Letter letter = letterFindService.findById(findLetterByIdCommand);
+ Game gameInProgress = getGameInProgress(letter.getRegisteredPlayer().getId());
+ final WriteLetterLog writeLetterLog = new WriteLetterLog(gameInProgress, letter);
+ writeLetterLogRepository.save(writeLetterLog);
+ }
+
+ private Game getGameInProgress(final Long playerId) {
+ final FindGameInProgressCommand findGameByStatusCommand = new FindGameInProgressCommand(playerId);
+ return gameService.findGameInProgress(findGameByStatusCommand);
+ }
+
+ public List findWriteLetterByGameId(final LetterByGameCommand letterByGameCommand) {
+ final FindGameByIdCommand findGameByIdCommand = new FindGameByIdCommand(letterByGameCommand.gameId(), letterByGameCommand.playerId());
+ final Game game = gameService.findGameById(findGameByIdCommand);
+ return writeLetterLogRepository.findByGameId(game.getId());
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/application/letterlog/dto/LetterByGameCommand.java b/backend/src/main/java/com/now/naaga/letter/application/letterlog/dto/LetterByGameCommand.java
new file mode 100644
index 000000000..0a2cf04fa
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/application/letterlog/dto/LetterByGameCommand.java
@@ -0,0 +1,13 @@
+package com.now.naaga.letter.application.letterlog.dto;
+
+
+import com.now.naaga.player.presentation.dto.PlayerRequest;
+
+public record LetterByGameCommand(Long playerId,
+ Long gameId) {
+
+ public static LetterByGameCommand of(final PlayerRequest playerRequest,
+ final Long gameId) {
+ return new LetterByGameCommand(playerRequest.playerId(), gameId);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/application/letterlog/dto/LetterLogCreateCommand.java b/backend/src/main/java/com/now/naaga/letter/application/letterlog/dto/LetterLogCreateCommand.java
new file mode 100644
index 000000000..e0b4f54d3
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/application/letterlog/dto/LetterLogCreateCommand.java
@@ -0,0 +1,7 @@
+package com.now.naaga.letter.application.letterlog.dto;
+
+import com.now.naaga.letter.domain.Letter;
+
+public record LetterLogCreateCommand(Long playerId,
+ Letter letter) {
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/application/letterlog/dto/WriteLetterLogCreateCommand.java b/backend/src/main/java/com/now/naaga/letter/application/letterlog/dto/WriteLetterLogCreateCommand.java
new file mode 100644
index 000000000..83071b91c
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/application/letterlog/dto/WriteLetterLogCreateCommand.java
@@ -0,0 +1,4 @@
+package com.now.naaga.letter.application.letterlog.dto;
+
+public record WriteLetterLogCreateCommand(Long letterId) {
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/domain/Letter.java b/backend/src/main/java/com/now/naaga/letter/domain/Letter.java
new file mode 100644
index 000000000..2d644a5d8
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/domain/Letter.java
@@ -0,0 +1,98 @@
+package com.now.naaga.letter.domain;
+
+import com.now.naaga.common.domain.BaseEntity;
+import com.now.naaga.place.domain.Position;
+import com.now.naaga.player.domain.Player;
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import java.time.LocalDateTime;
+import java.util.Objects;
+
+@Entity
+public class Letter extends BaseEntity {
+
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Id
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "player_id")
+ private Player registeredPlayer;
+
+ @Embedded
+ private Position position;
+
+ private String message;
+
+ protected Letter() {
+ }
+
+ public Letter(final Player registeredPlayer,
+ final Position position,
+ final String message) {
+ this(null, registeredPlayer, position, message);
+ }
+
+ public Letter(final Long id,
+ final Player registeredPlayer,
+ final Position position,
+ final String message) {
+ this.id = id;
+ this.registeredPlayer = registeredPlayer;
+ this.position = position;
+ this.message = message;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public Player getRegisteredPlayer() {
+ return registeredPlayer;
+ }
+
+ public Position getPosition() {
+ return position;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public LocalDateTime getCreatedTime() {
+ return super.getCreatedAt();
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Letter letter = (Letter) o;
+ return Objects.equals(id, letter.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+
+ @Override
+ public String toString() {
+ return "Letter{" +
+ "id=" + id +
+ ", playerId=" + registeredPlayer.getId() +
+ ", position=" + position +
+ ", message='" + message +
+ '}';
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/domain/letterlog/ReadLetterLog.java b/backend/src/main/java/com/now/naaga/letter/domain/letterlog/ReadLetterLog.java
new file mode 100644
index 000000000..cc73198cc
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/domain/letterlog/ReadLetterLog.java
@@ -0,0 +1,84 @@
+package com.now.naaga.letter.domain.letterlog;
+
+import com.now.naaga.common.domain.BaseEntity;
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.letter.domain.Letter;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import java.util.Objects;
+
+
+@Entity
+public class ReadLetterLog extends BaseEntity {
+
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Id
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "game_id")
+ private Game game;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "letter_id")
+ private Letter letter;
+
+ protected ReadLetterLog() {
+ }
+
+ public ReadLetterLog(final Game game,
+ final Letter letter) {
+ this(null, game, letter);
+ }
+
+ public ReadLetterLog(final Long id,
+ final Game game,
+ final Letter letter) {
+ this.id = id;
+ this.game = game;
+ this.letter = letter;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public Game getGame() {
+ return game;
+ }
+
+ public Letter getLetter() {
+ return letter;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ReadLetterLog letterLog = (ReadLetterLog) o;
+ return Objects.equals(id, letterLog.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+
+ @Override
+ public String toString() {
+ return "LetterLog{" +
+ "id=" + id +
+ ", gameId=" + game.getId() +
+ ", letterId=" + letter.getId() +
+ '}';
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/domain/letterlog/WriteLetterLog.java b/backend/src/main/java/com/now/naaga/letter/domain/letterlog/WriteLetterLog.java
new file mode 100644
index 000000000..b95899dfb
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/domain/letterlog/WriteLetterLog.java
@@ -0,0 +1,80 @@
+package com.now.naaga.letter.domain.letterlog;
+
+import com.now.naaga.common.domain.BaseEntity;
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.letter.domain.Letter;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToOne;
+import java.util.Objects;
+
+@Entity
+public class WriteLetterLog extends BaseEntity {
+
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Id
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "game_id")
+ private Game game;
+
+ @OneToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "letter_id")
+ private Letter letter;
+
+ protected WriteLetterLog() {
+ }
+
+ public WriteLetterLog(final Game game,
+ final Letter letter) {
+ this(null, game, letter);
+ }
+
+ public WriteLetterLog(final Long id,
+ final Game game,
+ final Letter letter) {
+ this.id = id;
+ this.game = game;
+ this.letter = letter;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public Game getGame() {
+ return game;
+ }
+
+ public Letter getLetter() {
+ return letter;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ WriteLetterLog that = (WriteLetterLog) o;
+ return Objects.equals(id, that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+
+ @Override
+ public String toString() {
+ return "WriteLetterLog{" +
+ "id=" + id +
+ ", gameId=" + game.getId() +
+ ", letterId=" + letter.getId() +
+ '}';
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/exception/LetterException.java b/backend/src/main/java/com/now/naaga/letter/exception/LetterException.java
new file mode 100644
index 000000000..9ee166500
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/exception/LetterException.java
@@ -0,0 +1,18 @@
+package com.now.naaga.letter.exception;
+
+import com.now.naaga.common.exception.BaseException;
+import com.now.naaga.common.exception.BaseExceptionType;
+
+public class LetterException extends BaseException {
+
+ private final LetterExceptionType letterExceptionType;
+
+ public LetterException(final LetterExceptionType letterExceptionType) {
+ this.letterExceptionType = letterExceptionType;
+ }
+
+ @Override
+ public BaseExceptionType exceptionType() {
+ return letterExceptionType;
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/exception/LetterExceptionType.java b/backend/src/main/java/com/now/naaga/letter/exception/LetterExceptionType.java
new file mode 100644
index 000000000..ce1039f04
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/exception/LetterExceptionType.java
@@ -0,0 +1,41 @@
+package com.now.naaga.letter.exception;
+
+import com.now.naaga.common.exception.BaseExceptionType;
+import org.springframework.http.HttpStatus;
+
+public enum LetterExceptionType implements BaseExceptionType {
+
+ NO_EXIST(
+ 604,
+ HttpStatus.NOT_FOUND,
+ "ํด๋น ์ชฝ์ง๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค."
+ ),
+ ;
+
+ private final int errorCode;
+ private final HttpStatus httpStatus;
+ private final String errorMessage;
+
+ LetterExceptionType(final int errorCode,
+ final HttpStatus httpStatus,
+ final String errorMessage) {
+ this.errorCode = errorCode;
+ this.httpStatus = httpStatus;
+ this.errorMessage = errorMessage;
+ }
+
+ @Override
+ public int errorCode() {
+ return errorCode;
+ }
+
+ @Override
+ public HttpStatus httpStatus() {
+ return httpStatus;
+ }
+
+ @Override
+ public String errorMessage() {
+ return errorMessage;
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/presentation/LetterController.java b/backend/src/main/java/com/now/naaga/letter/presentation/LetterController.java
new file mode 100644
index 000000000..af9b288f5
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/presentation/LetterController.java
@@ -0,0 +1,68 @@
+package com.now.naaga.letter.presentation;
+
+import com.now.naaga.auth.presentation.annotation.Auth;
+import com.now.naaga.letter.application.LetterService;
+import com.now.naaga.letter.application.dto.CreateLetterCommand;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.presentation.dto.FindNearByLetterCommand;
+import com.now.naaga.letter.presentation.dto.LetterReadCommand;
+import com.now.naaga.letter.presentation.dto.LetterRequest;
+import com.now.naaga.letter.presentation.dto.LetterResponse;
+import com.now.naaga.letter.presentation.dto.NearByLetterResponse;
+import com.now.naaga.player.presentation.dto.PlayerRequest;
+import java.net.URI;
+import java.util.List;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RequestMapping("/letters")
+@RestController
+public class LetterController {
+
+ private final LetterService letterService;
+
+ public LetterController(final LetterService letterService) {
+ this.letterService = letterService;
+ }
+
+ @PostMapping
+ public ResponseEntity createLetter(@Auth final PlayerRequest playerRequest,
+ @RequestBody final LetterRequest letterRequest) {
+ final CreateLetterCommand createLetterCommand = CreateLetterCommand.of(playerRequest, letterRequest);
+ final Letter letter = letterService.writeLetter(createLetterCommand);
+ return ResponseEntity
+ .status(HttpStatus.CREATED)
+ .location(URI.create("/letters/" + letter.getId()))
+ .body(LetterResponse.from(letter));
+ }
+
+ @GetMapping("/{letterId}")
+ public ResponseEntity findLetterById(@Auth final PlayerRequest playerRequest,
+ @PathVariable final Long letterId) {
+ final LetterReadCommand letterReadCommand = LetterReadCommand.of(playerRequest, letterId);
+ final Letter letter = letterService.findLetter(letterReadCommand);
+ return ResponseEntity
+ .status(HttpStatus.OK)
+ .body(LetterResponse.from(letter));
+ }
+
+ @GetMapping("/nearby")
+ public ResponseEntity> findLetterNearBy(@Auth final PlayerRequest playerRequest,
+ @RequestParam final Double latitude,
+ @RequestParam final Double longitude) {
+ final FindNearByLetterCommand findNearByLetterCommand = FindNearByLetterCommand.from(latitude, longitude);
+
+ final List letters = letterService.findNearByLetters(findNearByLetterCommand);
+ final List nearByLetterResponses = NearByLetterResponse.convertToLetterResponses(letters);
+ return ResponseEntity
+ .status(HttpStatus.OK)
+ .body(nearByLetterResponses);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/presentation/LetterLogController.java b/backend/src/main/java/com/now/naaga/letter/presentation/LetterLogController.java
new file mode 100644
index 000000000..dd07115b2
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/presentation/LetterLogController.java
@@ -0,0 +1,72 @@
+package com.now.naaga.letter.presentation;
+
+import static com.now.naaga.common.exception.CommonExceptionType.INVALID_REQUEST_PARAMETERS;
+import static com.now.naaga.letter.presentation.LogType.READ;
+import static com.now.naaga.letter.presentation.LogType.WRITE;
+
+import com.now.naaga.auth.presentation.annotation.Auth;
+import com.now.naaga.common.exception.CommonException;
+import com.now.naaga.letter.application.letterlog.ReadLetterLogService;
+import com.now.naaga.letter.application.letterlog.WriteLetterLogService;
+import com.now.naaga.letter.application.letterlog.dto.LetterByGameCommand;
+import com.now.naaga.letter.domain.letterlog.ReadLetterLog;
+import com.now.naaga.letter.domain.letterlog.WriteLetterLog;
+import com.now.naaga.letter.presentation.dto.LetterResponse;
+import com.now.naaga.player.presentation.dto.PlayerRequest;
+import java.util.List;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RequestMapping("/letterlogs")
+@RestController
+public class LetterLogController {
+
+ private final ReadLetterLogService readLetterLogService;
+
+ private final WriteLetterLogService writeLetterLogService;
+
+ public LetterLogController(final ReadLetterLogService readLetterLogService,
+ final WriteLetterLogService writeLetterLogService) {
+ this.readLetterLogService = readLetterLogService;
+ this.writeLetterLogService = writeLetterLogService;
+ }
+
+ @GetMapping
+ public ResponseEntity> findLetterInGame(@Auth final PlayerRequest playerRequest,
+ @RequestParam final Long gameId,
+ @RequestParam final String logType) {
+ if (!(READ.name().equalsIgnoreCase(logType) || WRITE.name().equalsIgnoreCase(logType))) {
+ throw new CommonException(INVALID_REQUEST_PARAMETERS);
+ }
+ final LetterByGameCommand letterByGameCommand = LetterByGameCommand.of(playerRequest, gameId);
+
+ if (READ.name().equalsIgnoreCase(logType)) {
+ return findReadLetterByGameId(letterByGameCommand);
+ }
+ return findWriteLetterByGameId(letterByGameCommand);
+ }
+
+ private ResponseEntity> findReadLetterByGameId(final LetterByGameCommand letterByGameCommand) {
+ final List readLetterLogs = readLetterLogService.findReadLettersByGameId(letterByGameCommand);
+ final List readLetterResponses = readLetterLogs.stream()
+ .map(readLetterLog -> LetterResponse.from(readLetterLog.getLetter()))
+ .toList();
+ return ResponseEntity
+ .status(HttpStatus.OK)
+ .body(readLetterResponses);
+ }
+
+ private ResponseEntity> findWriteLetterByGameId(final LetterByGameCommand letterByGameCommand) {
+ final List writeLetterLogs = writeLetterLogService.findWriteLetterByGameId(letterByGameCommand);
+ final List writeLetterResponses = writeLetterLogs.stream()
+ .map(readLetterLog -> LetterResponse.from(readLetterLog.getLetter()))
+ .toList();
+ return ResponseEntity
+ .status(HttpStatus.OK)
+ .body(writeLetterResponses);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/presentation/LogType.java b/backend/src/main/java/com/now/naaga/letter/presentation/LogType.java
new file mode 100644
index 000000000..d584575ea
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/presentation/LogType.java
@@ -0,0 +1,8 @@
+package com.now.naaga.letter.presentation;
+
+public enum LogType {
+
+ READ,
+ WRITE,
+ ;
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/presentation/dto/FindNearByLetterCommand.java b/backend/src/main/java/com/now/naaga/letter/presentation/dto/FindNearByLetterCommand.java
new file mode 100644
index 000000000..32d527413
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/presentation/dto/FindNearByLetterCommand.java
@@ -0,0 +1,12 @@
+package com.now.naaga.letter.presentation.dto;
+
+import com.now.naaga.place.domain.Position;
+import java.math.BigDecimal;
+
+public record FindNearByLetterCommand(Position position) {
+
+ public static FindNearByLetterCommand from(final Double latitude,
+ final Double longitude) {
+ return new FindNearByLetterCommand(new Position(BigDecimal.valueOf(latitude), BigDecimal.valueOf(longitude)));
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/presentation/dto/LetterReadCommand.java b/backend/src/main/java/com/now/naaga/letter/presentation/dto/LetterReadCommand.java
new file mode 100644
index 000000000..4e0616eb0
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/presentation/dto/LetterReadCommand.java
@@ -0,0 +1,13 @@
+package com.now.naaga.letter.presentation.dto;
+
+import com.now.naaga.player.presentation.dto.PlayerRequest;
+
+public record LetterReadCommand(Long playerId,
+ Long letterId) {
+
+ public static LetterReadCommand of(final PlayerRequest playerRequest,
+ final Long letterId) {
+ final Long playerId = playerRequest.playerId();
+ return new LetterReadCommand(playerId, letterId);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/presentation/dto/LetterRequest.java b/backend/src/main/java/com/now/naaga/letter/presentation/dto/LetterRequest.java
new file mode 100644
index 000000000..03af3dc15
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/presentation/dto/LetterRequest.java
@@ -0,0 +1,6 @@
+package com.now.naaga.letter.presentation.dto;
+
+public record LetterRequest(String message,
+ Double latitude,
+ Double longitude) {
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/presentation/dto/LetterResponse.java b/backend/src/main/java/com/now/naaga/letter/presentation/dto/LetterResponse.java
new file mode 100644
index 000000000..9c6a771d2
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/presentation/dto/LetterResponse.java
@@ -0,0 +1,20 @@
+package com.now.naaga.letter.presentation.dto;
+
+import com.now.naaga.game.presentation.dto.CoordinateResponse;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.player.presentation.dto.PlayerResponse;
+
+public record LetterResponse(Long id,
+ PlayerResponse player,
+ CoordinateResponse coordinate,
+ String message,
+ String registerDate) {
+
+ public static LetterResponse from(final Letter letter) {
+ final Long id = letter.getId();
+ final PlayerResponse playerResponse = PlayerResponse.from(letter.getRegisteredPlayer());
+ final CoordinateResponse coordinateResponse = CoordinateResponse.of(letter.getPosition());
+ final String registerDate = letter.getCreatedTime().toString();
+ return new LetterResponse(id, playerResponse, coordinateResponse, letter.getMessage(), registerDate);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/presentation/dto/NearByLetterResponse.java b/backend/src/main/java/com/now/naaga/letter/presentation/dto/NearByLetterResponse.java
new file mode 100644
index 000000000..fa0f1ce2c
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/presentation/dto/NearByLetterResponse.java
@@ -0,0 +1,19 @@
+package com.now.naaga.letter.presentation.dto;
+
+import com.now.naaga.game.presentation.dto.CoordinateResponse;
+import com.now.naaga.letter.domain.Letter;
+import java.util.List;
+
+public record NearByLetterResponse(Long id,
+ CoordinateResponse coordinate) {
+
+ public static NearByLetterResponse from(final Letter letter) {
+ return new NearByLetterResponse(letter.getId(), CoordinateResponse.of(letter.getPosition()));
+ }
+
+ public static List convertToLetterResponses(final List letters) {
+ return letters.stream()
+ .map(NearByLetterResponse::from)
+ .toList();
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/repository/LetterRepository.java b/backend/src/main/java/com/now/naaga/letter/repository/LetterRepository.java
new file mode 100644
index 000000000..24ab1c07d
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/repository/LetterRepository.java
@@ -0,0 +1,19 @@
+package com.now.naaga.letter.repository;
+
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.place.domain.Position;
+import java.util.List;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+public interface LetterRepository extends JpaRepository {
+
+ @Query(value = "SELECT letter FROM Letter letter " +
+ "WHERE ACOS(" +
+ "SIN(RADIANS(:#{#user_position.latitude})) * SIN(RADIANS(letter.position.latitude)) " +
+ "+ (COS(RADIANS(:#{#user_position.latitude})) * COS(RADIANS(letter.position.latitude)) * COS(RADIANS(:#{#user_position.longitude} - letter.position.longitude)))" +
+ ") * 6371.0 <= :distance")
+ List findLetterByPositionAndDistance(@Param(value = "user_position") final Position position,
+ @Param(value = "distance") final double distance);
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/repository/letterlog/ReadLetterLogRepository.java b/backend/src/main/java/com/now/naaga/letter/repository/letterlog/ReadLetterLogRepository.java
new file mode 100644
index 000000000..7a2d47c79
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/repository/letterlog/ReadLetterLogRepository.java
@@ -0,0 +1,10 @@
+package com.now.naaga.letter.repository.letterlog;
+
+import com.now.naaga.letter.domain.letterlog.ReadLetterLog;
+import java.util.List;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface ReadLetterLogRepository extends JpaRepository {
+
+ List findByGameId(Long gamedId);
+}
diff --git a/backend/src/main/java/com/now/naaga/letter/repository/letterlog/WriteLetterLogRepository.java b/backend/src/main/java/com/now/naaga/letter/repository/letterlog/WriteLetterLogRepository.java
new file mode 100644
index 000000000..1af8058e3
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/letter/repository/letterlog/WriteLetterLogRepository.java
@@ -0,0 +1,10 @@
+package com.now.naaga.letter.repository.letterlog;
+
+import com.now.naaga.letter.domain.letterlog.WriteLetterLog;
+import java.util.List;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface WriteLetterLogRepository extends JpaRepository {
+
+ List findByGameId(Long gamedId);
+}
diff --git a/backend/src/main/java/com/now/naaga/like/application/PlaceLikeService.java b/backend/src/main/java/com/now/naaga/like/application/PlaceLikeService.java
new file mode 100644
index 000000000..1ab9531af
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/application/PlaceLikeService.java
@@ -0,0 +1,128 @@
+package com.now.naaga.like.application;
+
+import com.now.naaga.like.application.dto.ApplyLikeCommand;
+import com.now.naaga.like.application.dto.CancelLikeCommand;
+import com.now.naaga.like.application.dto.CheckMyPlaceLikeCommand;
+import com.now.naaga.like.application.dto.CountPlaceLikeCommand;
+import com.now.naaga.like.domain.MyPlaceLikeType;
+import com.now.naaga.like.domain.PlaceLike;
+import com.now.naaga.like.domain.PlaceLikeType;
+import com.now.naaga.like.exception.PlaceLikeException;
+import com.now.naaga.like.exception.PlaceLikeExceptionType;
+import com.now.naaga.like.repository.PlaceLikeRepository;
+import com.now.naaga.place.application.PlaceService;
+import com.now.naaga.place.application.PlaceStatisticsService;
+import com.now.naaga.place.application.dto.FindPlaceByIdCommand;
+import com.now.naaga.place.application.dto.FindPlaceStatisticsByPlaceIdCommand;
+import com.now.naaga.place.application.dto.PlusLikeCommand;
+import com.now.naaga.place.application.dto.SubtractLikeCommand;
+import com.now.naaga.place.domain.Place;
+import com.now.naaga.place.domain.PlaceStatistics;
+import com.now.naaga.player.application.PlayerService;
+import com.now.naaga.player.domain.Player;
+import java.util.Optional;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+@Service
+public class PlaceLikeService {
+
+ private final PlaceLikeRepository placeLikeRepository;
+
+ private final PlaceStatisticsService placeStatisticsService;
+
+ private final PlayerService playerService;
+
+ private final PlaceService placeService;
+
+ public PlaceLikeService(final PlaceLikeRepository placeLikeRepository,
+ final PlaceStatisticsService placeStatisticsService,
+ final PlayerService playerService,
+ final PlaceService placeService) {
+ this.placeLikeRepository = placeLikeRepository;
+ this.placeStatisticsService = placeStatisticsService;
+ this.playerService = playerService;
+ this.placeService = placeService;
+ }
+
+ public PlaceLike applyLike(final ApplyLikeCommand applyLikeCommand) {
+ final Long playerId = applyLikeCommand.playerId();
+ final Long placeId = applyLikeCommand.placeId();
+ final PlaceLikeType placeLikeType = applyLikeCommand.placeLikeType();
+
+ if (placeLikeType == PlaceLikeType.LIKE) {
+ placeStatisticsService.plusLike(new PlusLikeCommand(placeId));
+ }
+
+ final Optional maybePlaceLike = placeLikeRepository.findByPlaceIdAndPlayerId(placeId, playerId);
+
+ if (maybePlaceLike.isPresent()) {
+ final PlaceLike exsistingPlaceLike = maybePlaceLike.get();
+ return updatePlaceLike(exsistingPlaceLike, placeLikeType);
+ }
+
+ return createPlaceLike(playerId, placeId, placeLikeType);
+ }
+
+ private PlaceLike updatePlaceLike(final PlaceLike target,
+ final PlaceLikeType toBeChanged) {
+ if (target.getType() == toBeChanged) {
+ throw new PlaceLikeException(PlaceLikeExceptionType.ALREADY_APPLIED_TYPE);
+ }
+ if (toBeChanged == PlaceLikeType.DISLIKE) {
+ placeStatisticsService.subtractLike(new SubtractLikeCommand(target.getPlace().getId()));
+ }
+ target.switchType();
+ return target;
+ }
+
+ private PlaceLike createPlaceLike(final Long playerId,
+ final Long placeId,
+ final PlaceLikeType placeLikeType) {
+ final Player player = playerService.findPlayerById(playerId);
+ final Place place = placeService.findPlaceById(new FindPlaceByIdCommand(placeId));
+ return placeLikeRepository.save(new PlaceLike(place, player, placeLikeType));
+ }
+
+ public void cancelLike(final CancelLikeCommand cancelLikeCommand) {
+ final Long playerId = cancelLikeCommand.playerId();
+ final Long placeId = cancelLikeCommand.placeId();
+
+ final Optional maybePlaceLike = placeLikeRepository.findByPlaceIdAndPlayerId(placeId, playerId);
+ if (maybePlaceLike.isEmpty()) {
+ return;
+ }
+
+ final PlaceLike placeLike = maybePlaceLike.get();
+ placeLikeRepository.delete(placeLike);
+
+ subtractPlaceLikeCount(placeId, placeLike);
+ }
+
+ private void subtractPlaceLikeCount(final Long placeId, final PlaceLike placeLike) {
+ if (placeLike.getType() == PlaceLikeType.LIKE) {
+ final SubtractLikeCommand subtractLikeCommand = new SubtractLikeCommand(placeId);
+ placeStatisticsService.subtractLike(subtractLikeCommand);
+ }
+ }
+
+ @Transactional(readOnly = true)
+ public MyPlaceLikeType checkMyLike(final CheckMyPlaceLikeCommand checkMyPlaceLikeCommand) {
+ final Long playerId = checkMyPlaceLikeCommand.playerId();
+ final Long placeId = checkMyPlaceLikeCommand.placeId();
+
+ return placeLikeRepository.findByPlaceIdAndPlayerId(placeId, playerId)
+ .map(PlaceLike::getType)
+ .map(MyPlaceLikeType::from)
+ .orElse(MyPlaceLikeType.NONE);
+ }
+
+ @Transactional(readOnly = true)
+ public Long countPlaceLike(final CountPlaceLikeCommand countPlaceLikeCommand) {
+ final FindPlaceStatisticsByPlaceIdCommand findPlaceStatisticsByPlaceIdCommand = new FindPlaceStatisticsByPlaceIdCommand(countPlaceLikeCommand.placeId());
+ final PlaceStatistics placeStatistics = placeStatisticsService.findPlaceStatisticsByPlaceId(findPlaceStatisticsByPlaceIdCommand);
+
+ return placeStatistics.getLikeCount();
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/like/application/dto/ApplyLikeCommand.java b/backend/src/main/java/com/now/naaga/like/application/dto/ApplyLikeCommand.java
new file mode 100644
index 000000000..812181ea0
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/application/dto/ApplyLikeCommand.java
@@ -0,0 +1,16 @@
+package com.now.naaga.like.application.dto;
+
+import com.now.naaga.like.domain.PlaceLikeType;
+import com.now.naaga.like.presentation.dto.ApplyPlaceLikeRequest;
+import com.now.naaga.player.presentation.dto.PlayerRequest;
+
+public record ApplyLikeCommand(Long playerId,
+ Long placeId,
+ PlaceLikeType placeLikeType) {
+
+ public static ApplyLikeCommand of(final PlayerRequest playerRequest,
+ final Long placeId,
+ final ApplyPlaceLikeRequest applyPlaceLikeRequest) {
+ return new ApplyLikeCommand(playerRequest.playerId(), placeId, applyPlaceLikeRequest.type());
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/like/application/dto/CancelLikeCommand.java b/backend/src/main/java/com/now/naaga/like/application/dto/CancelLikeCommand.java
new file mode 100644
index 000000000..df25ec1c0
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/application/dto/CancelLikeCommand.java
@@ -0,0 +1,11 @@
+package com.now.naaga.like.application.dto;
+
+import com.now.naaga.player.presentation.dto.PlayerRequest;
+
+public record CancelLikeCommand(Long playerId,
+ Long placeId) {
+
+ public static CancelLikeCommand of(final PlayerRequest playerRequest, final Long placeId) {
+ return new CancelLikeCommand(playerRequest.playerId(), placeId);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/like/application/dto/CheckMyPlaceLikeCommand.java b/backend/src/main/java/com/now/naaga/like/application/dto/CheckMyPlaceLikeCommand.java
new file mode 100644
index 000000000..75d79c847
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/application/dto/CheckMyPlaceLikeCommand.java
@@ -0,0 +1,13 @@
+package com.now.naaga.like.application.dto;
+
+import com.now.naaga.player.presentation.dto.PlayerRequest;
+
+public record CheckMyPlaceLikeCommand(Long playerId,
+ Long placeId) {
+
+ public static CheckMyPlaceLikeCommand of(final PlayerRequest playerRequest,
+ final Long placeId) {
+ return new CheckMyPlaceLikeCommand(playerRequest.playerId(),
+ placeId);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/like/application/dto/CountPlaceLikeCommand.java b/backend/src/main/java/com/now/naaga/like/application/dto/CountPlaceLikeCommand.java
new file mode 100644
index 000000000..932a0ead2
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/application/dto/CountPlaceLikeCommand.java
@@ -0,0 +1,4 @@
+package com.now.naaga.like.application.dto;
+
+public record CountPlaceLikeCommand(Long placeId) {
+}
diff --git a/backend/src/main/java/com/now/naaga/like/domain/MyPlaceLikeType.java b/backend/src/main/java/com/now/naaga/like/domain/MyPlaceLikeType.java
new file mode 100644
index 000000000..4afdaf4ac
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/domain/MyPlaceLikeType.java
@@ -0,0 +1,13 @@
+package com.now.naaga.like.domain;
+
+public enum MyPlaceLikeType {
+
+ LIKE,
+ DISLIKE,
+ NONE,
+ ;
+
+ public static MyPlaceLikeType from(final PlaceLikeType placeLikeType) {
+ return MyPlaceLikeType.valueOf(placeLikeType.name());
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/like/domain/PlaceLike.java b/backend/src/main/java/com/now/naaga/like/domain/PlaceLike.java
index 744ed121b..73bf1ac91 100644
--- a/backend/src/main/java/com/now/naaga/like/domain/PlaceLike.java
+++ b/backend/src/main/java/com/now/naaga/like/domain/PlaceLike.java
@@ -1,11 +1,14 @@
package com.now.naaga.like.domain;
import com.now.naaga.common.domain.BaseEntity;
+import com.now.naaga.like.exception.PlaceLikeException;
+import com.now.naaga.like.exception.PlaceLikeExceptionType;
import com.now.naaga.place.domain.Place;
import com.now.naaga.player.domain.Player;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
+import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@@ -13,7 +16,6 @@
import jakarta.persistence.ManyToOne;
import java.util.Objects;
-// ์์ง ๋ฏธ๊ตฌ์ญ ์์ญ์
๋๋ค. ์ฌ์ค ๋ฐฑ์๋ ๋๋ ํ ๋ฆฌ ๋ณ๊ฒฝ์ ์ํ ๋ณ๊ฒฝ์ฌํญ์
๋๋ค.
@Entity
public class PlaceLike extends BaseEntity {
@@ -21,11 +23,11 @@ public class PlaceLike extends BaseEntity {
@Id
private Long id;
- @ManyToOne
+ @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "place_id")
private Place place;
- @ManyToOne
+ @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "player_id")
private Player player;
@@ -51,6 +53,16 @@ public PlaceLike(final Long id,
this.placeLikeType = placeLikeType;
}
+ public void validateOwner(final Player player) {
+ if (!this.player.equals(player)) {
+ throw new PlaceLikeException(PlaceLikeExceptionType.INACCESSIBLE_AUTHENTICATION);
+ }
+ }
+
+ public void switchType() {
+ this.placeLikeType = this.placeLikeType.switchType();
+ }
+
public Long getId() {
return id;
}
diff --git a/backend/src/main/java/com/now/naaga/like/domain/PlaceLikeType.java b/backend/src/main/java/com/now/naaga/like/domain/PlaceLikeType.java
index e18438bbc..77940326a 100644
--- a/backend/src/main/java/com/now/naaga/like/domain/PlaceLikeType.java
+++ b/backend/src/main/java/com/now/naaga/like/domain/PlaceLikeType.java
@@ -5,4 +5,11 @@ public enum PlaceLikeType {
LIKE,
DISLIKE,
;
+
+ public PlaceLikeType switchType() {
+ if (this == LIKE) {
+ return DISLIKE;
+ }
+ return LIKE;
+ }
}
diff --git a/backend/src/main/java/com/now/naaga/like/exception/PlaceLikeException.java b/backend/src/main/java/com/now/naaga/like/exception/PlaceLikeException.java
new file mode 100644
index 000000000..c2ad8bc82
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/exception/PlaceLikeException.java
@@ -0,0 +1,18 @@
+package com.now.naaga.like.exception;
+
+import com.now.naaga.common.exception.BaseException;
+import com.now.naaga.common.exception.BaseExceptionType;
+
+public class PlaceLikeException extends BaseException {
+
+ private final PlaceLikeExceptionType placeLikeExceptionType;
+
+ public PlaceLikeException(final PlaceLikeExceptionType placeLikeExceptionType) {
+ this.placeLikeExceptionType = placeLikeExceptionType;
+ }
+
+ @Override
+ public BaseExceptionType exceptionType() {
+ return placeLikeExceptionType;
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/like/exception/PlaceLikeExceptionType.java b/backend/src/main/java/com/now/naaga/like/exception/PlaceLikeExceptionType.java
new file mode 100644
index 000000000..88cf5b5b2
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/exception/PlaceLikeExceptionType.java
@@ -0,0 +1,53 @@
+package com.now.naaga.like.exception;
+
+import com.now.naaga.common.exception.BaseExceptionType;
+import org.springframework.http.HttpStatus;
+
+public enum PlaceLikeExceptionType implements BaseExceptionType {
+
+ INACCESSIBLE_AUTHENTICATION(
+ 703,
+ HttpStatus.FORBIDDEN,
+ "์ ๊ทผ ๊ถํ์ด ์๋ ์ข์์/์ซ์ด์์
๋๋ค."
+ ),
+
+ NOT_EXIST(
+ 704,
+ HttpStatus.NOT_FOUND,
+ "์ข์์/์ซ์ด์๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค."
+ ),
+
+ ALREADY_APPLIED_TYPE(
+ 705,
+ HttpStatus.BAD_REQUEST,
+ "์ด๋ฏธ ๋ฑ๋ก๋ ์ข์์/์ซ์ด์ ์
๋๋ค."
+ ),
+ ;
+
+ private final int errorCode;
+ private final HttpStatus httpStatus;
+ private final String errorMessage;
+
+ PlaceLikeExceptionType(final int errorCode,
+ final HttpStatus httpStatus,
+ final String errorMessage) {
+ this.errorCode = errorCode;
+ this.httpStatus = httpStatus;
+ this.errorMessage = errorMessage;
+ }
+
+ @Override
+ public int errorCode() {
+ return errorCode;
+ }
+
+ @Override
+ public HttpStatus httpStatus() {
+ return httpStatus;
+ }
+
+ @Override
+ public String errorMessage() {
+ return errorMessage;
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/like/presentation/PlaceLikeController.java b/backend/src/main/java/com/now/naaga/like/presentation/PlaceLikeController.java
new file mode 100644
index 000000000..d7481783f
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/presentation/PlaceLikeController.java
@@ -0,0 +1,83 @@
+package com.now.naaga.like.presentation;
+
+import com.now.naaga.auth.presentation.annotation.Auth;
+import com.now.naaga.like.application.PlaceLikeService;
+import com.now.naaga.like.application.dto.ApplyLikeCommand;
+import com.now.naaga.like.application.dto.CancelLikeCommand;
+import com.now.naaga.like.application.dto.CheckMyPlaceLikeCommand;
+import com.now.naaga.like.application.dto.CountPlaceLikeCommand;
+import com.now.naaga.like.domain.MyPlaceLikeType;
+import com.now.naaga.like.domain.PlaceLike;
+import com.now.naaga.like.presentation.dto.ApplyPlaceLikeRequest;
+import com.now.naaga.like.presentation.dto.CheckMyPlaceLikeResponse;
+import com.now.naaga.like.presentation.dto.PlaceLikeCountResponse;
+import com.now.naaga.like.presentation.dto.PlaceLikeResponse;
+import com.now.naaga.player.presentation.dto.PlayerRequest;
+import java.net.URI;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RequestMapping("/places/{placeId}/likes")
+@RestController
+public class PlaceLikeController {
+
+ private final PlaceLikeService placeLikeService;
+
+ public PlaceLikeController(final PlaceLikeService placeLikeService) {
+ this.placeLikeService = placeLikeService;
+ }
+
+ @PostMapping
+ public ResponseEntity applyPlaceLike(@Auth PlayerRequest playerRequest,
+ @PathVariable Long placeId,
+ @RequestBody ApplyPlaceLikeRequest applyPlaceLikeRequest) {
+ final ApplyLikeCommand command = ApplyLikeCommand.of(playerRequest,
+ placeId,
+ applyPlaceLikeRequest);
+ final PlaceLike placeLike = placeLikeService.applyLike(command);
+ final PlaceLikeResponse response = PlaceLikeResponse.from(placeLike);
+ return ResponseEntity
+ .status(HttpStatus.CREATED)
+ .location(URI.create("/places/" + placeId + "/likes/my"))
+ .body(response);
+ }
+
+ @DeleteMapping("/my")
+ public ResponseEntity cancelPlaceLike(@Auth PlayerRequest playerRequest,
+ @PathVariable Long placeId) {
+ final CancelLikeCommand cancelLikeCommand = CancelLikeCommand.of(playerRequest, placeId);
+ placeLikeService.cancelLike(cancelLikeCommand);
+ return ResponseEntity
+ .status(HttpStatus.NO_CONTENT)
+ .build();
+ }
+
+ @GetMapping("/my")
+ public ResponseEntity checkMyPlaceLike(@Auth final PlayerRequest playerRequest,
+ @PathVariable final Long placeId) {
+ final CheckMyPlaceLikeCommand command = CheckMyPlaceLikeCommand.of(playerRequest, placeId);
+ final MyPlaceLikeType myPlaceLikeType = placeLikeService.checkMyLike(command);
+ final CheckMyPlaceLikeResponse response = CheckMyPlaceLikeResponse.from(myPlaceLikeType);
+ return ResponseEntity
+ .status(HttpStatus.OK)
+ .body(response);
+ }
+
+ @GetMapping("/count")
+ public ResponseEntity countPlaceLike(@PathVariable Long placeId) {
+ final CountPlaceLikeCommand countPlaceLikeCommand = new CountPlaceLikeCommand(placeId);
+ final Long placeLikeCount = placeLikeService.countPlaceLike(countPlaceLikeCommand);
+
+ final PlaceLikeCountResponse placeLikeCountResponse = new PlaceLikeCountResponse(placeLikeCount);
+ return ResponseEntity
+ .status(HttpStatus.OK)
+ .body(placeLikeCountResponse);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/like/presentation/dto/ApplyPlaceLikeRequest.java b/backend/src/main/java/com/now/naaga/like/presentation/dto/ApplyPlaceLikeRequest.java
new file mode 100644
index 000000000..c4270dfed
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/presentation/dto/ApplyPlaceLikeRequest.java
@@ -0,0 +1,6 @@
+package com.now.naaga.like.presentation.dto;
+
+import com.now.naaga.like.domain.PlaceLikeType;
+
+public record ApplyPlaceLikeRequest(PlaceLikeType type) {
+}
diff --git a/backend/src/main/java/com/now/naaga/like/presentation/dto/CheckMyPlaceLikeResponse.java b/backend/src/main/java/com/now/naaga/like/presentation/dto/CheckMyPlaceLikeResponse.java
new file mode 100644
index 000000000..d71a8b39d
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/presentation/dto/CheckMyPlaceLikeResponse.java
@@ -0,0 +1,10 @@
+package com.now.naaga.like.presentation.dto;
+
+import com.now.naaga.like.domain.MyPlaceLikeType;
+
+public record CheckMyPlaceLikeResponse(MyPlaceLikeType type) {
+
+ public static CheckMyPlaceLikeResponse from(final MyPlaceLikeType myPlaceLikeType) {
+ return new CheckMyPlaceLikeResponse(myPlaceLikeType);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/like/presentation/dto/PlaceLikeCountResponse.java b/backend/src/main/java/com/now/naaga/like/presentation/dto/PlaceLikeCountResponse.java
new file mode 100644
index 000000000..2487f2261
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/presentation/dto/PlaceLikeCountResponse.java
@@ -0,0 +1,4 @@
+package com.now.naaga.like.presentation.dto;
+
+public record PlaceLikeCountResponse(Long placeLikeCount) {
+}
diff --git a/backend/src/main/java/com/now/naaga/like/presentation/dto/PlaceLikeResponse.java b/backend/src/main/java/com/now/naaga/like/presentation/dto/PlaceLikeResponse.java
new file mode 100644
index 000000000..bb918402a
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/like/presentation/dto/PlaceLikeResponse.java
@@ -0,0 +1,17 @@
+package com.now.naaga.like.presentation.dto;
+
+import com.now.naaga.like.domain.PlaceLike;
+import com.now.naaga.like.domain.PlaceLikeType;
+
+public record PlaceLikeResponse(Long id,
+ Long playerId,
+ Long placeId,
+ PlaceLikeType type) {
+
+ public static PlaceLikeResponse from(final PlaceLike placeLike) {
+ return new PlaceLikeResponse(placeLike.getId(),
+ placeLike.getPlayer().getId(),
+ placeLike.getPlace().getId(),
+ placeLike.getType());
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/like/repository/PlaceLikeRepository.java b/backend/src/main/java/com/now/naaga/like/repository/PlaceLikeRepository.java
index 920c754dd..b1376f9d7 100644
--- a/backend/src/main/java/com/now/naaga/like/repository/PlaceLikeRepository.java
+++ b/backend/src/main/java/com/now/naaga/like/repository/PlaceLikeRepository.java
@@ -1,8 +1,11 @@
package com.now.naaga.like.repository;
import com.now.naaga.like.domain.PlaceLike;
+import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PlaceLikeRepository extends JpaRepository {
+ Optional findByPlaceIdAndPlayerId(final Long placeId,
+ final Long playerId);
}
diff --git a/backend/src/main/java/com/now/naaga/member/application/CreateMemberCommand.java b/backend/src/main/java/com/now/naaga/member/application/CreateMemberCommand.java
deleted file mode 100644
index a9b305085..000000000
--- a/backend/src/main/java/com/now/naaga/member/application/CreateMemberCommand.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.now.naaga.member.application;
-
-public record CreateMemberCommand(String email) {
-}
diff --git a/backend/src/main/java/com/now/naaga/member/application/DeleteMemberCommand.java b/backend/src/main/java/com/now/naaga/member/application/DeleteMemberCommand.java
deleted file mode 100644
index 347ede966..000000000
--- a/backend/src/main/java/com/now/naaga/member/application/DeleteMemberCommand.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.now.naaga.member.application;
-
-public record DeleteMemberCommand(Long memberId) {
-}
diff --git a/backend/src/main/java/com/now/naaga/member/domain/Member.java b/backend/src/main/java/com/now/naaga/member/domain/Member.java
index f57ffe742..a8327b525 100644
--- a/backend/src/main/java/com/now/naaga/member/domain/Member.java
+++ b/backend/src/main/java/com/now/naaga/member/domain/Member.java
@@ -1,12 +1,14 @@
package com.now.naaga.member.domain;
import com.now.naaga.common.domain.BaseEntity;
-import jakarta.persistence.*;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import java.util.Objects;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
-import java.util.Objects;
-
@SQLDelete(sql = "UPDATE member SET deleted = true WHERE id = ?")
@Where(clause = "deleted = false")
@Entity
diff --git a/backend/src/main/java/com/now/naaga/place/application/CreatePlaceStatisticsWithPlaceCreateEventHandler.java b/backend/src/main/java/com/now/naaga/place/application/CreatePlaceStatisticsWithPlaceCreateEventHandler.java
new file mode 100644
index 000000000..6726da7b9
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/place/application/CreatePlaceStatisticsWithPlaceCreateEventHandler.java
@@ -0,0 +1,25 @@
+package com.now.naaga.place.application;
+
+import com.now.naaga.place.application.dto.CreatePlaceStatisticsCommand;
+import com.now.naaga.place.domain.PlaceCreateEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class CreatePlaceStatisticsWithPlaceCreateEventHandler {
+
+ private final PlaceStatisticsService placeStatisticsService;
+
+ public CreatePlaceStatisticsWithPlaceCreateEventHandler(final PlaceStatisticsService placeStatisticsService) {
+ this.placeStatisticsService = placeStatisticsService;
+ }
+
+ @Transactional
+ @EventListener
+ public void handle(final PlaceCreateEvent placeCreateEvent) {
+ final Long placeId = placeCreateEvent.placeId();
+ final CreatePlaceStatisticsCommand command = new CreatePlaceStatisticsCommand(placeId);
+ placeStatisticsService.createPlaceStatistics(command);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/place/application/PlaceService.java b/backend/src/main/java/com/now/naaga/place/application/PlaceService.java
index d27464e1a..0b3ec83de 100644
--- a/backend/src/main/java/com/now/naaga/place/application/PlaceService.java
+++ b/backend/src/main/java/com/now/naaga/place/application/PlaceService.java
@@ -8,16 +8,16 @@
import com.now.naaga.place.application.dto.FindPlaceByIdCommand;
import com.now.naaga.place.application.dto.RecommendPlaceCommand;
import com.now.naaga.place.domain.Place;
-import com.now.naaga.place.domain.PlaceCheckService;
+import com.now.naaga.place.domain.PlaceCreateEvent;
import com.now.naaga.place.domain.PlaceRecommendService;
import com.now.naaga.place.domain.Position;
import com.now.naaga.place.domain.SortType;
import com.now.naaga.place.exception.PlaceException;
-import com.now.naaga.place.persistence.repository.PlaceRepository;
+import com.now.naaga.place.repository.PlaceRepository;
import com.now.naaga.player.application.PlayerService;
import com.now.naaga.player.domain.Player;
-import com.now.naaga.temporaryplace.application.TemporaryPlaceService;
import java.util.List;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -29,22 +29,18 @@ public class PlaceService {
private final PlayerService playerService;
- private final TemporaryPlaceService temporaryPlaceService;
-
- private final PlaceCheckService placeCheckService;
-
private final PlaceRecommendService placeRecommendService;
+ private final ApplicationEventPublisher applicationEventPublisher;
+
public PlaceService(final PlaceRepository placeRepository,
final PlayerService playerService,
- final TemporaryPlaceService temporaryPlaceService,
- final PlaceCheckService placeCheckService,
- final PlaceRecommendService placeRecommendService) {
+ final PlaceRecommendService placeRecommendService,
+ final ApplicationEventPublisher applicationEventPublisher) {
this.placeRepository = placeRepository;
this.playerService = playerService;
- this.temporaryPlaceService = temporaryPlaceService;
- this.placeCheckService = placeCheckService;
this.placeRecommendService = placeRecommendService;
+ this.applicationEventPublisher = applicationEventPublisher;
}
@Transactional(readOnly = true)
@@ -69,8 +65,6 @@ public Place recommendPlaceByPosition(final RecommendPlaceCommand recommendPlace
}
public Place createPlace(final CreatePlaceCommand createPlaceCommand) {
- placeCheckService.checkOtherPlaceNearby(createPlaceCommand.position());
-
final Long registeredPlayerId = createPlaceCommand.registeredPlayerId();
final Player registeredPlayer = playerService.findPlayerById(registeredPlayerId);
final Place place = new Place(createPlaceCommand.name(),
@@ -80,7 +74,7 @@ public Place createPlace(final CreatePlaceCommand createPlaceCommand) {
registeredPlayer);
placeRepository.save(place);
- temporaryPlaceService.deleteById(createPlaceCommand.temporaryPlaceId());
+ applicationEventPublisher.publishEvent(new PlaceCreateEvent(createPlaceCommand.temporaryPlaceId(), place.getId()));
return place;
}
}
diff --git a/backend/src/main/java/com/now/naaga/place/application/PlaceStatisticsService.java b/backend/src/main/java/com/now/naaga/place/application/PlaceStatisticsService.java
new file mode 100644
index 000000000..b81e4ab49
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/place/application/PlaceStatisticsService.java
@@ -0,0 +1,64 @@
+package com.now.naaga.place.application;
+
+import static com.now.naaga.place.domain.PlaceStatistics.LIKE_COUNT_DEFAULT_VALUE;
+
+import com.now.naaga.place.application.dto.CreatePlaceStatisticsCommand;
+import com.now.naaga.place.application.dto.FindPlaceByIdCommand;
+import com.now.naaga.place.application.dto.FindPlaceStatisticsByPlaceIdCommand;
+import com.now.naaga.place.application.dto.PlusLikeCommand;
+import com.now.naaga.place.application.dto.SubtractLikeCommand;
+import com.now.naaga.place.domain.Place;
+import com.now.naaga.place.domain.PlaceStatistics;
+import com.now.naaga.place.exception.PlaceException;
+import com.now.naaga.place.exception.PlaceExceptionType;
+import com.now.naaga.place.exception.PlaceStatisticsException;
+import com.now.naaga.place.exception.PlaceStatisticsExceptionType;
+import com.now.naaga.place.repository.PlaceStatisticsRepository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+@Service
+public class PlaceStatisticsService {
+
+ private final PlaceStatisticsRepository placeStatisticsRepository;
+
+ private final PlaceService placeService;
+
+ public PlaceStatisticsService(final PlaceStatisticsRepository placeStatisticsRepository,
+ final PlaceService placeService) {
+ this.placeStatisticsRepository = placeStatisticsRepository;
+ this.placeService = placeService;
+ }
+
+ public PlaceStatistics createPlaceStatistics(final CreatePlaceStatisticsCommand createPlaceStatisticsCommand) {
+ final Long placeId = createPlaceStatisticsCommand.placeId();
+ final Place place = placeService.findPlaceById(new FindPlaceByIdCommand(placeId));
+
+ final PlaceStatistics placeStatistics = new PlaceStatistics(place, LIKE_COUNT_DEFAULT_VALUE);
+ return placeStatisticsRepository.save(placeStatistics);
+ }
+
+ public void plusLike(final PlusLikeCommand plusLikeCommand) {
+ final Long placeId = plusLikeCommand.placeId();
+ final PlaceStatistics placeStatistics = placeStatisticsRepository.findByPlaceId(placeId)
+ .orElseThrow(() -> new PlaceException(PlaceExceptionType.NO_EXIST));
+ placeStatistics.plusLike();
+ }
+
+ public void subtractLike(final SubtractLikeCommand subtractLikeCommand) {
+ final Long placeId = subtractLikeCommand.placeId();
+
+ final PlaceStatistics placeStatistics = placeStatisticsRepository.findByPlaceId(placeId)
+ .orElseThrow(() -> new PlaceStatisticsException(PlaceStatisticsExceptionType.NOT_FOUND));
+
+ placeStatistics.subtractLike();
+ }
+
+ public PlaceStatistics findPlaceStatisticsByPlaceId(final FindPlaceStatisticsByPlaceIdCommand findPlaceStatisticsByPlaceIdCommand) {
+ final Long placeId = findPlaceStatisticsByPlaceIdCommand.placeId();
+
+ return placeStatisticsRepository.findByPlaceId(placeId)
+ .orElseThrow(() -> new PlaceStatisticsException(PlaceStatisticsExceptionType.NOT_FOUND));
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/place/application/dto/CreatePlaceStatisticsCommand.java b/backend/src/main/java/com/now/naaga/place/application/dto/CreatePlaceStatisticsCommand.java
new file mode 100644
index 000000000..5366c66e5
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/place/application/dto/CreatePlaceStatisticsCommand.java
@@ -0,0 +1,4 @@
+package com.now.naaga.place.application.dto;
+
+public record CreatePlaceStatisticsCommand(Long placeId) {
+}
diff --git a/backend/src/main/java/com/now/naaga/place/application/dto/FindPlaceStatisticsByPlaceIdCommand.java b/backend/src/main/java/com/now/naaga/place/application/dto/FindPlaceStatisticsByPlaceIdCommand.java
new file mode 100644
index 000000000..be6546cd8
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/place/application/dto/FindPlaceStatisticsByPlaceIdCommand.java
@@ -0,0 +1,4 @@
+package com.now.naaga.place.application.dto;
+
+public record FindPlaceStatisticsByPlaceIdCommand(Long placeId) {
+}
diff --git a/backend/src/main/java/com/now/naaga/place/application/dto/PlusLikeCommand.java b/backend/src/main/java/com/now/naaga/place/application/dto/PlusLikeCommand.java
new file mode 100644
index 000000000..cfd4b8bc7
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/place/application/dto/PlusLikeCommand.java
@@ -0,0 +1,4 @@
+package com.now.naaga.place.application.dto;
+
+public record PlusLikeCommand(Long placeId) {
+}
diff --git a/backend/src/main/java/com/now/naaga/place/application/dto/SubtractLikeCommand.java b/backend/src/main/java/com/now/naaga/place/application/dto/SubtractLikeCommand.java
new file mode 100644
index 000000000..149043c94
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/place/application/dto/SubtractLikeCommand.java
@@ -0,0 +1,4 @@
+package com.now.naaga.place.application.dto;
+
+public record SubtractLikeCommand(Long placeId) {
+}
diff --git a/backend/src/main/java/com/now/naaga/place/domain/Place.java b/backend/src/main/java/com/now/naaga/place/domain/Place.java
index 6b2682faa..2d8b9882c 100644
--- a/backend/src/main/java/com/now/naaga/place/domain/Place.java
+++ b/backend/src/main/java/com/now/naaga/place/domain/Place.java
@@ -6,8 +6,14 @@
import com.now.naaga.place.exception.PlaceException;
import com.now.naaga.place.exception.PlaceExceptionType;
import com.now.naaga.player.domain.Player;
-import jakarta.persistence.*;
-
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
import java.util.Objects;
@Entity
diff --git a/backend/src/main/java/com/now/naaga/place/domain/PlaceCheckService.java b/backend/src/main/java/com/now/naaga/place/domain/PlaceCheckService.java
deleted file mode 100644
index b44b9ac6e..000000000
--- a/backend/src/main/java/com/now/naaga/place/domain/PlaceCheckService.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.now.naaga.place.domain;
-
-import com.now.naaga.place.exception.PlaceException;
-import com.now.naaga.place.exception.PlaceExceptionType;
-import com.now.naaga.place.persistence.repository.PlaceRepository;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-@Transactional
-@Service
-public class PlaceCheckService {
-
- private final PlaceRepository placeRepository;
-
- public PlaceCheckService(final PlaceRepository placeRepository) {
- this.placeRepository = placeRepository;
- }
-
- @Transactional(readOnly = true)
- public void checkOtherPlaceNearby(final Position position) {
- List places = placeRepository.findPlaceByPositionAndDistance(position, 0.02);
- if (!places.isEmpty()) {
- throw new PlaceException(PlaceExceptionType.ALREADY_EXIST_NEARBY);
- }
- }
-}
diff --git a/backend/src/main/java/com/now/naaga/place/domain/PlaceCreateEvent.java b/backend/src/main/java/com/now/naaga/place/domain/PlaceCreateEvent.java
new file mode 100644
index 000000000..93f2548a2
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/place/domain/PlaceCreateEvent.java
@@ -0,0 +1,5 @@
+package com.now.naaga.place.domain;
+
+public record PlaceCreateEvent(Long temporaryPlaceId,
+ Long placeId) {
+}
diff --git a/backend/src/main/java/com/now/naaga/place/domain/PlaceRecommendService.java b/backend/src/main/java/com/now/naaga/place/domain/PlaceRecommendService.java
index 93060f064..63adfa6a8 100644
--- a/backend/src/main/java/com/now/naaga/place/domain/PlaceRecommendService.java
+++ b/backend/src/main/java/com/now/naaga/place/domain/PlaceRecommendService.java
@@ -1,14 +1,12 @@
package com.now.naaga.place.domain;
-import com.now.naaga.place.exception.PlaceException;
-import com.now.naaga.place.persistence.repository.PlaceRepository;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
+import static com.now.naaga.place.exception.PlaceExceptionType.NO_EXIST;
+import com.now.naaga.place.exception.PlaceException;
+import com.now.naaga.place.repository.PlaceRepository;
import java.util.List;
import java.util.Random;
-
-import static com.now.naaga.place.exception.PlaceExceptionType.NO_EXIST;
+import org.springframework.stereotype.Service;
@Service
public class PlaceRecommendService {
diff --git a/backend/src/main/java/com/now/naaga/placestatistics/PlaceStatistics.java b/backend/src/main/java/com/now/naaga/place/domain/PlaceStatistics.java
similarity index 79%
rename from backend/src/main/java/com/now/naaga/placestatistics/PlaceStatistics.java
rename to backend/src/main/java/com/now/naaga/place/domain/PlaceStatistics.java
index 61ed29625..c3adeba52 100644
--- a/backend/src/main/java/com/now/naaga/placestatistics/PlaceStatistics.java
+++ b/backend/src/main/java/com/now/naaga/place/domain/PlaceStatistics.java
@@ -1,8 +1,8 @@
-package com.now.naaga.placestatistics;
+package com.now.naaga.place.domain;
import com.now.naaga.common.domain.BaseEntity;
-import com.now.naaga.place.domain.Place;
import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@@ -13,11 +13,13 @@
@Entity
public class PlaceStatistics extends BaseEntity {
+ public static final long LIKE_COUNT_DEFAULT_VALUE = 0L;
+
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Long id;
- @OneToOne
+ @OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "place_id")
private Place place;
@@ -41,6 +43,21 @@ public PlaceStatistics(final Long id,
this.likeCount = likeCount;
}
+ public void plusLike() {
+ likeCount++;
+ }
+
+ public void subtractLike() {
+ if(isDefaultValue()) {
+ return;
+ }
+ likeCount--;
+ }
+
+ private boolean isDefaultValue() {
+ return likeCount == LIKE_COUNT_DEFAULT_VALUE;
+ }
+
public Long getId() {
return id;
}
diff --git a/backend/src/main/java/com/now/naaga/place/exception/PlaceStatisticsException.java b/backend/src/main/java/com/now/naaga/place/exception/PlaceStatisticsException.java
new file mode 100644
index 000000000..11991da1a
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/place/exception/PlaceStatisticsException.java
@@ -0,0 +1,18 @@
+package com.now.naaga.place.exception;
+
+import com.now.naaga.common.exception.BaseException;
+import com.now.naaga.common.exception.BaseExceptionType;
+
+public class PlaceStatisticsException extends BaseException {
+
+ private final PlaceStatisticsExceptionType placeStatisticsExceptionType;
+
+ public PlaceStatisticsException(final PlaceStatisticsExceptionType placeStatisticsExceptionType) {
+ this.placeStatisticsExceptionType = placeStatisticsExceptionType;
+ }
+
+ @Override
+ public BaseExceptionType exceptionType() {
+ return placeStatisticsExceptionType;
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/place/exception/PlaceStatisticsExceptionType.java b/backend/src/main/java/com/now/naaga/place/exception/PlaceStatisticsExceptionType.java
new file mode 100644
index 000000000..421f03a32
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/place/exception/PlaceStatisticsExceptionType.java
@@ -0,0 +1,41 @@
+package com.now.naaga.place.exception;
+
+import com.now.naaga.common.exception.BaseExceptionType;
+import org.springframework.http.HttpStatus;
+
+public enum PlaceStatisticsExceptionType implements BaseExceptionType {
+
+ NOT_FOUND(
+ 804,
+ HttpStatus.NOT_FOUND,
+ "ํด๋น ์ฅ์ ํต๊ณ๋ ์กด์ฌํ์ง ์์ต๋๋ค."
+ ),
+ ;
+
+ private final int errorCode;
+ private final HttpStatus httpStatus;
+ private final String errorMessage;
+
+ PlaceStatisticsExceptionType(final int errorCode,
+ final HttpStatus httpStatus,
+ final String errorMessage) {
+ this.errorCode = errorCode;
+ this.httpStatus = httpStatus;
+ this.errorMessage = errorMessage;
+ }
+
+ @Override
+ public int errorCode() {
+ return errorCode;
+ }
+
+ @Override
+ public HttpStatus httpStatus() {
+ return httpStatus;
+ }
+
+ @Override
+ public String errorMessage() {
+ return errorMessage;
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/place/persistence/repository/PlaceRepository.java b/backend/src/main/java/com/now/naaga/place/repository/PlaceRepository.java
similarity index 95%
rename from backend/src/main/java/com/now/naaga/place/persistence/repository/PlaceRepository.java
rename to backend/src/main/java/com/now/naaga/place/repository/PlaceRepository.java
index 60198adf9..acc420dcd 100644
--- a/backend/src/main/java/com/now/naaga/place/persistence/repository/PlaceRepository.java
+++ b/backend/src/main/java/com/now/naaga/place/repository/PlaceRepository.java
@@ -1,4 +1,4 @@
-package com.now.naaga.place.persistence.repository;
+package com.now.naaga.place.repository;
import com.now.naaga.place.domain.Place;
import com.now.naaga.place.domain.Position;
diff --git a/backend/src/main/java/com/now/naaga/place/repository/PlaceStatisticsRepository.java b/backend/src/main/java/com/now/naaga/place/repository/PlaceStatisticsRepository.java
new file mode 100644
index 000000000..01c07d853
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/place/repository/PlaceStatisticsRepository.java
@@ -0,0 +1,10 @@
+package com.now.naaga.place.repository;
+
+import com.now.naaga.place.domain.PlaceStatistics;
+import java.util.Optional;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface PlaceStatisticsRepository extends JpaRepository {
+
+ Optional findByPlaceId(Long placeId);
+}
diff --git a/backend/src/main/java/com/now/naaga/placestatistics/repository/PlaceStatisticsRepository.java b/backend/src/main/java/com/now/naaga/placestatistics/repository/PlaceStatisticsRepository.java
deleted file mode 100644
index 267c40a17..000000000
--- a/backend/src/main/java/com/now/naaga/placestatistics/repository/PlaceStatisticsRepository.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.now.naaga.placestatistics.repository;
-
-import com.now.naaga.placestatistics.PlaceStatistics;
-import org.springframework.data.jpa.repository.JpaRepository;
-
-public interface PlaceStatisticsRepository extends JpaRepository {
-}
diff --git a/backend/src/main/java/com/now/naaga/player/application/PlayerService.java b/backend/src/main/java/com/now/naaga/player/application/PlayerService.java
index b1c96dd24..b3ea891ad 100644
--- a/backend/src/main/java/com/now/naaga/player/application/PlayerService.java
+++ b/backend/src/main/java/com/now/naaga/player/application/PlayerService.java
@@ -1,5 +1,7 @@
package com.now.naaga.player.application;
+import static com.now.naaga.player.exception.PlayerExceptionType.PLAYER_NOT_FOUND;
+
import com.now.naaga.player.application.dto.AddScoreCommand;
import com.now.naaga.player.application.dto.CreatePlayerCommand;
import com.now.naaga.player.application.dto.DeletePlayerCommand;
@@ -9,13 +11,10 @@
import com.now.naaga.player.persistence.repository.PlayerRepository;
import com.now.naaga.player.presentation.dto.PlayerRequest;
import com.now.naaga.score.domain.Score;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
import java.util.ArrayList;
import java.util.List;
-
-import static com.now.naaga.player.exception.PlayerExceptionType.PLAYER_NOT_FOUND;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
@Transactional
@Service
diff --git a/backend/src/main/java/com/now/naaga/player/domain/Player.java b/backend/src/main/java/com/now/naaga/player/domain/Player.java
index c892c1a62..aaea7a4c3 100644
--- a/backend/src/main/java/com/now/naaga/player/domain/Player.java
+++ b/backend/src/main/java/com/now/naaga/player/domain/Player.java
@@ -1,16 +1,24 @@
package com.now.naaga.player.domain;
+import static java.lang.Boolean.FALSE;
+
import com.now.naaga.common.domain.BaseEntity;
import com.now.naaga.member.domain.Member;
import com.now.naaga.score.domain.Score;
-import jakarta.persistence.*;
+import jakarta.persistence.AttributeOverride;
+import jakarta.persistence.Column;
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToOne;
+import java.util.Objects;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
-import java.util.Objects;
-
-import static java.lang.Boolean.FALSE;
-
@SQLDelete(sql = "UPDATE player SET deleted = true WHERE id = ?")
@Where(clause = "deleted = false")
@Entity
diff --git a/backend/src/main/java/com/now/naaga/player/presentation/PlayerController.java b/backend/src/main/java/com/now/naaga/player/presentation/PlayerController.java
index 318957cac..0638e5ac7 100644
--- a/backend/src/main/java/com/now/naaga/player/presentation/PlayerController.java
+++ b/backend/src/main/java/com/now/naaga/player/presentation/PlayerController.java
@@ -1,22 +1,21 @@
package com.now.naaga.player.presentation;
+import static com.now.naaga.common.exception.CommonExceptionType.INVALID_REQUEST_PARAMETERS;
+
import com.now.naaga.auth.presentation.annotation.Auth;
import com.now.naaga.common.exception.CommonException;
import com.now.naaga.player.application.PlayerService;
import com.now.naaga.player.domain.Rank;
import com.now.naaga.player.presentation.dto.PlayerRequest;
import com.now.naaga.player.presentation.dto.RankResponse;
+import java.util.List;
+import java.util.stream.Collectors;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static com.now.naaga.common.exception.CommonExceptionType.INVALID_REQUEST_PARAMETERS;
-
@RequestMapping("/ranks")
@RestController
public class PlayerController {
diff --git a/backend/src/main/java/com/now/naaga/temporaryplace/application/DeleteTemporaryPlaceWithPlaceCreateEventHandler.java b/backend/src/main/java/com/now/naaga/temporaryplace/application/DeleteTemporaryPlaceWithPlaceCreateEventHandler.java
new file mode 100644
index 000000000..89d08f46f
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/temporaryplace/application/DeleteTemporaryPlaceWithPlaceCreateEventHandler.java
@@ -0,0 +1,23 @@
+package com.now.naaga.temporaryplace.application;
+
+import com.now.naaga.place.domain.PlaceCreateEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class DeleteTemporaryPlaceWithPlaceCreateEventHandler {
+
+ private final TemporaryPlaceService temporaryPlaceService;
+
+ public DeleteTemporaryPlaceWithPlaceCreateEventHandler(final TemporaryPlaceService temporaryPlaceService) {
+ this.temporaryPlaceService = temporaryPlaceService;
+ }
+
+ @Transactional
+ @EventListener
+ public void handle(final PlaceCreateEvent placeCreateEvent) {
+ final Long temporaryPlaceId = placeCreateEvent.temporaryPlaceId();
+ temporaryPlaceService.deleteByIdWhenPlaceCreated(temporaryPlaceId);
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/temporaryplace/application/TemporaryPlaceService.java b/backend/src/main/java/com/now/naaga/temporaryplace/application/TemporaryPlaceService.java
index 5165a2694..b2c1ca530 100644
--- a/backend/src/main/java/com/now/naaga/temporaryplace/application/TemporaryPlaceService.java
+++ b/backend/src/main/java/com/now/naaga/temporaryplace/application/TemporaryPlaceService.java
@@ -1,41 +1,49 @@
package com.now.naaga.temporaryplace.application;
-import com.now.naaga.common.infrastructure.FileManager;
+import com.now.naaga.common.infrastructure.AwsS3FileManager;
import com.now.naaga.place.domain.Position;
import com.now.naaga.player.application.PlayerService;
import com.now.naaga.player.domain.Player;
import com.now.naaga.temporaryplace.application.dto.CreateTemporaryPlaceCommand;
import com.now.naaga.temporaryplace.domain.TemporaryPlace;
+import com.now.naaga.temporaryplace.exception.TemporaryPlaceException;
import com.now.naaga.temporaryplace.repository.TemporaryPlaceRepository;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.multipart.MultipartFile;
-import java.io.File;
import java.util.Comparator;
import java.util.List;
+import static com.now.naaga.temporaryplace.exception.TemporaryPlaceExceptionType.NOT_EXIST;
+
@Transactional
@Service
public class TemporaryPlaceService {
-
+
private final TemporaryPlaceRepository temporaryPlaceRepository;
-
+
private final PlayerService playerService;
-
- private final FileManager fileManager;
-
+
+ private final AwsS3FileManager awsS3FileManager;
+
+ private final String imageUrlPrefix;
+
public TemporaryPlaceService(final TemporaryPlaceRepository temporaryPlaceRepository,
final PlayerService playerService,
- final FileManager fileManager) {
+ final AwsS3FileManager awsS3FileManager,
+ @Value("${image.path.url.prefix}") final String imageUrlPrefix) {
this.temporaryPlaceRepository = temporaryPlaceRepository;
this.playerService = playerService;
- this.fileManager = fileManager;
+ this.awsS3FileManager = awsS3FileManager;
+ this.imageUrlPrefix = imageUrlPrefix;
}
-
+
public TemporaryPlace createTemporaryPlace(final CreateTemporaryPlaceCommand createTemporaryPlaceCommand) {
final Position position = createTemporaryPlaceCommand.position();
- final File uploadPath = fileManager.save(createTemporaryPlaceCommand.imageFile());
+ final String s3Path = awsS3FileManager.uploadFile(createTemporaryPlaceCommand.imageFile());
+ final String fileName = s3Path.substring(s3Path.lastIndexOf("/") + 1);
+ final String imageUrl = imageUrlPrefix + fileName;
try {
final Long playerId = createTemporaryPlaceCommand.playerId();
final Player registeredPlayer = playerService.findPlayerById(playerId);
@@ -43,19 +51,28 @@ public TemporaryPlace createTemporaryPlace(final CreateTemporaryPlaceCommand cre
createTemporaryPlaceCommand.name(),
createTemporaryPlaceCommand.description(),
position,
- fileManager.convertToUrlPath(uploadPath),
+ imageUrl,
registeredPlayer);
return temporaryPlaceRepository.save(temporaryPlace);
} catch (final RuntimeException exception) {
- uploadPath.delete();
+ awsS3FileManager.deleteFile(s3Path);
throw exception;
}
}
-
- public void deleteById(final Long id) {
+
+ public void deleteByIdWhenPlaceCreated(final Long id) {
+ TemporaryPlace temporaryPlace = temporaryPlaceRepository.findById(id)
+ .orElseThrow(() -> new TemporaryPlaceException(NOT_EXIST));
temporaryPlaceRepository.deleteById(id);
}
-
+
+ public void deleteByIdWhenTemporaryPlaceDenied(final Long id) {
+ TemporaryPlace temporaryPlace = temporaryPlaceRepository.findById(id)
+ .orElseThrow(() -> new TemporaryPlaceException(NOT_EXIST));
+ temporaryPlaceRepository.deleteById(id);
+ awsS3FileManager.deleteFile(temporaryPlace.getImageUrl());
+ }
+
@Transactional(readOnly = true)
public List findAllTemporaryPlace() {
final List temporaryPlaces = temporaryPlaceRepository.findAll();
diff --git a/backend/src/main/java/com/now/naaga/temporaryplace/exception/TemporaryPlaceException.java b/backend/src/main/java/com/now/naaga/temporaryplace/exception/TemporaryPlaceException.java
new file mode 100644
index 000000000..b5aaf85eb
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/temporaryplace/exception/TemporaryPlaceException.java
@@ -0,0 +1,18 @@
+package com.now.naaga.temporaryplace.exception;
+
+import com.now.naaga.common.exception.BaseException;
+import com.now.naaga.common.exception.BaseExceptionType;
+
+public class TemporaryPlaceException extends BaseException {
+
+ private final TemporaryPlaceExceptionType temporaryPlaceExceptionType;
+
+ public TemporaryPlaceException(final TemporaryPlaceExceptionType temporaryPlaceExceptionType) {
+ this.temporaryPlaceExceptionType = temporaryPlaceExceptionType;
+ }
+
+ @Override
+ public BaseExceptionType exceptionType() {
+ return temporaryPlaceExceptionType;
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/temporaryplace/exception/TemporaryPlaceExceptionType.java b/backend/src/main/java/com/now/naaga/temporaryplace/exception/TemporaryPlaceExceptionType.java
new file mode 100644
index 000000000..7592731c6
--- /dev/null
+++ b/backend/src/main/java/com/now/naaga/temporaryplace/exception/TemporaryPlaceExceptionType.java
@@ -0,0 +1,43 @@
+package com.now.naaga.temporaryplace.exception;
+
+import com.now.naaga.common.exception.BaseExceptionType;
+import org.springframework.http.HttpStatus;
+
+public enum TemporaryPlaceExceptionType implements BaseExceptionType {
+
+ NOT_EXIST(
+ 604,
+ HttpStatus.NOT_FOUND,
+ "๊ฒ์ ํ ์ฅ์๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค"
+ ),
+ ;
+
+ private final int errorCode;
+
+ private final HttpStatus httpStatus;
+
+ private final String errorMessage;
+
+ TemporaryPlaceExceptionType(final int errorCode,
+ final HttpStatus httpStatus,
+ final String errorMessage) {
+ this.errorCode = errorCode;
+ this.httpStatus = httpStatus;
+ this.errorMessage = errorMessage;
+ }
+
+ @Override
+ public int errorCode() {
+ return errorCode();
+ }
+
+ @Override
+ public HttpStatus httpStatus() {
+ return httpStatus;
+ }
+
+ @Override
+ public String errorMessage() {
+ return errorMessage;
+ }
+}
diff --git a/backend/src/main/java/com/now/naaga/temporaryplace/presentation/TemporaryPlaceController.java b/backend/src/main/java/com/now/naaga/temporaryplace/presentation/TemporaryPlaceController.java
index c6832a902..76f6073c6 100644
--- a/backend/src/main/java/com/now/naaga/temporaryplace/presentation/TemporaryPlaceController.java
+++ b/backend/src/main/java/com/now/naaga/temporaryplace/presentation/TemporaryPlaceController.java
@@ -7,12 +7,17 @@
import com.now.naaga.temporaryplace.domain.TemporaryPlace;
import com.now.naaga.temporaryplace.presentation.dto.CreateTemporaryPlaceRequest;
import com.now.naaga.temporaryplace.presentation.dto.TemporaryPlaceResponse;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
-
import java.net.URI;
import java.util.List;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/temporary-places")
@RestController
@@ -47,9 +52,11 @@ public ResponseEntity createTemporaryPlace(@Auth final P
@DeleteMapping("/{temporaryPlaceId}")
public ResponseEntity deleteTemporaryPlace(@PathVariable final Long temporaryPlaceId) {
- temporaryPlaceService.deleteById(temporaryPlaceId);
+ temporaryPlaceService.deleteByIdWhenTemporaryPlaceDenied(temporaryPlaceId);
return ResponseEntity
.status(HttpStatus.NO_CONTENT)
.build();
}
+ /* S3์ฌ์ฉ
+ */
}
diff --git a/backend/src/main/java/com/now/naaga/temporaryplace/presentation/dto/TemporaryPlaceResponse.java b/backend/src/main/java/com/now/naaga/temporaryplace/presentation/dto/TemporaryPlaceResponse.java
index 2730c3832..f8da3b645 100644
--- a/backend/src/main/java/com/now/naaga/temporaryplace/presentation/dto/TemporaryPlaceResponse.java
+++ b/backend/src/main/java/com/now/naaga/temporaryplace/presentation/dto/TemporaryPlaceResponse.java
@@ -2,7 +2,6 @@
import com.now.naaga.game.presentation.dto.CoordinateResponse;
import com.now.naaga.temporaryplace.domain.TemporaryPlace;
-
import java.util.List;
import java.util.stream.Collectors;
diff --git a/backend/src/main/java/com/now/naaga/temporaryplace/repository/TemporaryPlaceRepository.java b/backend/src/main/java/com/now/naaga/temporaryplace/repository/TemporaryPlaceRepository.java
index d9a4a1faf..6c3ac7a0e 100644
--- a/backend/src/main/java/com/now/naaga/temporaryplace/repository/TemporaryPlaceRepository.java
+++ b/backend/src/main/java/com/now/naaga/temporaryplace/repository/TemporaryPlaceRepository.java
@@ -2,11 +2,10 @@
import com.now.naaga.temporaryplace.domain.TemporaryPlace;
+import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
-import java.util.List;
-
public interface TemporaryPlaceRepository extends JpaRepository {
@Override
diff --git a/backend/src/main/resources/console-appender.xml b/backend/src/main/resources/console-appender.xml
deleted file mode 100644
index b56628e05..000000000
--- a/backend/src/main/resources/console-appender.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- ${CONSOLE_LOG_PATTERN}
-
-
-
diff --git a/backend/src/main/resources/db-file-appender.xml b/backend/src/main/resources/db-file-appender.xml
deleted file mode 100644
index 13bfd0d23..000000000
--- a/backend/src/main/resources/db-file-appender.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- ${LOGS_ABSOLUTE_PATH}/db.log
-
- INFO
- ACCEPT
- DENY
-
-
- ${FILE_LOG_PATTERN}
-
-
- ${LOGS_ABSOLUTE_PATH}/old-logs/db.%d{yyyy-MM-dd}.%i.log.gz
-
- 50MB
-
- 30
- 1GB
-
-
-
diff --git a/backend/src/main/resources/error-file-appender.xml b/backend/src/main/resources/error-file-appender.xml
deleted file mode 100644
index f564b5387..000000000
--- a/backend/src/main/resources/error-file-appender.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- ${LOGS_ABSOLUTE_PATH}/error.log
-
- ERROR
- ACCEPT
- DENY
-
-
- ${FILE_LOG_PATTERN}
-
-
- ${LOGS_ABSOLUTE_PATH}/old-logs/error.%d{yyyy-MM-dd}.%i.log.gz
-
- 50MB
-
- 30
- 3GB
-
-
-
diff --git a/backend/src/main/resources/info-file-appender.xml b/backend/src/main/resources/info-file-appender.xml
deleted file mode 100644
index ba4fa9373..000000000
--- a/backend/src/main/resources/info-file-appender.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- ${LOGS_ABSOLUTE_PATH}/info.log
-
- INFO
- ACCEPT
- DENY
-
-
- ${FILE_LOG_PATTERN}
-
-
- ${LOGS_ABSOLUTE_PATH}/old-logs/info.%d{yyyy-MM-dd}.%i.log.gz
-
- 50MB
-
- 30
- 1GB
-
-
-
diff --git a/backend/src/main/resources/logback-spring.xml b/backend/src/main/resources/logback-spring.xml
deleted file mode 100644
index 06a184653..000000000
--- a/backend/src/main/resources/logback-spring.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/backend/src/main/resources/security b/backend/src/main/resources/security
index f95252b8f..6aea9836a 160000
--- a/backend/src/main/resources/security
+++ b/backend/src/main/resources/security
@@ -1 +1 @@
-Subproject commit f95252b8fb6b0766ec8a964f3737e70073863fee
+Subproject commit 6aea9836ab385f1eee8d5075f6dd98e800ff158e
diff --git a/backend/src/main/resources/warn-file-appender.xml b/backend/src/main/resources/warn-file-appender.xml
deleted file mode 100644
index f512584da..000000000
--- a/backend/src/main/resources/warn-file-appender.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- ${LOGS_ABSOLUTE_PATH}/warn.log
-
- WARN
- ACCEPT
- DENY
-
-
- ${FILE_LOG_PATTERN}
-
-
- ${LOGS_ABSOLUTE_PATH}/old-logs/warn.%d{yyyy-MM-dd}.%i.log.gz
-
- 50MB
-
- 30
- 2GB
-
-
-
diff --git a/backend/src/test/java/com/now/naaga/auth/application/AuthServiceTest.java b/backend/src/test/java/com/now/naaga/auth/application/AuthServiceTest.java
index 4ca8e2bff..106c8170e 100644
--- a/backend/src/test/java/com/now/naaga/auth/application/AuthServiceTest.java
+++ b/backend/src/test/java/com/now/naaga/auth/application/AuthServiceTest.java
@@ -1,19 +1,24 @@
package com.now.naaga.auth.application;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.when;
+
import com.now.naaga.auth.application.dto.AuthCommand;
-import com.now.naaga.auth.infrastructure.dto.AuthInfo;
import com.now.naaga.auth.domain.AuthToken;
import com.now.naaga.auth.infrastructure.AuthClient;
import com.now.naaga.auth.infrastructure.AuthType;
+import com.now.naaga.auth.infrastructure.dto.AuthInfo;
import com.now.naaga.auth.infrastructure.dto.MemberAuth;
import com.now.naaga.common.builder.PlayerBuilder;
import com.now.naaga.member.domain.Member;
-import com.now.naaga.member.exception.MemberException;
import com.now.naaga.member.persistence.repository.MemberRepository;
import com.now.naaga.player.domain.Player;
-import com.now.naaga.player.exception.PlayerException;
import com.now.naaga.player.persistence.repository.PlayerRepository;
import com.now.naaga.score.domain.Score;
+import java.util.Optional;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
@@ -22,16 +27,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.jdbc.Sql;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.MimeType;
-
-import java.util.Optional;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.when;
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
diff --git a/backend/src/test/java/com/now/naaga/auth/presentation/AuthControllerTest.java b/backend/src/test/java/com/now/naaga/auth/presentation/AuthControllerTest.java
index 544f04d7a..eae1b861f 100644
--- a/backend/src/test/java/com/now/naaga/auth/presentation/AuthControllerTest.java
+++ b/backend/src/test/java/com/now/naaga/auth/presentation/AuthControllerTest.java
@@ -1,5 +1,14 @@
package com.now.naaga.auth.presentation;
+import static com.now.naaga.auth.exception.AuthExceptionType.EXPIRED_TOKEN;
+import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_TOKEN;
+import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_TOKEN_ACCESS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.when;
+
import com.now.naaga.auth.domain.AuthToken;
import com.now.naaga.auth.infrastructure.AuthClient;
import com.now.naaga.auth.infrastructure.AuthType;
@@ -17,11 +26,11 @@
import com.now.naaga.common.exception.ExceptionResponse;
import com.now.naaga.member.domain.Member;
import com.now.naaga.player.domain.Player;
-import com.now.naaga.player.persistence.repository.PlayerRepository;
import com.now.naaga.score.domain.Score;
import io.restassured.RestAssured;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
+import java.util.Date;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
@@ -31,16 +40,6 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
-import java.util.Date;
-
-import static com.now.naaga.auth.exception.AuthExceptionType.*;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.InstanceOfAssertFactories.spliterator;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.when;
-
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(ReplaceUnderscores.class)
class AuthControllerTest extends CommonControllerTest {
diff --git a/backend/src/test/java/com/now/naaga/auth/presentation/AuthInterceptorTest.java b/backend/src/test/java/com/now/naaga/auth/presentation/AuthInterceptorTest.java
index 604b55c32..ae30a54fe 100644
--- a/backend/src/test/java/com/now/naaga/auth/presentation/AuthInterceptorTest.java
+++ b/backend/src/test/java/com/now/naaga/auth/presentation/AuthInterceptorTest.java
@@ -1,5 +1,11 @@
package com.now.naaga.auth.presentation;
+import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_HEADER;
+import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_TOKEN;
+import static com.now.naaga.auth.exception.AuthExceptionType.NOT_EXIST_HEADER;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
import com.now.naaga.auth.domain.AuthToken;
import com.now.naaga.auth.infrastructure.AuthType;
import com.now.naaga.auth.infrastructure.jwt.AuthTokenGenerator;
@@ -21,10 +27,6 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import static com.now.naaga.auth.exception.AuthExceptionType.*;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(ReplaceUnderscores.class)
public class AuthInterceptorTest extends CommonControllerTest {
diff --git a/backend/src/test/java/com/now/naaga/auth/presentation/PlayerArgumentResolverTest.java b/backend/src/test/java/com/now/naaga/auth/presentation/PlayerArgumentResolverTest.java
index 4db66a1a4..702334f78 100644
--- a/backend/src/test/java/com/now/naaga/auth/presentation/PlayerArgumentResolverTest.java
+++ b/backend/src/test/java/com/now/naaga/auth/presentation/PlayerArgumentResolverTest.java
@@ -1,5 +1,9 @@
package com.now.naaga.auth.presentation;
+import static com.now.naaga.player.exception.PlayerExceptionType.PLAYER_NOT_FOUND;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
import com.now.naaga.auth.domain.AuthToken;
import com.now.naaga.auth.infrastructure.AuthType;
import com.now.naaga.auth.infrastructure.jwt.AuthTokenGenerator;
@@ -18,10 +22,6 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import static com.now.naaga.player.exception.PlayerExceptionType.PLAYER_NOT_FOUND;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(ReplaceUnderscores.class)
public class PlayerArgumentResolverTest extends CommonControllerTest {
diff --git a/backend/src/test/java/com/now/naaga/auth/presentation/interceptor/ManagerAuthInterceptorTest.java b/backend/src/test/java/com/now/naaga/auth/presentation/interceptor/ManagerAuthInterceptorTest.java
index 0ba3de499..6eb262c4d 100644
--- a/backend/src/test/java/com/now/naaga/auth/presentation/interceptor/ManagerAuthInterceptorTest.java
+++ b/backend/src/test/java/com/now/naaga/auth/presentation/interceptor/ManagerAuthInterceptorTest.java
@@ -1,6 +1,10 @@
package com.now.naaga.auth.presentation.interceptor;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
import com.now.naaga.auth.exception.AuthException;
+import java.util.Base64;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
@@ -13,11 +17,6 @@
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.servlet.mvc.Controller;
-import java.util.Base64;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
@ActiveProfiles("test")
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
diff --git a/backend/src/test/java/com/now/naaga/common/CommonControllerTest.java b/backend/src/test/java/com/now/naaga/common/CommonControllerTest.java
index 542ca0bb4..fb1103278 100644
--- a/backend/src/test/java/com/now/naaga/common/CommonControllerTest.java
+++ b/backend/src/test/java/com/now/naaga/common/CommonControllerTest.java
@@ -6,8 +6,10 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
+@ActiveProfiles("test")
@Sql("/truncate.sql")
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public abstract class CommonControllerTest {
diff --git a/backend/src/test/java/com/now/naaga/common/builder/LetterBuilder.java b/backend/src/test/java/com/now/naaga/common/builder/LetterBuilder.java
new file mode 100644
index 000000000..de7e2b51b
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/common/builder/LetterBuilder.java
@@ -0,0 +1,61 @@
+package com.now.naaga.common.builder;
+
+import static com.now.naaga.common.fixture.LetterFixture.MESSAGE;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
+
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.repository.LetterRepository;
+import com.now.naaga.place.domain.Position;
+import com.now.naaga.player.domain.Player;
+import java.util.Optional;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class LetterBuilder {
+
+ @Autowired
+ private LetterRepository letterRepository;
+
+ @Autowired
+ private PlayerBuilder playerBuilder;
+
+ private Optional registeredPlayer;
+
+ private Position position;
+
+ private String message;
+
+ public LetterBuilder init() {
+ this.registeredPlayer = Optional.empty();
+ this.position = ์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
+ this.message = MESSAGE;
+ return this;
+ }
+
+ public LetterBuilder registeredPlayer(final Player persistedPlayer) {
+ this.registeredPlayer = Optional.ofNullable(persistedPlayer);
+ return this;
+ }
+
+ public LetterBuilder position(final Position position) {
+ this.position = position;
+ return this;
+ }
+
+ public LetterBuilder message(final String message) {
+ this.message = message;
+ return this;
+ }
+
+ public Letter build() {
+ final Player persistedPlayer = registeredPlayer.orElseGet(this::getPersistedPlayer);
+ final Letter letter = new Letter(persistedPlayer, position, message);
+ return letterRepository.save(letter);
+ }
+
+ private Player getPersistedPlayer() {
+ return playerBuilder.init()
+ .build();
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/common/builder/PlaceBuilder.java b/backend/src/test/java/com/now/naaga/common/builder/PlaceBuilder.java
index bfca3974d..d716e2b98 100644
--- a/backend/src/test/java/com/now/naaga/common/builder/PlaceBuilder.java
+++ b/backend/src/test/java/com/now/naaga/common/builder/PlaceBuilder.java
@@ -7,7 +7,7 @@
import com.now.naaga.place.domain.Place;
import com.now.naaga.place.domain.Position;
-import com.now.naaga.place.persistence.repository.PlaceRepository;
+import com.now.naaga.place.repository.PlaceRepository;
import com.now.naaga.player.domain.Player;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
diff --git a/backend/src/test/java/com/now/naaga/common/builder/PlaceStatisticsBuilder.java b/backend/src/test/java/com/now/naaga/common/builder/PlaceStatisticsBuilder.java
index e49f7a80d..e0211024b 100644
--- a/backend/src/test/java/com/now/naaga/common/builder/PlaceStatisticsBuilder.java
+++ b/backend/src/test/java/com/now/naaga/common/builder/PlaceStatisticsBuilder.java
@@ -1,8 +1,8 @@
package com.now.naaga.common.builder;
import com.now.naaga.place.domain.Place;
-import com.now.naaga.placestatistics.PlaceStatistics;
-import com.now.naaga.placestatistics.repository.PlaceStatisticsRepository;
+import com.now.naaga.place.domain.PlaceStatistics;
+import com.now.naaga.place.repository.PlaceStatisticsRepository;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
diff --git a/backend/src/test/java/com/now/naaga/common/builder/ReadLetterLogBuilder.java b/backend/src/test/java/com/now/naaga/common/builder/ReadLetterLogBuilder.java
new file mode 100644
index 000000000..5e9b30fcb
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/common/builder/ReadLetterLogBuilder.java
@@ -0,0 +1,59 @@
+package com.now.naaga.common.builder;
+
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.domain.letterlog.ReadLetterLog;
+import com.now.naaga.letter.repository.letterlog.ReadLetterLogRepository;
+import java.util.Optional;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ReadLetterLogBuilder {
+
+ @Autowired
+ private ReadLetterLogRepository readLetterLogRepository;
+
+ @Autowired
+ private GameBuilder gameBuilder;
+
+ @Autowired
+ private LetterBuilder letterBuilder;
+
+ private Optional registeredGame;
+
+ private Optional registeredLetter;
+
+ public ReadLetterLogBuilder init() {
+ this.registeredGame = Optional.empty();
+ this.registeredLetter = Optional.empty();
+ return this;
+ }
+
+ public ReadLetterLogBuilder game(final Game registeredGame) {
+ this.registeredGame = Optional.ofNullable(registeredGame);
+ return this;
+ }
+
+ public ReadLetterLogBuilder letter(final Letter registerdLetter) {
+ this.registeredLetter = Optional.ofNullable(registerdLetter);
+ return this;
+ }
+
+ public ReadLetterLog build() {
+ final Game persistedgame = registeredGame.orElseGet(this::getPersitedGame);
+ final Letter persistedLetter = registeredLetter.orElseGet(this::getPersistedLetter);
+ final ReadLetterLog letterLog = new ReadLetterLog(persistedgame, persistedLetter);
+ return readLetterLogRepository.save(letterLog);
+ }
+
+ public Game getPersitedGame() {
+ return gameBuilder.init()
+ .build();
+ }
+
+ public Letter getPersistedLetter() {
+ return letterBuilder.init()
+ .build();
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/common/builder/WriteLetterLogBuilder.java b/backend/src/test/java/com/now/naaga/common/builder/WriteLetterLogBuilder.java
new file mode 100644
index 000000000..27ed2d335
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/common/builder/WriteLetterLogBuilder.java
@@ -0,0 +1,59 @@
+package com.now.naaga.common.builder;
+
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.domain.letterlog.WriteLetterLog;
+import com.now.naaga.letter.repository.letterlog.WriteLetterLogRepository;
+import java.util.Optional;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class WriteLetterLogBuilder {
+
+ @Autowired
+ GameBuilder gameBuilder;
+
+ @Autowired
+ LetterBuilder letterBuilder;
+
+ @Autowired
+ WriteLetterLogRepository writeLetterLogRepository;
+
+ private Optional game;
+
+ private Optional letter;
+
+ public WriteLetterLogBuilder init() {
+ this.game = Optional.empty();
+ this.letter = Optional.empty();
+ return this;
+ }
+
+ public WriteLetterLogBuilder game(Game registerdGame) {
+ this.game = Optional.ofNullable(registerdGame);
+ return this;
+ }
+
+ public WriteLetterLogBuilder letter(Letter registerdLetter) {
+ this.letter = Optional.ofNullable(registerdLetter);
+ return this;
+ }
+
+ public WriteLetterLog build() {
+ final Game persistedGame = game.orElseGet(this::getPersitedGame);
+ final Letter persistedLetter = letter.orElseGet(this::getPersistedLetter);
+ final WriteLetterLog writeLetterLog = new WriteLetterLog(persistedGame, persistedLetter);
+ return writeLetterLogRepository.save(writeLetterLog);
+ }
+
+ public Game getPersitedGame() {
+ return gameBuilder.init()
+ .build();
+ }
+
+ public Letter getPersistedLetter() {
+ return letterBuilder.init()
+ .build();
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/common/fixture/GameFixture.java b/backend/src/test/java/com/now/naaga/common/fixture/GameFixture.java
new file mode 100644
index 000000000..f9f5d79ca
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/common/fixture/GameFixture.java
@@ -0,0 +1,14 @@
+package com.now.naaga.common.fixture;
+
+import static com.now.naaga.common.fixture.PlaceFixture.PLACE;
+import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
+import static com.now.naaga.common.fixture.PositionFixture.์์ธ_์ขํ;
+
+import com.now.naaga.game.domain.Game;
+
+public class GameFixture {
+
+ public static Game GAME() {
+ return new Game(PLAYER(), PLACE(), ์์ธ_์ขํ);
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/common/fixture/LetterFixture.java b/backend/src/test/java/com/now/naaga/common/fixture/LetterFixture.java
new file mode 100644
index 000000000..aff247be8
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/common/fixture/LetterFixture.java
@@ -0,0 +1,15 @@
+package com.now.naaga.common.fixture;
+
+import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+
+import com.now.naaga.letter.domain.Letter;
+
+public class LetterFixture {
+
+ public static final String MESSAGE = "์๋
ํ์ธ์. ๋์๊ฐ ๊ฐ๋ฐ์๋ค ์
๋๋ค.";
+
+ public static Letter LETTER() {
+ return new Letter(PLAYER(), ์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ, MESSAGE);
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/common/fixture/PlaceFixture.java b/backend/src/test/java/com/now/naaga/common/fixture/PlaceFixture.java
index f4d5363d0..4fb54e1bb 100644
--- a/backend/src/test/java/com/now/naaga/common/fixture/PlaceFixture.java
+++ b/backend/src/test/java/com/now/naaga/common/fixture/PlaceFixture.java
@@ -1,7 +1,6 @@
package com.now.naaga.common.fixture;
-import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
-import static com.now.naaga.common.fixture.PositionFixture.*;
+import static com.now.naaga.common.fixture.PositionFixture.์์ธ_์ขํ;
import com.now.naaga.place.domain.Place;
import com.now.naaga.place.domain.Position;
diff --git a/backend/src/test/java/com/now/naaga/common/fixture/PlaceStatisticsFixture.java b/backend/src/test/java/com/now/naaga/common/fixture/PlaceStatisticsFixture.java
index 3ae0ea5db..0f35c6bd2 100644
--- a/backend/src/test/java/com/now/naaga/common/fixture/PlaceStatisticsFixture.java
+++ b/backend/src/test/java/com/now/naaga/common/fixture/PlaceStatisticsFixture.java
@@ -1,6 +1,6 @@
package com.now.naaga.common.fixture;
-import com.now.naaga.placestatistics.PlaceStatistics;
+import com.now.naaga.place.domain.PlaceStatistics;
public class PlaceStatisticsFixture {
diff --git a/backend/src/test/java/com/now/naaga/common/fixture/PlayerFixture.java b/backend/src/test/java/com/now/naaga/common/fixture/PlayerFixture.java
index 067007b2b..6645b3387 100644
--- a/backend/src/test/java/com/now/naaga/common/fixture/PlayerFixture.java
+++ b/backend/src/test/java/com/now/naaga/common/fixture/PlayerFixture.java
@@ -1,6 +1,6 @@
package com.now.naaga.common.fixture;
-import static com.now.naaga.common.fixture.MemberFixture.*;
+import static com.now.naaga.common.fixture.MemberFixture.MEMBER;
import com.now.naaga.player.domain.Player;
import com.now.naaga.score.domain.Score;
diff --git a/backend/src/test/java/com/now/naaga/common/fixture/PositionFixture.java b/backend/src/test/java/com/now/naaga/common/fixture/PositionFixture.java
index faee1475c..075cb2aed 100644
--- a/backend/src/test/java/com/now/naaga/common/fixture/PositionFixture.java
+++ b/backend/src/test/java/com/now/naaga/common/fixture/PositionFixture.java
@@ -14,6 +14,9 @@ public class PositionFixture {
public static final Position ์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ = new Position(BigDecimal.valueOf(37.514258),
BigDecimal.valueOf(127.100883));
+ public static final Position ์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _110๋ฏธํฐ_์_์ขํ = new Position(์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ.getLatitude().add(BigDecimal.valueOf(0.000991)),
+ ์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ.getLongitude());
+
public static final Position GS25_๋ฐฉ์ด๋๊ณก์ _์ขํ = new Position(BigDecimal.valueOf(37.512184),
BigDecimal.valueOf(127.112789));
diff --git a/backend/src/test/java/com/now/naaga/common/fixture/ReadLetterLogFixture.java b/backend/src/test/java/com/now/naaga/common/fixture/ReadLetterLogFixture.java
new file mode 100644
index 000000000..a33678b03
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/common/fixture/ReadLetterLogFixture.java
@@ -0,0 +1,13 @@
+package com.now.naaga.common.fixture;
+
+import static com.now.naaga.common.fixture.GameFixture.GAME;
+import static com.now.naaga.common.fixture.LetterFixture.LETTER;
+
+import com.now.naaga.letter.domain.letterlog.ReadLetterLog;
+
+public class ReadLetterLogFixture {
+
+ public static ReadLetterLog READ_LETTER_LOG() {
+ return new ReadLetterLog(GAME(), LETTER());
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/common/fixture/TemporaryPlaceFixture.java b/backend/src/test/java/com/now/naaga/common/fixture/TemporaryPlaceFixture.java
index 906f53597..d00235bc3 100644
--- a/backend/src/test/java/com/now/naaga/common/fixture/TemporaryPlaceFixture.java
+++ b/backend/src/test/java/com/now/naaga/common/fixture/TemporaryPlaceFixture.java
@@ -1,10 +1,10 @@
package com.now.naaga.common.fixture;
-import com.now.naaga.temporaryplace.domain.TemporaryPlace;
-
import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import com.now.naaga.temporaryplace.domain.TemporaryPlace;
+
public class TemporaryPlaceFixture {
public static final String NAME = "temp_place_name";
diff --git a/backend/src/test/java/com/now/naaga/common/fixture/WriteLetterLogFixture.java b/backend/src/test/java/com/now/naaga/common/fixture/WriteLetterLogFixture.java
new file mode 100644
index 000000000..cb1901c62
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/common/fixture/WriteLetterLogFixture.java
@@ -0,0 +1,13 @@
+package com.now.naaga.common.fixture;
+
+import static com.now.naaga.common.fixture.GameFixture.GAME;
+import static com.now.naaga.common.fixture.LetterFixture.LETTER;
+
+import com.now.naaga.letter.domain.letterlog.WriteLetterLog;
+
+public class WriteLetterLogFixture {
+
+ public static WriteLetterLog WRITE_LETTER_LOG() {
+ return new WriteLetterLog(GAME(), LETTER());
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/common/presentation/interceptor/RequestMatcherInterceptorTest.java b/backend/src/test/java/com/now/naaga/common/presentation/interceptor/RequestMatcherInterceptorTest.java
index 7693dd2cc..9c88dbb0e 100644
--- a/backend/src/test/java/com/now/naaga/common/presentation/interceptor/RequestMatcherInterceptorTest.java
+++ b/backend/src/test/java/com/now/naaga/common/presentation/interceptor/RequestMatcherInterceptorTest.java
@@ -1,5 +1,11 @@
package com.now.naaga.common.presentation.interceptor;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.springframework.http.HttpMethod.GET;
+import static org.springframework.http.HttpMethod.POST;
+
+import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.params.ParameterizedTest;
@@ -10,18 +16,9 @@
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.ActiveProfiles;
-import org.springframework.util.AntPathMatcher;
-import org.springframework.util.PathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.mvc.Controller;
-import java.util.stream.Stream;
-
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.springframework.http.HttpMethod.GET;
-import static org.springframework.http.HttpMethod.POST;
-
@ActiveProfiles("test")
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
diff --git a/backend/src/test/java/com/now/naaga/common/presentation/interceptor/RequestPatternTest.java b/backend/src/test/java/com/now/naaga/common/presentation/interceptor/RequestPatternTest.java
index ec66c21a0..5debcc19d 100644
--- a/backend/src/test/java/com/now/naaga/common/presentation/interceptor/RequestPatternTest.java
+++ b/backend/src/test/java/com/now/naaga/common/presentation/interceptor/RequestPatternTest.java
@@ -1,21 +1,17 @@
package com.now.naaga.common.presentation.interceptor;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.http.HttpMethod.GET;
+import static org.springframework.http.HttpMethod.POST;
+
+import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.ActiveProfiles;
-import org.springframework.util.AntPathMatcher;
-import org.springframework.util.PathMatcher;
-
-import java.util.stream.Stream;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.springframework.http.HttpMethod.GET;
-import static org.springframework.http.HttpMethod.POST;
@ActiveProfiles("test")
@SuppressWarnings("NonAsciiCharacters")
diff --git a/backend/src/test/java/com/now/naaga/game/application/GameServiceTest.java b/backend/src/test/java/com/now/naaga/game/application/GameServiceTest.java
index 7112ba7f2..9281e908c 100644
--- a/backend/src/test/java/com/now/naaga/game/application/GameServiceTest.java
+++ b/backend/src/test/java/com/now/naaga/game/application/GameServiceTest.java
@@ -1,5 +1,23 @@
package com.now.naaga.game.application;
+import static com.now.naaga.common.fixture.PositionFixture.์ญ์ผ์ญ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_๊ทผ์ฒ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
+import static com.now.naaga.game.domain.EndType.ARRIVED;
+import static com.now.naaga.game.domain.EndType.GIVE_UP;
+import static com.now.naaga.game.domain.GameStatus.DONE;
+import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
+import static com.now.naaga.game.exception.GameExceptionType.ALREADY_IN_PROGRESS;
+import static com.now.naaga.game.exception.GameExceptionType.CAN_NOT_FIND_PLACE;
+import static com.now.naaga.game.exception.GameExceptionType.INACCESSIBLE_AUTHENTICATION;
+import static com.now.naaga.gameresult.domain.ResultType.FAIL;
+import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
+import static com.now.naaga.gameresult.exception.GameResultExceptionType.GAME_RESULT_NOT_EXIST;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
import com.now.naaga.common.builder.GameBuilder;
import com.now.naaga.common.builder.GameResultBuilder;
import com.now.naaga.common.builder.PlaceBuilder;
@@ -10,14 +28,17 @@
import com.now.naaga.game.application.dto.FindGameByStatusCommand;
import com.now.naaga.game.domain.Game;
import com.now.naaga.game.domain.GameRecord;
-import com.now.naaga.game.exception.GameNotFinishedException;
-import com.now.naaga.gameresult.domain.GameResult;
import com.now.naaga.game.domain.Statistic;
import com.now.naaga.game.exception.GameException;
+import com.now.naaga.game.exception.GameNotFinishedException;
+import com.now.naaga.gameresult.domain.GameResult;
import com.now.naaga.gameresult.exception.GameResultException;
import com.now.naaga.place.domain.Place;
import com.now.naaga.player.domain.Player;
import com.now.naaga.player.presentation.dto.PlayerRequest;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.util.List;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
@@ -25,23 +46,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
-import java.time.LocalDateTime;
-import java.time.Month;
-import java.util.List;
-
-import static com.now.naaga.common.fixture.PositionFixture.*;
-import static com.now.naaga.game.domain.EndType.ARRIVED;
-import static com.now.naaga.game.domain.EndType.GIVE_UP;
-import static com.now.naaga.game.domain.GameStatus.DONE;
-import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
-import static com.now.naaga.gameresult.domain.ResultType.FAIL;
-import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
-import static com.now.naaga.game.exception.GameExceptionType.*;
-import static com.now.naaga.gameresult.exception.GameResultExceptionType.*;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@Sql("/truncate.sql")
@SpringBootTest
diff --git a/backend/src/test/java/com/now/naaga/game/application/HintServiceTest.java b/backend/src/test/java/com/now/naaga/game/application/HintServiceTest.java
index f511504c8..351844d2e 100644
--- a/backend/src/test/java/com/now/naaga/game/application/HintServiceTest.java
+++ b/backend/src/test/java/com/now/naaga/game/application/HintServiceTest.java
@@ -17,7 +17,6 @@
import com.now.naaga.game.domain.Game;
import com.now.naaga.game.domain.Hint;
import com.now.naaga.game.exception.GameException;
-import com.now.naaga.member.domain.Member;
import com.now.naaga.place.domain.Place;
import java.time.LocalDateTime;
import org.junit.jupiter.api.DisplayNameGeneration;
diff --git a/backend/src/test/java/com/now/naaga/game/domain/GameScorePolicyTest.java b/backend/src/test/java/com/now/naaga/game/domain/GameScorePolicyTest.java
deleted file mode 100644
index b1d80943f..000000000
--- a/backend/src/test/java/com/now/naaga/game/domain/GameScorePolicyTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package com.now.naaga.game.domain;
-
-import com.now.naaga.game.domain.gamescore.GameScorePolicy;
-import com.now.naaga.game.domain.gamescore.SuccessGameScorePolicy;
-import com.now.naaga.player.domain.Player;
-import com.now.naaga.score.domain.Score;
-import org.junit.jupiter.api.DisplayNameGeneration;
-import org.junit.jupiter.api.DisplayNameGenerator;
-import org.junit.jupiter.api.Test;
-import org.springframework.test.context.ActiveProfiles;
-
-import java.time.LocalDateTime;
-import java.util.List;
-
-import static com.now.naaga.common.fixture.PlaceFixture.PLACE;
-import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
-import static com.now.naaga.common.fixture.PositionFixture.*;
-import static com.now.naaga.game.domain.GameStatus.DONE;
-import static org.assertj.core.api.Assertions.assertThat;
-
-@ActiveProfiles("test")
-@SuppressWarnings("NonAsciiCharacters")
-@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
-class GameScorePolicyTest {
-
- private final Player player = PLAYER();
- private final GameScorePolicy gameScorer = new SuccessGameScorePolicy();
-
- @Test
- void ๋ค๋ฅธ_์กฐ๊ฑด์ด_๊ฐ๊ณ _๊ฑฐ๋ฆฌ๊ฐ_๋ฉ์๋ก_์ ์๊ฐ_๋๋ค() {
- //given
- List hints = List.of(new Hint(), new Hint());
- LocalDateTime startTime = LocalDateTime.of(2023, 7, 31, 12, 00, 30);
- LocalDateTime endTime = LocalDateTime.of(2023, 7, 31, 14, 00, 30);
- Game gameHasDestinationInFurtherArea = new Game(DONE, player, PLACE(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ, player), ๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ, 3, hints, startTime, endTime);
- Game gameHasDestinationInNearArea = new Game(DONE, player, PLACE(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ, player), ์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ, 3, hints, startTime, endTime);
-
- //when
- Score furtherAreaScore = gameScorer.calculate(gameHasDestinationInFurtherArea);
- Score nearerAreaScore = gameScorer.calculate(gameHasDestinationInNearArea);
-
- //then
- assertThat(furtherAreaScore.isHigherThan(nearerAreaScore))
- .isTrue();
- }
-
- @Test
- void ๋ค๋ฅธ_์กฐ๊ฑด์ด_๊ฐ๊ณ _์์_์๊ฐ์ด_์งง์์๋ก_์ ์๊ฐ_๋๋ค() {
- //given
- List hints = List.of(new Hint(), new Hint());
- LocalDateTime startTime = LocalDateTime.of(2023, 7, 31, 12, 00, 30);
- LocalDateTime slowerEndTime = LocalDateTime.of(2023, 7, 31, 15, 00, 30);
- LocalDateTime fasterEndTime = LocalDateTime.of(2023, 7, 31, 13, 00, 30);
- Game slowerGame = new Game(DONE, player, PLACE(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ, player), ๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ, 3, hints, startTime, slowerEndTime);
- Game fasterGame = new Game(DONE, player, PLACE(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ, player), ๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ, 3, hints, startTime, fasterEndTime);
-
- //when
- Score slowerGameScore = gameScorer.calculate(slowerGame);
- Score fasterGameScore = gameScorer.calculate(fasterGame);
- //then
- assertThat(fasterGameScore.isHigherThan(slowerGameScore))
- .isTrue();
- }
-
- @Test
- void ๋ค๋ฅธ_์กฐ๊ฑด์ด_๊ฐ๊ณ _ํํธ_์ฌ์ฉ_๊ฐ์๊ฐ_์ ์์๋ก_์ ์๊ฐ_๋๋ค() {
- //given
- List threeHints = List.of(new Hint(), new Hint(), new Hint());
- List oneHints = List.of(new Hint());
- LocalDateTime startTime = LocalDateTime.of(2023, 7, 31, 12, 00, 30);
- LocalDateTime endTime = LocalDateTime.of(2023, 7, 31, 15, 00, 30);
- Game threeHintsGame = new Game(DONE, player, PLACE(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ, player), ๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ, 3, threeHints, startTime, endTime);
- Game oneHintsGame = new Game(DONE, player, PLACE(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ, player), ๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ, 3, oneHints, startTime, endTime);
-
- //when
- Score threeHintsGameScore = gameScorer.calculate(threeHintsGame);
- Score oneHintsGameScore = gameScorer.calculate(oneHintsGame);
- //then
- assertThat(oneHintsGameScore.isHigherThan(threeHintsGameScore))
- .isTrue();
- }
-
- @Test
- void ๋ค๋ฅธ_์กฐ๊ฑด์ด_๊ฐ๊ณ _์์ฌ_์๋_ํ์๊ฐ_๋ง์์๋ก_์ ์๊ฐ_๋๋ค() {
- //given
- int threeRemainingAttempts = 3;
- int oneRemainingAttempts = 1;
- List hints = List.of(new Hint(), new Hint());
- LocalDateTime startTime = LocalDateTime.of(2023, 7, 31, 12, 00, 30);
- LocalDateTime endTime = LocalDateTime.of(2023, 7, 31, 15, 00, 30);
- Game threeRemainingAttemptsGame = new Game(DONE, player, PLACE(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ, player), ๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ, threeRemainingAttempts, hints, startTime, endTime);
- Game oneRemainingAttemptsGame = new Game(DONE, player, PLACE(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ, player), ๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ, oneRemainingAttempts, hints, startTime, endTime);
-
- //when
- Score threeRemainingAttemptsGameScore = gameScorer.calculate(threeRemainingAttemptsGame);
- Score oneRemainingAttemptsGameScore = gameScorer.calculate(oneRemainingAttemptsGame);
- //then
- assertThat(threeRemainingAttemptsGameScore.isHigherThan(oneRemainingAttemptsGameScore))
- .isTrue();
- }
-}
diff --git a/backend/src/test/java/com/now/naaga/game/domain/GameTest.java b/backend/src/test/java/com/now/naaga/game/domain/GameTest.java
index e89146dc5..38d15db49 100644
--- a/backend/src/test/java/com/now/naaga/game/domain/GameTest.java
+++ b/backend/src/test/java/com/now/naaga/game/domain/GameTest.java
@@ -1,10 +1,25 @@
package com.now.naaga.game.domain;
+import static com.now.naaga.common.fixture.PlaceFixture.PLACE;
+import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
+import static com.now.naaga.common.fixture.PositionFixture.GS25_๋ฐฉ์ด๋๊ณก์ _์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_๊ทผ์ฒ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static com.now.naaga.game.domain.EndType.ARRIVED;
+import static com.now.naaga.game.domain.EndType.GIVE_UP;
+import static com.now.naaga.game.domain.Game.MAX_ATTEMPT_COUNT;
+import static com.now.naaga.game.domain.GameStatus.DONE;
+import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
import com.now.naaga.game.exception.GameException;
import com.now.naaga.game.exception.GameNotFinishedException;
import com.now.naaga.place.domain.Place;
import com.now.naaga.place.domain.Position;
import com.now.naaga.player.domain.Player;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
@@ -13,20 +28,6 @@
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.test.context.ActiveProfiles;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-
-import static com.now.naaga.common.fixture.PlaceFixture.PLACE;
-import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
-import static com.now.naaga.common.fixture.PositionFixture.*;
-import static com.now.naaga.game.domain.EndType.ARRIVED;
-import static com.now.naaga.game.domain.EndType.GIVE_UP;
-import static com.now.naaga.game.domain.Game.MAX_ATTEMPT_COUNT;
-import static com.now.naaga.game.domain.Game.MAX_HINT_COUNT;
-import static com.now.naaga.game.domain.GameStatus.DONE;
-import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
@ActiveProfiles("test")
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
diff --git a/backend/src/test/java/com/now/naaga/game/domain/ResultScorePolicyTest.java b/backend/src/test/java/com/now/naaga/game/domain/ResultScorePolicyTest.java
index beacce10f..5291cad0c 100644
--- a/backend/src/test/java/com/now/naaga/game/domain/ResultScorePolicyTest.java
+++ b/backend/src/test/java/com/now/naaga/game/domain/ResultScorePolicyTest.java
@@ -1,23 +1,24 @@
package com.now.naaga.game.domain;
+import static com.now.naaga.common.fixture.PlaceFixture.PLACE;
+import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
+import static com.now.naaga.common.fixture.PositionFixture.๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
+import static com.now.naaga.game.domain.GameStatus.DONE;
+import static org.assertj.core.api.Assertions.assertThat;
+
import com.now.naaga.gameresult.domain.gamescore.ResultScorePolicy;
import com.now.naaga.gameresult.domain.gamescore.SuccessResultScorePolicy;
import com.now.naaga.player.domain.Player;
import com.now.naaga.score.domain.Score;
+import java.time.LocalDateTime;
+import java.util.List;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
import org.springframework.test.context.ActiveProfiles;
-import java.time.LocalDateTime;
-import java.util.List;
-
-import static com.now.naaga.common.fixture.PlaceFixture.PLACE;
-import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
-import static com.now.naaga.common.fixture.PositionFixture.*;
-import static com.now.naaga.game.domain.GameStatus.DONE;
-import static org.assertj.core.api.Assertions.assertThat;
-
@ActiveProfiles("test")
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
diff --git a/backend/src/test/java/com/now/naaga/game/domain/StatisticTest.java b/backend/src/test/java/com/now/naaga/game/domain/StatisticTest.java
index 3865c809c..1f1ab2848 100644
--- a/backend/src/test/java/com/now/naaga/game/domain/StatisticTest.java
+++ b/backend/src/test/java/com/now/naaga/game/domain/StatisticTest.java
@@ -1,28 +1,27 @@
package com.now.naaga.game.domain;
+import static com.now.naaga.common.fixture.PlaceFixture.PLACE;
+import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
+import static com.now.naaga.common.fixture.PositionFixture.๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static com.now.naaga.game.domain.GameStatus.DONE;
+import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
import com.now.naaga.gameresult.domain.GameResult;
import com.now.naaga.place.domain.Place;
import com.now.naaga.place.domain.Position;
import com.now.naaga.player.domain.Player;
import com.now.naaga.score.domain.Score;
-import org.junit.jupiter.api.DisplayNameGeneration;
-import org.junit.jupiter.api.DisplayNameGenerator;
-import org.junit.jupiter.api.Test;
-import org.springframework.test.context.ActiveProfiles;
-
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;
import java.util.ArrayList;
import java.util.List;
-
-import static com.now.naaga.common.fixture.PlaceFixture.PLACE;
-import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
-import static com.now.naaga.common.fixture.PositionFixture.๋ํจ๋๋์ธ _์ฌ๋ฆผํฝ๊ณต์์ _์ขํ;
-import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
-import static com.now.naaga.game.domain.GameStatus.DONE;
-import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Test;
+import org.springframework.test.context.ActiveProfiles;
@ActiveProfiles("test")
@SuppressWarnings("NonAsciiCharacters")
diff --git a/backend/src/test/java/com/now/naaga/game/domain/gamescore/GameScoreCalculatorTest.java b/backend/src/test/java/com/now/naaga/game/domain/gamescore/GameScoreCalculatorTest.java
deleted file mode 100644
index 1c634c54f..000000000
--- a/backend/src/test/java/com/now/naaga/game/domain/gamescore/GameScoreCalculatorTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.now.naaga.game.domain.gamescore;
-
-import static com.now.naaga.common.fixture.PlaceFixture.PLACE;
-import static com.now.naaga.common.fixture.PlayerFixture.PLAYER;
-import static com.now.naaga.common.fixture.PositionFixture.์์ธ_์ขํ;
-import static com.now.naaga.game.domain.ResultType.FAIL;
-import static com.now.naaga.game.domain.ResultType.SUCCESS;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import com.now.naaga.game.domain.Game;
-import com.now.naaga.game.domain.GameStatus;
-import com.now.naaga.game.domain.ResultType;
-import com.now.naaga.score.domain.Score;
-import java.time.LocalDateTime;
-import java.util.Collections;
-import org.junit.jupiter.api.DisplayNameGeneration;
-import org.junit.jupiter.api.DisplayNameGenerator;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SuppressWarnings("NonAsciiCharacters")
-@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
-@SpringBootTest
-class GameScoreCalculatorTest {
-
- @Autowired
- GameScoreCalculator gameScoreCalculator;
-
- @Test
- void ๊ฒ์๊ฒฐ๊ณผ๊ฐ_์ฑ๊ณต์ผ_๋_์ ์๋ฅผ_์ป๋๋ค() {
- //given
- ResultType resultType = SUCCESS;
- Game game = new Game(GameStatus.DONE, PLAYER(), PLACE(), ์์ธ_์ขํ, 3,
- Collections.emptyList(),
- LocalDateTime.now().minusHours(1), LocalDateTime.now());
-
- //when
- final Score actual = gameScoreCalculator.calculate(game, resultType);
-
- //then
- assertThat(actual.getValue()).isGreaterThan(0);
- }
-
- @Test
- void ๊ฒ์๊ฒฐ๊ณผ๊ฐ_์คํจ์ผ_๋_0์ ์_์ป๋๋ค() {
- //given
- ResultType resultType = FAIL;
- Game game = new Game(GameStatus.DONE, PLAYER(), PLACE(), ์์ธ_์ขํ, 3,
- Collections.emptyList(),
- LocalDateTime.now().minusHours(1), LocalDateTime.now());
-
- //when
- final Score actual = gameScoreCalculator.calculate(game, resultType);
-
- //then
- assertThat(actual.getValue()).isZero();
- }
-}
diff --git a/backend/src/test/java/com/now/naaga/game/presentation/GameControllerTest.java b/backend/src/test/java/com/now/naaga/game/presentation/GameControllerTest.java
index 69744849a..5a1dcd656 100644
--- a/backend/src/test/java/com/now/naaga/game/presentation/GameControllerTest.java
+++ b/backend/src/test/java/com/now/naaga/game/presentation/GameControllerTest.java
@@ -1,13 +1,46 @@
package com.now.naaga.game.presentation;
+import static com.now.naaga.auth.exception.AuthExceptionType.NOT_EXIST_HEADER;
+import static com.now.naaga.common.fixture.PositionFixture.์์ธ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ญ์ผ์ญ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_๊ทผ์ฒ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ฃผ_์ขํ;
+import static com.now.naaga.game.domain.Game.MAX_ATTEMPT_COUNT;
+import static com.now.naaga.game.domain.GameStatus.DONE;
+import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
+import static com.now.naaga.game.exception.GameExceptionType.ALREADY_DONE;
+import static com.now.naaga.game.exception.GameExceptionType.ALREADY_IN_PROGRESS;
+import static com.now.naaga.game.exception.GameExceptionType.CAN_NOT_FIND_PLACE;
+import static com.now.naaga.game.exception.GameExceptionType.HINT_NOT_EXIST_IN_GAME;
+import static com.now.naaga.game.exception.GameExceptionType.INACCESSIBLE_AUTHENTICATION;
+import static com.now.naaga.game.exception.GameExceptionType.NOT_ARRIVED;
+import static com.now.naaga.game.exception.GameExceptionType.NOT_EXIST;
+import static com.now.naaga.gameresult.domain.ResultType.FAIL;
+import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
import com.now.naaga.auth.domain.AuthToken;
import com.now.naaga.auth.infrastructure.AuthType;
import com.now.naaga.auth.infrastructure.jwt.AuthTokenGenerator;
import com.now.naaga.common.CommonControllerTest;
-import com.now.naaga.common.builder.*;
+import com.now.naaga.common.builder.GameBuilder;
+import com.now.naaga.common.builder.GameResultBuilder;
+import com.now.naaga.common.builder.MemberBuilder;
+import com.now.naaga.common.builder.PlaceBuilder;
+import com.now.naaga.common.builder.PlayerBuilder;
import com.now.naaga.common.exception.ExceptionResponse;
-import com.now.naaga.game.domain.*;
-import com.now.naaga.game.presentation.dto.*;
+import com.now.naaga.game.domain.Direction;
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.game.domain.GameRecord;
+import com.now.naaga.game.domain.Hint;
+import com.now.naaga.game.presentation.dto.CoordinateRequest;
+import com.now.naaga.game.presentation.dto.EndGameRequest;
+import com.now.naaga.game.presentation.dto.GameResponse;
+import com.now.naaga.game.presentation.dto.GameResultResponse;
+import com.now.naaga.game.presentation.dto.GameStatusResponse;
+import com.now.naaga.game.presentation.dto.HintResponse;
import com.now.naaga.game.repository.GameRepository;
import com.now.naaga.game.repository.HintRepository;
import com.now.naaga.gameresult.domain.GameResult;
@@ -23,6 +56,9 @@
import io.restassured.http.ContentType;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
@@ -31,20 +67,6 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.now.naaga.auth.exception.AuthExceptionType.NOT_EXIST_HEADER;
-import static com.now.naaga.common.fixture.PositionFixture.*;
-import static com.now.naaga.game.domain.Game.MAX_ATTEMPT_COUNT;
-import static com.now.naaga.game.domain.GameStatus.DONE;
-import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
-import static com.now.naaga.gameresult.domain.ResultType.FAIL;
-import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
-import static com.now.naaga.game.exception.GameExceptionType.*;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(ReplaceUnderscores.class)
class GameControllerTest extends CommonControllerTest {
diff --git a/backend/src/test/java/com/now/naaga/game/presentation/StatisticControllerTest.java b/backend/src/test/java/com/now/naaga/game/presentation/StatisticControllerTest.java
index 16d798e76..53808d3ea 100644
--- a/backend/src/test/java/com/now/naaga/game/presentation/StatisticControllerTest.java
+++ b/backend/src/test/java/com/now/naaga/game/presentation/StatisticControllerTest.java
@@ -1,5 +1,9 @@
package com.now.naaga.game.presentation;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
import com.now.naaga.auth.domain.AuthToken;
import com.now.naaga.auth.infrastructure.AuthType;
import com.now.naaga.auth.infrastructure.jwt.AuthTokenGenerator;
@@ -27,10 +31,6 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
-import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
-import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
public class StatisticControllerTest extends CommonControllerTest {
diff --git a/backend/src/test/java/com/now/naaga/gameresult/application/GameResultServiceTest.java b/backend/src/test/java/com/now/naaga/gameresult/application/GameResultServiceTest.java
index 5842116a9..cc7aeb026 100644
--- a/backend/src/test/java/com/now/naaga/gameresult/application/GameResultServiceTest.java
+++ b/backend/src/test/java/com/now/naaga/gameresult/application/GameResultServiceTest.java
@@ -1,5 +1,11 @@
package com.now.naaga.gameresult.application;
+import static com.now.naaga.game.domain.EndType.ARRIVED;
+import static com.now.naaga.game.domain.GameStatus.DONE;
+import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
+import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
import com.now.naaga.common.builder.GameBuilder;
import com.now.naaga.common.builder.GameResultBuilder;
import com.now.naaga.common.builder.PlaceBuilder;
@@ -8,11 +14,11 @@
import com.now.naaga.game.domain.Game;
import com.now.naaga.game.exception.GameException;
import com.now.naaga.gameresult.domain.GameResult;
-import com.now.naaga.gameresult.exception.GameResultException;
import com.now.naaga.gameresult.repository.GameResultRepository;
import com.now.naaga.place.domain.Position;
import com.now.naaga.player.domain.Player;
import com.now.naaga.score.domain.Score;
+import java.time.LocalDateTime;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
@@ -23,14 +29,6 @@
import org.springframework.test.context.jdbc.Sql;
import org.springframework.transaction.annotation.Transactional;
-import java.time.LocalDateTime;
-
-import static com.now.naaga.game.domain.EndType.ARRIVED;
-import static com.now.naaga.game.domain.GameStatus.DONE;
-import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
-import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@Sql("/truncate.sql")
@ActiveProfiles("test")
diff --git a/backend/src/test/java/com/now/naaga/gameresult/repository/GameResultRepositoryTest.java b/backend/src/test/java/com/now/naaga/gameresult/repository/GameResultRepositoryTest.java
index a0297933a..c4b42d429 100644
--- a/backend/src/test/java/com/now/naaga/gameresult/repository/GameResultRepositoryTest.java
+++ b/backend/src/test/java/com/now/naaga/gameresult/repository/GameResultRepositoryTest.java
@@ -1,5 +1,11 @@
package com.now.naaga.gameresult.repository;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
+import static com.now.naaga.game.domain.GameStatus.DONE;
+import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
+import static org.assertj.core.api.Assertions.assertThat;
+
import com.now.naaga.common.builder.GameBuilder;
import com.now.naaga.common.builder.GameResultBuilder;
import com.now.naaga.common.builder.PlaceBuilder;
@@ -8,6 +14,7 @@
import com.now.naaga.gameresult.domain.GameResult;
import com.now.naaga.place.domain.Place;
import com.now.naaga.player.domain.Player;
+import java.util.List;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
@@ -15,14 +22,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
-import java.util.List;
-
-import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
-import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
-import static com.now.naaga.game.domain.GameStatus.DONE;
-import static com.now.naaga.gameresult.domain.ResultType.SUCCESS;
-import static org.assertj.core.api.Assertions.assertThat;
-
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@Sql("/truncate.sql")
@SpringBootTest
diff --git a/backend/src/test/java/com/now/naaga/letter/application/LetterServiceTest.java b/backend/src/test/java/com/now/naaga/letter/application/LetterServiceTest.java
new file mode 100644
index 000000000..27bf88d7f
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/letter/application/LetterServiceTest.java
@@ -0,0 +1,216 @@
+package com.now.naaga.letter.application;
+
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _110๋ฏธํฐ_์_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
+import static com.now.naaga.letter.exception.LetterExceptionType.NO_EXIST;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.now.naaga.common.builder.GameBuilder;
+import com.now.naaga.common.builder.LetterBuilder;
+import com.now.naaga.common.builder.PlaceBuilder;
+import com.now.naaga.common.builder.PlayerBuilder;
+import com.now.naaga.common.exception.BaseExceptionType;
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.game.exception.GameException;
+import com.now.naaga.game.exception.GameExceptionType;
+import com.now.naaga.letter.application.dto.CreateLetterCommand;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.exception.LetterException;
+import com.now.naaga.letter.presentation.dto.FindNearByLetterCommand;
+import com.now.naaga.letter.presentation.dto.LetterReadCommand;
+import com.now.naaga.letter.repository.letterlog.ReadLetterLogRepository;
+import com.now.naaga.place.domain.Place;
+import com.now.naaga.place.domain.Position;
+import com.now.naaga.player.domain.Player;
+import java.util.List;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.transaction.annotation.Transactional;
+
+@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+@ActiveProfiles("test")
+@Sql("/truncate.sql")
+@SpringBootTest
+class LetterServiceTest {
+
+ @Autowired
+ private LetterService letterService;
+
+ @Autowired
+ private PlayerBuilder playerBuilder;
+
+ @Autowired
+ private GameBuilder gameBuilder;
+
+ @Autowired
+ private ReadLetterLogRepository readLetterLogRepository;
+
+ @Autowired
+ private PlaceBuilder placeBuilder;
+
+ @Autowired
+ private LetterBuilder letterBuilder;
+
+ @Transactional
+ @Test
+ void ์ชฝ์ง๋ฅผ_์ ์์ ์ผ๋ก_์์ฑํ๊ณ _๊ฒ์์ค_๋ฑ๋กํ_์ชฝ์ง๋ฅผ_๊ธฐ๋ก์ผ๋ก_๋จ๊ธด๋ค() {
+ //given
+ final Player savedPlayer = playerBuilder.init()
+ .build();
+ final String message = "๋ ์จ๊ฐ ์ ์ ํด์.";
+ final Position position = ์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+ gameBuilder.init()
+ .player(savedPlayer)
+ .build();
+
+ //when
+ final CreateLetterCommand createLetterCommand = new CreateLetterCommand(
+ savedPlayer.getId(),
+ message,
+ position);
+ final Letter expected = new Letter(savedPlayer, position, message);
+ final Letter actual = letterService.writeLetter(createLetterCommand);
+
+ //then
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(actual)
+ .usingRecursiveComparison()
+ .ignoringExpectedNullFields()
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void ์ชฝ์ง๋ฅผ_๋ฑ๋กํ _๋_ํ์ฌ_์งํ_์ค์ธ_๊ฒ์์ด_์กด์ฌํ์ง_์์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ //given
+ final Player savedPlayer = playerBuilder.init()
+ .build();
+ final String message = "๋ ์จ๊ฐ ์ ์ ํด์.";
+ final Position position = ์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+ final CreateLetterCommand createLetterCommand = new CreateLetterCommand(
+ savedPlayer.getId(),
+ message,
+ position);
+
+ //when&then
+ assertThatThrownBy(() -> letterService.writeLetter(createLetterCommand))
+ .isInstanceOf(GameException.class);
+ Assertions.assertAll(() -> {
+ final BaseExceptionType baseExceptionType = assertThrows(GameException.class, () -> letterService.writeLetter(createLetterCommand))
+ .exceptionType();
+ assertThat(baseExceptionType).isEqualTo(GameExceptionType.NOT_EXIST_IN_PROGRESS);
+ });
+ }
+
+ @Test
+ void ํ๋ ์ด์ด์ฃผ๋ณ_100m_๋ด๋ก์_์ชฝ์ง๋ง_๋ชจ๋_์กฐํํ๋ค() {
+ // given
+ final Player registerPlayer = playerBuilder.init()
+ .build();
+
+ final Letter letter1 = letterBuilder.init()
+ .registeredPlayer(registerPlayer)
+ .build();
+
+ final Letter letter2 = letterBuilder.init()
+ .registeredPlayer(registerPlayer)
+ .position(์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _110๋ฏธํฐ_์_์ขํ)
+ .build();
+
+ // when
+ final List actual = letterService.findNearByLetters(new FindNearByLetterCommand(์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ));
+
+ // then
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(actual.size()).isEqualTo(1);
+ softAssertions.assertThat(actual.get(0).getId()).isEqualTo(letter1.getId());
+ });
+ }
+
+ @Test
+ void ํ๋ ์ด์ด์ฃผ๋ณ_100m_๋ด๋ก์_์ชฝ์ง๊ฐ_์์ผ๋ฉด_๋น๋ฆฌ์คํธ๋ฅผ_๋ฐํํ๋ค() {
+ // given
+ final Player registerPlayer = playerBuilder.init()
+ .build();
+
+ final Letter letter = letterBuilder.init()
+ .registeredPlayer(registerPlayer)
+ .position(์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _110๋ฏธํฐ_์_์ขํ)
+ .build();
+
+ // when
+ final List actual = letterService.findNearByLetters(new FindNearByLetterCommand(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ));
+
+ // then
+ assertThat(actual).isEmpty();
+ }
+
+ @Test
+ void ์ชฝ์ง๋ฅผ_๋จ๊ฑด์กฐํ_ํ๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place destination = placeBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Game game = gameBuilder.init()
+ .place(destination)
+ .player(player)
+ .startPosition(์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ)
+ .build();
+
+ final Player letterRegister = playerBuilder.init()
+ .build();
+
+ final Letter letter = letterBuilder.init()
+ .registeredPlayer(letterRegister)
+ .build();
+
+ // when
+ final Letter actual = letterService.findLetter(new LetterReadCommand(player.getId(), letter.getId()));
+
+ // then
+ assertThat(actual.getId()).isEqualTo(letter.getId());
+ }
+
+ @Test
+ void ์ชฝ์ง๊ฐ_์กด์ฌํ์ง_์์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ // given & when
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place destination = placeBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Game game = gameBuilder.init()
+ .place(destination)
+ .player(player)
+ .startPosition(์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ)
+ .build();
+
+ final Player letterRegister = playerBuilder.init()
+ .build();
+
+ final Letter letter = letterBuilder.init()
+ .registeredPlayer(letterRegister)
+ .build();
+
+ // then
+ final LetterException letterException = assertThrows(
+ LetterException.class, () -> letterService.findLetter(new LetterReadCommand(player.getId(), letter.getId() + 1)));
+ assertThat(letterException.exceptionType()).isEqualTo(NO_EXIST);
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/letter/application/letterlog/ReadLetterLogServiceTest.java b/backend/src/test/java/com/now/naaga/letter/application/letterlog/ReadLetterLogServiceTest.java
new file mode 100644
index 000000000..4ddc644ef
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/letter/application/letterlog/ReadLetterLogServiceTest.java
@@ -0,0 +1,119 @@
+package com.now.naaga.letter.application.letterlog;
+
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
+import static com.now.naaga.game.exception.GameExceptionType.NOT_EXIST_IN_PROGRESS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.now.naaga.common.builder.GameBuilder;
+import com.now.naaga.common.builder.LetterBuilder;
+import com.now.naaga.common.builder.PlaceBuilder;
+import com.now.naaga.common.builder.PlayerBuilder;
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.game.domain.GameStatus;
+import com.now.naaga.game.exception.GameException;
+import com.now.naaga.letter.application.letterlog.dto.LetterLogCreateCommand;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.domain.letterlog.ReadLetterLog;
+import com.now.naaga.letter.repository.letterlog.ReadLetterLogRepository;
+import com.now.naaga.place.domain.Place;
+import com.now.naaga.player.domain.Player;
+import java.util.List;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.jdbc.Sql;
+
+@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+@Sql("/truncate.sql")
+@SpringBootTest
+class ReadLetterLogServiceTest {
+
+ @Autowired
+ private ReadLetterLogService readLetterLogService;
+
+ @Autowired
+ private ReadLetterLogRepository readLetterLogRepository;
+
+ @Autowired
+ private PlayerBuilder playerBuilder;
+
+ @Autowired
+ private PlaceBuilder placeBuilder;
+
+ @Autowired
+ private GameBuilder gameBuilder;
+
+ @Autowired
+ private LetterBuilder letterBuilder;
+
+ @Test
+ void ์ฝ์์ชฝ์ง๋ก๊ทธ์_๋ฐ์ดํฐ๋ฅผ_์ ์ฅํ๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place destination = placeBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Game game = gameBuilder.init()
+ .place(destination)
+ .player(player)
+ .startPosition(์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ)
+ .build();
+
+ final Player letterRegister = playerBuilder.init()
+ .build();
+
+ final Letter letter = letterBuilder.init()
+ .registeredPlayer(letterRegister)
+ .build();
+
+ // when
+ readLetterLogService.log(new LetterLogCreateCommand(player.getId(), letter));
+
+ // then
+ final List actual = readLetterLogRepository.findAll();
+ final long expected = actual.get(0).getLetter().getId();
+
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(actual).hasSize(1);
+ softAssertions.assertThat(expected).isEqualTo(letter.getId());
+ });
+ }
+
+ @Test
+ void ์ฝ์์ชฝ์ง๋ก๊ทธ์_๋ฐ์ดํฐ์ ์ฅ์_์งํ์ค์ธ_๊ฒ์์ด์์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ // given && when
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place destination = placeBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Game game = gameBuilder.init()
+ .place(destination)
+ .player(player)
+ .startPosition(์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ)
+ .gameStatus(GameStatus.DONE)
+ .build();
+
+ final Player letterRegister = playerBuilder.init()
+ .build();
+
+ final Letter letter = letterBuilder.init()
+ .registeredPlayer(letterRegister)
+ .build();
+
+ //then
+ final GameException gameException = assertThrows(
+ GameException.class, () -> readLetterLogService.log(new LetterLogCreateCommand(player.getId(), letter)));
+ assertThat(gameException.exceptionType()).isEqualTo(NOT_EXIST_IN_PROGRESS);
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/letter/presentation/LetterControllerTest.java b/backend/src/test/java/com/now/naaga/letter/presentation/LetterControllerTest.java
new file mode 100644
index 000000000..10326043a
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/letter/presentation/LetterControllerTest.java
@@ -0,0 +1,353 @@
+package com.now.naaga.letter.presentation;
+
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _110๋ฏธํฐ_์_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ;
+import static com.now.naaga.game.domain.GameStatus.DONE;
+import static com.now.naaga.game.exception.GameExceptionType.NOT_EXIST_IN_PROGRESS;
+import static com.now.naaga.player.exception.PlayerExceptionType.PLAYER_NOT_FOUND;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
+import com.now.naaga.auth.domain.AuthToken;
+import com.now.naaga.auth.infrastructure.AuthType;
+import com.now.naaga.auth.infrastructure.jwt.AuthTokenGenerator;
+import com.now.naaga.common.CommonControllerTest;
+import com.now.naaga.common.builder.GameBuilder;
+import com.now.naaga.common.builder.LetterBuilder;
+import com.now.naaga.common.builder.PlaceBuilder;
+import com.now.naaga.common.builder.PlayerBuilder;
+import com.now.naaga.common.exception.ExceptionResponse;
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.game.presentation.dto.CoordinateResponse;
+import com.now.naaga.game.repository.GameRepository;
+import com.now.naaga.letter.application.LetterService;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.presentation.dto.LetterRequest;
+import com.now.naaga.letter.presentation.dto.LetterResponse;
+import com.now.naaga.letter.presentation.dto.NearByLetterResponse;
+import com.now.naaga.letter.repository.LetterRepository;
+import com.now.naaga.member.domain.Member;
+import com.now.naaga.place.domain.Place;
+import com.now.naaga.player.domain.Player;
+import com.now.naaga.player.presentation.dto.PlayerResponse;
+import io.restassured.RestAssured;
+import io.restassured.common.mapper.TypeRef;
+import io.restassured.http.ContentType;
+import io.restassured.parsing.Parser;
+import io.restassured.response.ExtractableResponse;
+import io.restassured.response.Response;
+import java.time.LocalDateTime;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+
+@SuppressWarnings("NonAsciiCharacters")
+@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+class LetterControllerTest extends CommonControllerTest {
+
+ @Autowired
+ private AuthTokenGenerator authTokenGenerator;
+
+ @Autowired
+ private GameRepository gameRepository;
+
+ @Autowired
+ private LetterService letterService;
+
+ @Autowired
+ private LetterRepository letterRepository;
+
+ @Autowired
+ private GameBuilder gameBuilder;
+
+ @Autowired
+ private LetterBuilder letterBuilder;
+
+ @Autowired
+ private PlaceBuilder placeBuilder;
+
+ @Autowired
+ private PlayerBuilder playerBuilder;
+
+ @BeforeEach
+ protected void setUp() {
+ super.setUp();
+ }
+
+ @Test
+ void ์ฃผ๋ณ_์ชฝ์ง๋ฅผ_๋ชจ๋_์กฐํํ๋ค() {
+ // given
+ final Place destination = placeBuilder.init()
+ .build();
+ final Player player = playerBuilder.init()
+ .build();
+ final Letter letter1 = letterBuilder.init()
+ .build();
+ final Letter letter2 = letterBuilder.init()
+ .position(์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _110๋ฏธํฐ_์_์ขํ)
+ .build();
+
+ final AuthToken generate = authTokenGenerator.generate(destination.getRegisteredPlayer().getMember(), 1L, AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ // when
+ final ExtractableResponse extract = RestAssured.given().log().all()
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .header("Authorization", "Bearer " + accessToken)
+ .param("latitude", ์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ.getLatitude())
+ .param("longitude", ์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ.getLongitude())
+ .when()
+ .get("/letters/nearby")
+ .then().log().all()
+ .statusCode(HttpStatus.OK.value())
+ .extract();
+
+ // then
+ final List actual = extract.as(new TypeRef<>() {
+ });
+ final int statusCode = extract.statusCode();
+ final List expected = List.of(NearByLetterResponse.from(letter1));
+
+ assertSoftly(softly -> {
+ softly.assertThat(statusCode).isEqualTo(HttpStatus.OK.value());
+ softly.assertThat(actual)
+ .hasSize(1)
+ .usingRecursiveComparison()
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void ์ชฝ์ง_์๋ณ์๋ก_์ชฝ์ง๋ฅผ_์กฐํํ๋ค() {
+ // given & when
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place destination = placeBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Game game = gameBuilder.init()
+ .place(destination)
+ .player(player)
+ .startPosition(์ ์ค์ญ_๊ต๋ณด๋ฌธ๊ณ _์ขํ)
+ .build();
+
+ final Letter letter = letterBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final AuthToken generate = authTokenGenerator.generate(player.getMember(), 1L, AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .when()
+ .get("/letters/{letterId}", letter.getId())
+ .then().log().all()
+ .extract();
+
+ // then
+ final int statusCode = extract.statusCode();
+ final LetterResponse actual = extract.as(LetterResponse.class);
+ final LetterResponse expected = LetterResponse.from(letter);
+
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.OK.value());
+ softAssertions.assertThat(actual)
+ .usingRecursiveComparison()
+ .ignoringExpectedNullFields()
+ .ignoringFields("registerDate")
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void ์ชฝ์ง_์๋ณ์๋ก_์ชฝ์ง๋ฅผ_์กฐํ์_์ํ์ค_๊ฒ์์ด_์์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ // given & when
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place destination = placeBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Letter letter = letterBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final AuthToken generate = authTokenGenerator.generate(player.getMember(), 1L, AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .when()
+ .get("/letters/{letterId}", letter.getId())
+ .then().log().all()
+ .extract();
+
+ // then
+ final int statusCode = extract.statusCode();
+ final ExceptionResponse actual = extract.as(ExceptionResponse.class);
+
+ final ExceptionResponse expected = new ExceptionResponse(NOT_EXIST_IN_PROGRESS.errorCode(), NOT_EXIST_IN_PROGRESS.errorMessage());
+
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.NOT_FOUND.value());
+ softAssertions.assertThat(actual)
+ .usingRecursiveComparison()
+ .ignoringExpectedNullFields()
+ .ignoringFieldsOfTypes(LocalDateTime.class)
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void ์ชฝ์ง_๋ฑ๋ก_์์ฒญ์_์ชฝ์ง๋ฅผ_๋ฑ๋กํ_ํ๋ ์ด์ด๊ฐ_์กด์ฌํ๊ณ _๊ทธ_ํ๋ ์ด์ด๊ฐ_์งํ์ค์ธ_๊ฒ์์ด_์์ผ๋ฉด_์ ์์ ์ผ๋ก_์ชฝ์ง๋ฅผ_์์ฑํ๋ค() {
+ //given
+ final Player player = playerBuilder.init()
+ .build();
+ final Game game = gameBuilder.init()
+ .player(player)
+ .build();
+
+ final AuthToken generate = authTokenGenerator.generate(player.getMember(), 1L, AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ String message = "๋ ์จ๊ฐ ์ ์ ํ๋ค์";
+ final LetterRequest letterRequest = new LetterRequest(message,
+ ์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ.getLatitude().doubleValue(),
+ ์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ.getLongitude().doubleValue());
+
+ //when
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .contentType(ContentType.JSON)
+ .body(letterRequest)
+ .when()
+ .post("/letters")
+ .then().log().all()
+ .extract();
+
+ //then
+ final int statusCode = extract.statusCode();
+ final String location = extract.header("Location");
+ final Long letterId = getIdFromLocationHeader(extract);
+ final LetterResponse actual = extract.as(LetterResponse.class);
+ final LetterResponse expected = new LetterResponse(
+ letterId,
+ PlayerResponse.from(player),
+ CoordinateResponse.of(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ),
+ message,
+ null
+ );
+
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.CREATED.value());
+ softAssertions.assertThat(location).isNotEqualTo("/letters" + letterId);
+ softAssertions.assertThat(actual)
+ .usingRecursiveComparison()
+ .ignoringExpectedNullFields()
+ .isEqualTo(expected);
+ }
+ );
+ }
+
+ @Test
+ void ์ชฝ์ง_๋ฑ๋ก_์์ฒญ์_์ชฝ์ง๋ฅผ_๋ฑ๋กํ_ํ๋ ์ด์ด๊ฐ_์กด์ฌํ์ง_์์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ //given
+ final AuthToken generate = authTokenGenerator.generate(new Member(1L, "email", false),
+ 1L,
+ AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ String message = "๋ ์จ๊ฐ ์ ์ ํ๋ค์";
+ final LetterRequest letterRequest = new LetterRequest(message,
+ ์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ.getLatitude().doubleValue(),
+ ์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ.getLongitude().doubleValue());
+
+ //when
+ RestAssured.defaultParser = Parser.JSON;
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .contentType(ContentType.JSON)
+ .body(letterRequest)
+ .when()
+ .post("/letters")
+ .then().log().all()
+ .extract();
+
+ //then
+ final int statusCode = extract.statusCode();
+ final ExceptionResponse actual = extract.as(ExceptionResponse.class);
+ final ExceptionResponse expected = new ExceptionResponse(
+ PLAYER_NOT_FOUND.errorCode(),
+ PLAYER_NOT_FOUND.errorMessage()
+ );
+
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.NOT_FOUND.value());
+ softAssertions.assertThat(actual)
+ .usingRecursiveComparison()
+ .isEqualTo(expected);
+ }
+ );
+ }
+
+ @Test
+ void ์ชฝ์ง_๋ฑ๋ก_์์ฒญ์_์ชฝ์ง๋ฅผ_๋ฑ๋กํ_์งํ์ค์ธ_๊ฒ์์ด_์กด์ฌํ์ง_์์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ //given
+ final Player player = playerBuilder.init()
+ .build();
+ final Game finishedGame = gameBuilder.init()
+ .player(player)
+ .gameStatus(DONE)
+ .build();
+ final AuthToken generate = authTokenGenerator.generate(player.getMember(),
+ 1L,
+ AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ String message = "๋ ์จ๊ฐ ์ ์ ํ๋ค์";
+ final LetterRequest letterRequest = new LetterRequest(message,
+ ์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ.getLatitude().doubleValue(),
+ ์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ.getLongitude().doubleValue());
+
+ //when
+ RestAssured.defaultParser = Parser.JSON;
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .contentType(ContentType.JSON)
+ .body(letterRequest)
+ .when()
+ .post("/letters")
+ .then().log().all()
+ .extract();
+
+ //then
+ final int statusCode = extract.statusCode();
+ final ExceptionResponse actual = extract.as(ExceptionResponse.class);
+ final ExceptionResponse expected = new ExceptionResponse(
+ NOT_EXIST_IN_PROGRESS.errorCode(),
+ NOT_EXIST_IN_PROGRESS.errorMessage()
+ );
+
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.NOT_FOUND.value());
+ softAssertions.assertThat(actual)
+ .usingRecursiveComparison()
+ .isEqualTo(expected);
+ }
+ );
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/letter/presentation/LetterLogControllerTest.java b/backend/src/test/java/com/now/naaga/letter/presentation/LetterLogControllerTest.java
new file mode 100644
index 000000000..350dfa22e
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/letter/presentation/LetterLogControllerTest.java
@@ -0,0 +1,266 @@
+package com.now.naaga.letter.presentation;
+
+import static com.now.naaga.common.exception.CommonExceptionType.INVALID_REQUEST_PARAMETERS;
+import static com.now.naaga.common.fixture.PositionFixture.GS25_๋ฐฉ์ด๋๊ณก์ _์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ญ์ผ์ญ_์ขํ;
+import static com.now.naaga.common.fixture.PositionFixture.์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
+import com.now.naaga.auth.domain.AuthToken;
+import com.now.naaga.auth.infrastructure.AuthType;
+import com.now.naaga.auth.infrastructure.jwt.AuthTokenGenerator;
+import com.now.naaga.common.CommonControllerTest;
+import com.now.naaga.common.builder.GameBuilder;
+import com.now.naaga.common.builder.LetterBuilder;
+import com.now.naaga.common.builder.PlaceBuilder;
+import com.now.naaga.common.builder.PlayerBuilder;
+import com.now.naaga.common.builder.ReadLetterLogBuilder;
+import com.now.naaga.common.builder.WriteLetterLogBuilder;
+import com.now.naaga.common.exception.ExceptionResponse;
+import com.now.naaga.game.domain.Game;
+import com.now.naaga.letter.domain.Letter;
+import com.now.naaga.letter.domain.letterlog.ReadLetterLog;
+import com.now.naaga.letter.domain.letterlog.WriteLetterLog;
+import com.now.naaga.letter.presentation.dto.LetterResponse;
+import com.now.naaga.letter.repository.letterlog.WriteLetterLogRepository;
+import com.now.naaga.place.domain.Place;
+import com.now.naaga.player.domain.Player;
+import io.restassured.RestAssured;
+import io.restassured.common.mapper.TypeRef;
+import io.restassured.response.ExtractableResponse;
+import io.restassured.response.Response;
+import java.time.LocalDateTime;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+
+@SuppressWarnings("NonAsciiCharacters")
+@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+class LetterLogControllerTest extends CommonControllerTest {
+
+ @Autowired
+ private AuthTokenGenerator authTokenGenerator;
+
+ @Autowired
+ private WriteLetterLogRepository writeLetterLogRepository;
+
+ @Autowired
+ private GameBuilder gameBuilder;
+
+ @Autowired
+ private PlaceBuilder placeBuilder;
+
+ @Autowired
+ private PlayerBuilder playerBuilder;
+
+ @Autowired
+ private LetterBuilder letterBuilder;
+
+ @Autowired
+ private ReadLetterLogBuilder readLetterLogBuilder;
+
+ @Autowired
+ private WriteLetterLogBuilder writeLetterLogBuilder;
+
+ @BeforeEach
+ protected void setUp() {
+ super.setUp();
+ }
+
+ // ์๋ชป๋ ํ๋ผ๋ฏธํฐ๋ ์์ธ๋ฅผ ๋์ง๋ค.
+ @Test
+ void ๊ฒ์์์ด๋์_ํ์์ผ๋ก_์ฝ์์ชฝ์ง๋ก๊ทธ๋ฅผ_๋ชจ๋_์กฐํํ๋ค() {
+ // given & when
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place destination = placeBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Game game1 = gameBuilder.init()
+ .place(destination)
+ .player(player)
+ .startPosition(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Game game2 = gameBuilder.init()
+ .place(destination)
+ .player(player)
+ .startPosition(์ญ์ผ์ญ_์ขํ)
+ .build();
+
+ final Letter letter = letterBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final ReadLetterLog readLetterLog1 = readLetterLogBuilder.init()
+ .game(game1)
+ .letter(letter)
+ .build();
+
+ final ReadLetterLog readLetterLog2 = readLetterLogBuilder.init()
+ .game(game2)
+ .letter(letter)
+ .build();
+
+ final AuthToken generate = authTokenGenerator.generate(player.getMember(), 1L, AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .param("gameId", game1.getId())
+ .param("logType", "READ")
+ .when()
+ .get("/letterlogs")
+ .then().log().all()
+ .statusCode(HttpStatus.OK.value())
+ .extract();
+
+ // then
+ final List actual = extract.as(new TypeRef<>() {
+ });
+ final int statusCode = extract.statusCode();
+ final List expected = List.of(LetterResponse.from(letter));
+
+ assertSoftly(softly -> {
+ softly.assertThat(statusCode).isEqualTo(HttpStatus.OK.value());
+ softly.assertThat(actual)
+ .hasSize(1)
+ .usingRecursiveComparison()
+ .ignoringFields("registerDate")
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void
+ ๊ฒ์์์ด๋์_ํ์์ผ๋ก_์์ฑํ_์ชฝ์ง๋ก๊ทธ๋ฅผ_๋ชจ๋_์กฐํํ๋ค() {
+ // given & when
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place destination = placeBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Game game = gameBuilder.init()
+ .place(destination)
+ .player(player)
+ .startPosition(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Letter letter = letterBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final WriteLetterLog writeLetterLog1 = writeLetterLogBuilder.init()
+ .game(game)
+ .letter(letter)
+ .build();
+
+ final AuthToken generate = authTokenGenerator.generate(player.getMember(), 1L, AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .param("gameId", game.getId())
+ .param("logType", "WRITE")
+ .when()
+ .get("/letterlogs")
+ .then().log().all()
+ .statusCode(HttpStatus.OK.value())
+ .extract();
+
+ // then
+ final List actual = extract.as(new TypeRef<>() {
+ });
+ final int statusCode = extract.statusCode();
+ final List expected = List.of(LetterResponse.from(letter));
+
+ assertSoftly(softly -> {
+ softly.assertThat(statusCode).isEqualTo(HttpStatus.OK.value());
+ softly.assertThat(actual)
+ .hasSize(1)
+ .usingRecursiveComparison()
+ .ignoringFields("registerDate")
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void ์ชฝ์ง๋ก๊ทธ_์กฐํ์_์๋ชป๋_ํ๋ผ๋ฏธํฐ๋_์์ธ๋ฅผ_๋์ง๋ค() {
+ // given & when
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place destination = placeBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Game game1 = gameBuilder.init()
+ .place(destination)
+ .player(player)
+ .startPosition(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Game game2 = gameBuilder.init()
+ .place(destination)
+ .player(player)
+ .startPosition(์ญ์ผ์ญ_์ขํ)
+ .build();
+
+ final Letter letter = letterBuilder.init()
+ .position(์ ์ค_๋ฃจํฐํ๊ด_์ ๋ฌธ_์ขํ)
+ .build();
+
+ final Letter letter2 = letterBuilder.init()
+ .position(GS25_๋ฐฉ์ด๋๊ณก์ _์ขํ)
+ .build();
+
+ final WriteLetterLog writeLetterLog1 = writeLetterLogBuilder.init()
+ .game(game1)
+ .letter(letter)
+ .build();
+
+ final WriteLetterLog writeLetterLog2 = writeLetterLogBuilder.init()
+ .game(game2)
+ .letter(letter2)
+ .build();
+
+ final AuthToken generate = authTokenGenerator.generate(player.getMember(), 1L, AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .param("gameId", game1.getId())
+ .param("logType", "์๋ชป๋enum")
+ .when()
+ .get("/letterlogs")
+ .then().log().all()
+ .extract();
+
+ // then
+ final int statusCode = extract.statusCode();
+ final ExceptionResponse actual = extract.as(ExceptionResponse.class);
+ final ExceptionResponse expected = new ExceptionResponse(INVALID_REQUEST_PARAMETERS.errorCode(), INVALID_REQUEST_PARAMETERS.errorMessage());
+
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.BAD_REQUEST.value());
+ softAssertions.assertThat(actual)
+ .usingRecursiveComparison()
+ .ignoringExpectedNullFields()
+ .ignoringFieldsOfTypes(LocalDateTime.class)
+ .ignoringFields("registerDate")
+ .isEqualTo(expected);
+ }
+ );
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/like/application/PlaceLikeServiceTest.java b/backend/src/test/java/com/now/naaga/like/application/PlaceLikeServiceTest.java
new file mode 100644
index 000000000..f7266a748
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/like/application/PlaceLikeServiceTest.java
@@ -0,0 +1,425 @@
+package com.now.naaga.like.application;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.now.naaga.common.builder.PlaceBuilder;
+import com.now.naaga.common.builder.PlaceLikeBuilder;
+import com.now.naaga.common.builder.PlaceStatisticsBuilder;
+import com.now.naaga.common.builder.PlayerBuilder;
+import com.now.naaga.common.exception.BaseExceptionType;
+import com.now.naaga.like.application.dto.ApplyLikeCommand;
+import com.now.naaga.like.application.dto.CancelLikeCommand;
+import com.now.naaga.like.application.dto.CheckMyPlaceLikeCommand;
+import com.now.naaga.like.application.dto.CountPlaceLikeCommand;
+import com.now.naaga.like.domain.MyPlaceLikeType;
+import com.now.naaga.like.domain.PlaceLike;
+import com.now.naaga.like.domain.PlaceLikeType;
+import com.now.naaga.like.exception.PlaceLikeException;
+import com.now.naaga.like.exception.PlaceLikeExceptionType;
+import com.now.naaga.like.repository.PlaceLikeRepository;
+import com.now.naaga.place.domain.Place;
+import com.now.naaga.place.domain.PlaceStatistics;
+import com.now.naaga.place.repository.PlaceStatisticsRepository;
+import com.now.naaga.player.domain.Player;
+import java.util.Optional;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.transaction.annotation.Transactional;
+
+@SuppressWarnings("NonAsciiCharacters")
+@DisplayNameGeneration(ReplaceUnderscores.class)
+@Sql("/truncate.sql")
+@ActiveProfiles("test")
+@SpringBootTest
+class PlaceLikeServiceTest {
+
+ private final PlaceLikeService placeLikeService;
+
+ private final PlaceBuilder placeBuilder;
+
+ private final PlayerBuilder playerBuilder;
+
+ private final PlaceLikeBuilder placeLikeBuilder;
+
+ private final PlaceStatisticsBuilder placeStatisticsBuilder;
+
+ private final PlaceLikeRepository placeLikeRepository;
+
+ private final PlaceStatisticsRepository placeStatisticsRepository;
+
+ @Autowired
+ public PlaceLikeServiceTest(final PlaceLikeService placeLikeService,
+ final PlaceBuilder placeBuilder,
+ final PlayerBuilder playerBuilder,
+ final PlaceLikeBuilder placeLikeBuilder,
+ final PlaceStatisticsBuilder placeStatisticsBuilder,
+ final PlaceLikeRepository placeLikeRepository,
+ final PlaceStatisticsRepository placeStatisticsRepository) {
+ this.placeLikeService = placeLikeService;
+ this.placeBuilder = placeBuilder;
+ this.playerBuilder = playerBuilder;
+ this.placeLikeBuilder = placeLikeBuilder;
+ this.placeStatisticsBuilder = placeStatisticsBuilder;
+ this.placeLikeRepository = placeLikeRepository;
+ this.placeStatisticsRepository = placeStatisticsRepository;
+ }
+
+ @Transactional
+ @Test
+ void ๊ธฐ์กด์_์ข์์_ํ์
๊ณผ_๋ฐ๋๋๋_ํ์
์_๋ฑ๋กํ๋ฉด_๊ธฐ์กด์_์ํฐํฐ์์_์ข์์_ํ์
๋ง_์์ ๋๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ placeStatisticsBuilder.init()
+ .place(place)
+ .build();
+
+ final PlaceLike placeLike = placeLikeBuilder.init()
+ .player(player)
+ .place(place)
+ .placeLikeType(PlaceLikeType.LIKE)
+ .build();
+
+ // when
+ final ApplyLikeCommand command = new ApplyLikeCommand(player.getId(),
+ place.getId(),
+ PlaceLikeType.DISLIKE);
+ final PlaceLike actual = placeLikeService.applyLike(command);
+
+ // then
+ SoftAssertions.assertSoftly(softAssertions -> {
+ softAssertions.assertThat(actual).usingRecursiveComparison()
+ .ignoringFields("placeLikeType")
+ .isEqualTo(placeLike);
+ softAssertions.assertThat(actual.getType()).isEqualTo(PlaceLikeType.DISLIKE);
+ });
+ }
+
+ @Test
+ void ๊ธฐ์กด์_์ข์์๊ฐ_์์_๊ฒฝ์ฐ์_ํ์
์_๋ฑ๋กํ๋ฉด_์๋ก์ด_์ข์์_์ํฐํฐ๊ฐ_์์ฑ๋๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ placeStatisticsBuilder.init()
+ .place(place)
+ .build();
+
+ // when
+ final int beforeSize = placeLikeRepository.findAll().size();
+ final ApplyLikeCommand command = new ApplyLikeCommand(player.getId(),
+ place.getId(),
+ PlaceLikeType.LIKE);
+ placeLikeService.applyLike(command);
+ final int afterSize = placeLikeRepository.findAll().size();
+
+ // then
+ assertThat(afterSize).isEqualTo(beforeSize + 1);
+ }
+
+ @Test
+ void ์ข์์๋ฅผ_๋ฑ๋กํ๋ฉด_์ข์์_์ง๊ณ_๊ฐ์_1_๋ํด์ง๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ final long beforeLikeCount = 10L;
+
+ placeStatisticsBuilder.init()
+ .place(place)
+ .likeCount(beforeLikeCount)
+ .build();
+
+ // when
+ final ApplyLikeCommand command = new ApplyLikeCommand(player.getId(),
+ place.getId(),
+ PlaceLikeType.LIKE);
+ placeLikeService.applyLike(command);
+ final PlaceStatistics placeStatistics = placeStatisticsRepository.findByPlaceId(place.getId()).get();
+
+ // then
+ assertThat(placeStatistics.getLikeCount()).isEqualTo(beforeLikeCount + 1);
+ }
+
+ @Test
+ void ๊ธฐ์กด์_์ข์์์์_์ซ์ด์๋ก_๋ณ๊ฒฝํ์ฌ_๋ฑ๋กํ๋ฉด_์ข์์_์ง๊ณ_๊ฐ์_1_๋บ๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ final long beforeLikeCount = 10L;
+
+ placeStatisticsBuilder.init()
+ .place(place)
+ .likeCount(beforeLikeCount)
+ .build();
+
+ placeLikeBuilder.init()
+ .player(player)
+ .place(place)
+ .placeLikeType(PlaceLikeType.LIKE)
+ .build();
+
+ // when
+ final ApplyLikeCommand command = new ApplyLikeCommand(player.getId(),
+ place.getId(),
+ PlaceLikeType.DISLIKE);
+ placeLikeService.applyLike(command);
+ final PlaceStatistics placeStatistics = placeStatisticsRepository.findByPlaceId(place.getId()).get();
+
+ // then
+ assertThat(placeStatistics.getLikeCount()).isEqualTo(beforeLikeCount - 1);
+ }
+
+ @Test
+ void ์๋กญ๊ฒ_์ซ์ด์๋ฅผ_๋ฑ๋กํ์_๋_์ข์์_์ง๊ณ_์๋_๋ณํ์ง_์๋๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ final long beforeLikeCount = 10L;
+
+ placeStatisticsBuilder.init()
+ .place(place)
+ .likeCount(beforeLikeCount)
+ .build();
+
+ // when
+ final ApplyLikeCommand command = new ApplyLikeCommand(player.getId(),
+ place.getId(),
+ PlaceLikeType.DISLIKE);
+ placeLikeService.applyLike(command);
+
+ // then
+ final PlaceStatistics placeStatistics = placeStatisticsRepository.findByPlaceId(place.getId()).get();
+ assertThat(placeStatistics.getLikeCount()).isEqualTo(beforeLikeCount);
+ }
+
+ @Test
+ void ๊ธฐ์กด์_์ข์์_ํ์
๊ณผ_๊ฐ์_ํ์
์ผ๋ก_์ข์์_๋ฑ๋ก์_์์ฒญํ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ placeStatisticsBuilder.init()
+ .place(place)
+ .build();
+
+ placeLikeBuilder.init()
+ .player(player)
+ .place(place)
+ .placeLikeType(PlaceLikeType.LIKE)
+ .build();
+
+ // when
+ final ApplyLikeCommand command = new ApplyLikeCommand(player.getId(),
+ place.getId(),
+ PlaceLikeType.LIKE);
+ final BaseExceptionType baseExceptionType = assertThrows(PlaceLikeException.class, () ->
+ placeLikeService.applyLike(command)
+ ).exceptionType();
+
+ // then
+ assertThat(baseExceptionType).isEqualTo(PlaceLikeExceptionType.ALREADY_APPLIED_TYPE);
+ }
+
+ @Test
+ void ์ข์์๋ฅผ_์ญ์ ํ๊ณ _ํต๊ณ์์_์ข์์๋ฅผ_1๊ฐ_๋บธ๋ค() {
+ // given
+ final Place place = placeBuilder.init()
+ .build();
+ final Player player = playerBuilder.init()
+ .build();
+ final PlaceLike placeLike = placeLikeBuilder.init()
+ .place(place)
+ .player(player)
+ .placeLikeType(PlaceLikeType.LIKE)
+ .build();
+ final long beforeLikeCount = 10L;
+ placeStatisticsBuilder.init()
+ .place(place)
+ .likeCount(beforeLikeCount)
+ .build();
+ final CancelLikeCommand cancelLikeCommand = new CancelLikeCommand(player.getId(), place.getId());
+
+ // when
+ placeLikeService.cancelLike(cancelLikeCommand);
+
+ // then
+ final Optional findPlaceLike = placeLikeRepository.findById(placeLike.getId());
+ final PlaceStatistics findPlaceStatistics = placeStatisticsRepository.findByPlaceId(place.getId()).get();
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(findPlaceStatistics.getLikeCount()).isEqualTo(beforeLikeCount - 1);
+ softAssertions.assertThat(findPlaceLike).isEmpty();
+ });
+ }
+
+ @Test
+ void ์ซ์ด์๋ฅผ_์ญ์ ํ๋ฉด_ํต๊ณ๊ฐ_์ค์ด๋ค์ง_์๋๋ค() {
+ // given
+ final Place place = placeBuilder.init()
+ .build();
+ final Player player = playerBuilder.init()
+ .build();
+ final PlaceLike placeLike = placeLikeBuilder.init()
+ .place(place)
+ .player(player)
+ .placeLikeType(PlaceLikeType.DISLIKE)
+ .build();
+ final long beforeLikeCount = 10L;
+ placeStatisticsBuilder.init()
+ .place(place)
+ .likeCount(beforeLikeCount)
+ .build();
+ final CancelLikeCommand cancelLikeCommand = new CancelLikeCommand(player.getId(), place.getId());
+
+ // when
+ placeLikeService.cancelLike(cancelLikeCommand);
+
+ // then
+ final Optional findPlaceLike = placeLikeRepository.findById(placeLike.getId());
+ final PlaceStatistics findPlaceStatistics = placeStatisticsRepository.findByPlaceId(place.getId()).get();
+ assertSoftly(softAssertions -> {
+ assertThat(findPlaceStatistics.getLikeCount()).isEqualTo(beforeLikeCount);
+ assertThat(findPlaceLike).isEmpty();
+ });
+ }
+
+ @Test
+ void ์ข์์๊ฐ_0๊ฐ์ผ_๋_์ข์์๋ฅผ_์ญ์ ํ๋ฉด_ํต๊ณ์์_์ข์์๋ฅผ_0๊ฐ๋ก_์ ์งํ๋ค() {
+ // given
+ final Place place = placeBuilder.init()
+ .build();
+ final Player player = playerBuilder.init()
+ .build();
+ final PlaceLike placeLike = placeLikeBuilder.init()
+ .place(place)
+ .player(player)
+ .placeLikeType(PlaceLikeType.LIKE)
+ .build();
+ final long beforeLikeCount = 0L;
+ placeStatisticsBuilder.init()
+ .place(place)
+ .likeCount(beforeLikeCount)
+ .build();
+ final CancelLikeCommand cancelLikeCommand = new CancelLikeCommand(player.getId(), place.getId());
+
+ // when
+ placeLikeService.cancelLike(cancelLikeCommand);
+
+ // then
+ final Optional findPlaceLike = placeLikeRepository.findById(placeLike.getId());
+ final PlaceStatistics findPlaceStatistics = placeStatisticsRepository.findByPlaceId(place.getId()).get();
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(findPlaceStatistics.getLikeCount()).isEqualTo(beforeLikeCount);
+ softAssertions.assertThat(findPlaceLike).isEmpty();
+ });
+ }
+
+ @Test
+ void ์ข์์๋ฅผ_์ญ์ ํ _๋_์ข์์๊ฐ_์กด์ฌํ์ง_์์ผ๋ฉด_์๋ฌด_์ผ๋_์ผ์ด๋์ง_์๋๋ค() {
+ // given
+ final Place place = placeBuilder.init()
+ .build();
+ final Player player = playerBuilder.init()
+ .build();
+ final CancelLikeCommand cancelLikeCommand = new CancelLikeCommand(player.getId(), place.getId());
+
+ // when & then
+ assertDoesNotThrow(() -> placeLikeService.cancelLike(cancelLikeCommand));
+ }
+
+ @Test
+ void ์ฅ์์_๋ํ_์ข์์_์๋ฅผ_๋ฐํํ๋ค() {
+ //given
+ final Long expected = 123L;
+ final PlaceStatistics placeStatistics = placeStatisticsBuilder.init()
+ .likeCount(expected)
+ .build();
+ final Long placeId = placeStatistics.getPlace().getId();
+
+ // when
+ final CountPlaceLikeCommand countPlaceLikeCommand = new CountPlaceLikeCommand(placeId);
+ final Long actual = placeLikeService.countPlaceLike(countPlaceLikeCommand);
+
+ // then
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
+ void ํน์ _์ฅ์์_๋ํ_๋์_์ข์์_์ฌ๋ถ_์กฐํ์_๋ด๊ฐ_๋๋ฅธ_์ข์์๊ฐ_์กด์ฌํ๋ค๋ฉด_ํด๋น_์ข์์_ํ์
์_๋ฐํํ๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ placeLikeBuilder.init()
+ .player(player)
+ .place(place)
+ .placeLikeType(PlaceLikeType.LIKE)
+ .build();
+
+ // when
+ final CheckMyPlaceLikeCommand command = new CheckMyPlaceLikeCommand(player.getId(), place.getId());
+ final MyPlaceLikeType actual = placeLikeService.checkMyLike(command);
+
+ // then
+ assertThat(actual).isEqualTo(MyPlaceLikeType.LIKE);
+ }
+
+ @Test
+ void ํน์ _์ฅ์์_๋ํ_๋์_์ข์์_์ฌ๋ถ_์กฐํ์_๋ด๊ฐ_๋๋ฅธ_์ข์์๊ฐ_์๋ค๋ฉด_NONE_ํ์
์_๋ฐํํ๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place applied = placeBuilder.init()
+ .build();
+
+ final Place notApplied = placeBuilder.init()
+ .build();
+
+ placeLikeBuilder.init()
+ .player(player)
+ .place(applied)
+ .placeLikeType(PlaceLikeType.LIKE)
+ .build();
+
+ // when
+ final CheckMyPlaceLikeCommand command = new CheckMyPlaceLikeCommand(player.getId(), notApplied.getId());
+ final MyPlaceLikeType actual = placeLikeService.checkMyLike(command);
+
+ // then
+ assertThat(actual).isEqualTo(MyPlaceLikeType.NONE);
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/like/domain/MyPlaceLikeTypeTest.java b/backend/src/test/java/com/now/naaga/like/domain/MyPlaceLikeTypeTest.java
new file mode 100644
index 000000000..3c4b37e8a
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/like/domain/MyPlaceLikeTypeTest.java
@@ -0,0 +1,26 @@
+package com.now.naaga.like.domain;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+@SuppressWarnings("NonAsciiCharacters")
+@DisplayNameGeneration(ReplaceUnderscores.class)
+class MyPlaceLikeTypeTest {
+
+ @ParameterizedTest(name = "PlaceLikeType ์ด {0} ์ผ๋, MyPlaceLikeType ์ {1} ์ผ๋ก ๋ณํ๋๋ค.")
+ @CsvSource(value = {"LIKE,LIKE", "DISLIKE,DISLIKE"})
+ void PlaceLikeType_์_MyPlaceLikeType_์ผ๋ก_๋ณํํ๋ค(final String placeLikeTypeValue, final String myPlaceLikeTypeValue) {
+ // given
+ final PlaceLikeType placeLikeType = PlaceLikeType.valueOf(placeLikeTypeValue);
+
+ // when
+ final MyPlaceLikeType actual = MyPlaceLikeType.from(placeLikeType);
+
+ // then
+ assertThat(actual.name()).isEqualTo(myPlaceLikeTypeValue);
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/like/domain/PlaceLikeTest.java b/backend/src/test/java/com/now/naaga/like/domain/PlaceLikeTest.java
new file mode 100644
index 000000000..d92a62d89
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/like/domain/PlaceLikeTest.java
@@ -0,0 +1,37 @@
+package com.now.naaga.like.domain;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.now.naaga.common.exception.BaseExceptionType;
+import com.now.naaga.common.fixture.PlaceLikeFixture;
+import com.now.naaga.like.exception.PlaceLikeException;
+import com.now.naaga.like.exception.PlaceLikeExceptionType;
+import com.now.naaga.member.domain.Member;
+import com.now.naaga.player.domain.Player;
+import com.now.naaga.score.domain.Score;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Test;
+import org.springframework.test.context.ActiveProfiles;
+
+@ActiveProfiles("test")
+@SuppressWarnings("NonAsciiCharacters")
+@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+class PlaceLikeTest {
+
+ @Test
+ void ์ข์์๋ฅผ_๋๋ฅธ_๋น์ฌ์๊ฐ_์๋๋ฉด_์์ธ๋ฅผ_๋ฐ์ํ๋ค() {
+ // given
+ final PlaceLike placeLike = PlaceLikeFixture.PLACE_LIKE();
+ final Player newPlayer = new Player(2L, "unknown", new Score(123), new Member("123@naver.com"), false);
+
+ // when & then
+ assertSoftly(softAssertions -> {
+ final BaseExceptionType baseExceptionType = assertThrows(PlaceLikeException.class, () -> placeLike.validateOwner(newPlayer))
+ .exceptionType();
+ assertThat(baseExceptionType).isEqualTo(PlaceLikeExceptionType.INACCESSIBLE_AUTHENTICATION);
+ });
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/like/domain/PlaceLikeTypeTest.java b/backend/src/test/java/com/now/naaga/like/domain/PlaceLikeTypeTest.java
new file mode 100644
index 000000000..d5321207c
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/like/domain/PlaceLikeTypeTest.java
@@ -0,0 +1,29 @@
+package com.now.naaga.like.domain;
+
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
+import org.junit.jupiter.api.Test;
+
+@SuppressWarnings("NonAsciiCharacters")
+@DisplayNameGeneration(ReplaceUnderscores.class)
+class PlaceLikeTypeTest {
+
+ @Test
+ void ์ข์์_ํน์_์ซ์ด์_ํ์
์_๋ฐ๋๋ก_๋ฐ๊พผ๋ค() {
+ // given
+ final PlaceLikeType like = PlaceLikeType.LIKE;
+ final PlaceLikeType dislike = PlaceLikeType.DISLIKE;
+
+ // when
+ final PlaceLikeType actual1 = like.switchType();
+ final PlaceLikeType actual2 = dislike.switchType();
+
+ // then
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(actual1).isEqualTo(PlaceLikeType.DISLIKE);
+ softAssertions.assertThat(actual2).isEqualTo(PlaceLikeType.LIKE);
+ });
+ }
+}
\ No newline at end of file
diff --git a/backend/src/test/java/com/now/naaga/like/presentation/PlaceLikeControllerTest.java b/backend/src/test/java/com/now/naaga/like/presentation/PlaceLikeControllerTest.java
new file mode 100644
index 000000000..88fd6c672
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/like/presentation/PlaceLikeControllerTest.java
@@ -0,0 +1,315 @@
+package com.now.naaga.like.presentation;
+
+import static com.now.naaga.like.exception.PlaceLikeExceptionType.ALREADY_APPLIED_TYPE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import static org.springframework.http.HttpStatus.NOT_FOUND;
+import static org.springframework.http.HttpStatus.NO_CONTENT;
+import static org.springframework.http.HttpStatus.OK;
+
+import com.now.naaga.auth.domain.AuthToken;
+import com.now.naaga.auth.infrastructure.AuthType;
+import com.now.naaga.auth.infrastructure.jwt.AuthTokenGenerator;
+import com.now.naaga.common.CommonControllerTest;
+import com.now.naaga.common.builder.PlaceBuilder;
+import com.now.naaga.common.builder.PlaceLikeBuilder;
+import com.now.naaga.common.builder.PlaceStatisticsBuilder;
+import com.now.naaga.common.builder.PlayerBuilder;
+import com.now.naaga.common.exception.ExceptionResponse;
+import com.now.naaga.like.domain.MyPlaceLikeType;
+import com.now.naaga.like.domain.PlaceLike;
+import com.now.naaga.like.domain.PlaceLikeType;
+import com.now.naaga.like.presentation.dto.ApplyPlaceLikeRequest;
+import com.now.naaga.like.presentation.dto.CheckMyPlaceLikeResponse;
+import com.now.naaga.like.presentation.dto.PlaceLikeCountResponse;
+import com.now.naaga.like.presentation.dto.PlaceLikeResponse;
+import com.now.naaga.member.domain.Member;
+import com.now.naaga.place.domain.Place;
+import com.now.naaga.place.domain.PlaceStatistics;
+import com.now.naaga.place.exception.PlaceStatisticsExceptionType;
+import com.now.naaga.player.domain.Player;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import io.restassured.response.ExtractableResponse;
+import io.restassured.response.Response;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+
+
+@SuppressWarnings("NonAsciiCharacters")
+@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+class PlaceLikeControllerTest extends CommonControllerTest {
+
+ @Autowired
+ private PlayerBuilder playerBuilder;
+
+ @Autowired
+ private PlaceBuilder placeBuilder;
+
+ @Autowired
+ private PlaceLikeBuilder placeLikeBuilder;
+
+ @Autowired
+ private PlaceStatisticsBuilder placeStatisticsBuilder;
+
+ @Autowired
+ private AuthTokenGenerator authTokenGenerator;
+
+ @BeforeEach
+ void setup() {
+ super.setUp();
+ }
+
+ @Test
+ void ์ข์์_๋ฑ๋ก์ด_์ฑ๊ณตํ๋ฉด_201_์๋ต์_๋ฐํํ๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ placeStatisticsBuilder.init()
+ .place(place)
+ .build();
+
+ final ApplyPlaceLikeRequest applyPlaceLikeRequest = new ApplyPlaceLikeRequest(PlaceLikeType.LIKE);
+
+ final Member member = player.getMember();
+ final AuthToken generate = authTokenGenerator.generate(member, member.getId(), AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ // when
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .body(applyPlaceLikeRequest)
+ .when()
+ .post("/places/{placeId}/likes", place.getId())
+ .then().log().all()
+ .extract();
+
+ // then
+ final int statusCode = extract.statusCode();
+ final PlaceLikeResponse actual = extract.as(PlaceLikeResponse.class);
+ final PlaceLikeResponse expected = new PlaceLikeResponse(null,
+ player.getId(),
+ place.getId(),
+ PlaceLikeType.LIKE);
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.CREATED.value());
+ softAssertions.assertThat(actual).usingRecursiveComparison()
+ .ignoringExpectedNullFields()
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void ์ข์์_๋ฑ๋ก_์์ฒญ์_์ค๋ณต๋๋_์ข์์_ํ์
์_๋ํ_์
๋ ฅ์ด_๋ค์ด์ค๋ฉด_์์ธ_์๋ต๊ณผ_400_์๋ต์_๋ฐํํ๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ placeStatisticsBuilder.init()
+ .place(place)
+ .build();
+
+ placeLikeBuilder.init()
+ .player(player)
+ .place(place)
+ .placeLikeType(PlaceLikeType.LIKE)
+ .build();
+
+ final ApplyPlaceLikeRequest applyPlaceLikeRequest = new ApplyPlaceLikeRequest(PlaceLikeType.LIKE);
+
+ final Member member = player.getMember();
+ final AuthToken generate = authTokenGenerator.generate(member, member.getId(), AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ // when
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .body(applyPlaceLikeRequest)
+ .when()
+ .post("/places/{placeId}/likes", place.getId())
+ .then().log().all()
+ .extract();
+
+ // then
+ final int statusCode = extract.statusCode();
+ final ExceptionResponse actual = extract.as(ExceptionResponse.class);
+ final ExceptionResponse expected = new ExceptionResponse(ALREADY_APPLIED_TYPE.errorCode(),
+ ALREADY_APPLIED_TYPE.errorMessage());
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.BAD_REQUEST.value());
+ softAssertions.assertThat(actual).usingRecursiveComparison()
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void ์ข์์_์ญ์ ๋ฅผ_์ฑ๊ณตํ๋ฉด_204์๋ต์_ํ๋ค() {
+ //given
+ final Place place = placeBuilder.init()
+ .build();
+ final PlaceLike placeLike = placeLikeBuilder.init()
+ .place(place)
+ .build();
+ placeStatisticsBuilder.init()
+ .place(place)
+ .build();
+ final Member member = placeLike.getPlayer().getMember();
+ final AuthToken generate = authTokenGenerator.generate(member, member.getId(), AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ //when
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .contentType(ContentType.JSON)
+ .pathParam("placeId", place.getId())
+ .when()
+ .delete("/places/{placeId}/likes/my")
+ .then().log().all()
+ .extract();
+
+ //then
+ final int statusCode = extract.statusCode();
+ assertThat(statusCode).isEqualTo(NO_CONTENT.value());
+ }
+
+ @Test
+ void ์ข์์๊ฐ_๋๋ ค์์_๋_๋์_์ข์์_์ฌ๋ถ๋ฅผ_์กฐํํ๋ฉด_ํด๋น_์ข์์_ํ์
_์๋ต๊ณผ_200_์ํ์ฝ๋๋ฅผ_๋ฐํํ๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ final PlaceLikeType myType = PlaceLikeType.LIKE;
+
+ placeLikeBuilder.init()
+ .player(player)
+ .place(place)
+ .placeLikeType(myType)
+ .build();
+
+ final Member member = player.getMember();
+ final AuthToken generate = authTokenGenerator.generate(member, member.getId(), AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ // when
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .when()
+ .get("/places/{placeId}/likes/my", place.getId())
+ .then().log().all()
+ .extract();
+
+ // then
+ final int statusCode = extract.statusCode();
+ final CheckMyPlaceLikeResponse actual = extract.as(CheckMyPlaceLikeResponse.class);
+ final CheckMyPlaceLikeResponse expected = new CheckMyPlaceLikeResponse(MyPlaceLikeType.from(myType));
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.OK.value());
+ softAssertions.assertThat(actual).usingRecursiveComparison()
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void ์๋ฌด๊ฒ๋_๋๋ ค์์ง_์์_๋_๋์_์ข์์_์ฌ๋ถ๋ฅผ_์กฐํํ๋ฉด_NONE_ํ์
_์๋ต๊ณผ_200_์ํ์ฝ๋๋ฅผ_๋ฐํํ๋ค() {
+ // given
+ final Player player = playerBuilder.init()
+ .build();
+
+ final Place place = placeBuilder.init()
+ .build();
+
+ final Member member = player.getMember();
+ final AuthToken generate = authTokenGenerator.generate(member, member.getId(), AuthType.KAKAO);
+ final String accessToken = generate.getAccessToken();
+
+ // when
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .header("Authorization", "Bearer " + accessToken)
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .when()
+ .get("/places/{placeId}/likes/my", place.getId())
+ .then().log().all()
+ .extract();
+
+ // then
+ final int statusCode = extract.statusCode();
+ final CheckMyPlaceLikeResponse actual = extract.as(CheckMyPlaceLikeResponse.class);
+ final CheckMyPlaceLikeResponse expected = new CheckMyPlaceLikeResponse(MyPlaceLikeType.NONE);
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.OK.value());
+ softAssertions.assertThat(actual).usingRecursiveComparison()
+ .isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void ํน์ _์ฅ์์_์ข์์_์๋ฅผ_์๋ตํ๊ณ _์๋ต์_์ํ์ฝ๋๋_200์ด๋ค() {
+ //given
+ final Long expected = 123L;
+ final PlaceStatistics placeStatistics = placeStatisticsBuilder.init()
+ .likeCount(expected)
+ .build();
+ final Long placeId = placeStatistics.getPlace().getId();
+
+ //when
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .pathParam("placeId", placeId)
+ .when()
+ .get("/places/{placeId}/likes/count")
+ .then().log().all()
+ .extract();
+
+ //then
+ final int statusCode = extract.statusCode();
+ final PlaceLikeCountResponse actual = extract.as(PlaceLikeCountResponse.class);
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(OK.value());
+ softAssertions.assertThat(actual.placeLikeCount()).isEqualTo(expected);
+ });
+ }
+
+ @Test
+ void ์ข์์_์๋ฅผ_์กฐํํ _๋_์ฅ์_ํต๊ณ๊ฐ_์์ผ๋ฉด_400_์์ธ๋ฅผ_๋ฐ์ํ๋ค() {
+ //given & when
+ final ExtractableResponse extract = RestAssured
+ .given().log().all()
+ .pathParam("placeId", 100)
+ .when()
+ .get("/places/{placeId}/likes/count")
+ .then().log().all()
+ .extract();
+
+ //then
+ final int statusCode = extract.statusCode();
+ final ExceptionResponse actual = extract.as(ExceptionResponse.class);
+ assertSoftly(softAssertions -> {
+ softAssertions.assertThat(statusCode).isEqualTo(NOT_FOUND.value());
+ softAssertions.assertThat(actual.getCode()).isEqualTo(PlaceStatisticsExceptionType.NOT_FOUND.errorCode());
+ softAssertions.assertThat(actual.getMessage()).isEqualTo(PlaceStatisticsExceptionType.NOT_FOUND.errorMessage());
+ });
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/place/application/PlaceServiceTest.java b/backend/src/test/java/com/now/naaga/place/application/PlaceServiceTest.java
index c1543b507..87a799721 100644
--- a/backend/src/test/java/com/now/naaga/place/application/PlaceServiceTest.java
+++ b/backend/src/test/java/com/now/naaga/place/application/PlaceServiceTest.java
@@ -1,18 +1,13 @@
package com.now.naaga.place.application;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-import com.now.naaga.common.builder.PlaceBuilder;
import com.now.naaga.common.builder.PlayerBuilder;
import com.now.naaga.common.builder.TemporaryPlaceBuilder;
-import com.now.naaga.common.exception.BaseExceptionType;
+import com.now.naaga.common.infrastructure.AwsS3FileManager;
import com.now.naaga.place.application.dto.CreatePlaceCommand;
import com.now.naaga.place.domain.Place;
+import com.now.naaga.place.domain.PlaceStatistics;
import com.now.naaga.place.domain.Position;
-import com.now.naaga.place.exception.PlaceException;
-import com.now.naaga.place.exception.PlaceExceptionType;
+import com.now.naaga.place.repository.PlaceStatisticsRepository;
import com.now.naaga.player.domain.Player;
import com.now.naaga.temporaryplace.domain.TemporaryPlace;
import com.now.naaga.temporaryplace.repository.TemporaryPlaceRepository;
@@ -21,95 +16,104 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.transaction.annotation.Transactional;
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.mockito.Mockito.*;
+
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(ReplaceUnderscores.class)
@Sql("/truncate.sql")
@ActiveProfiles("test")
@SpringBootTest
class PlaceServiceTest {
-
+
@Autowired
private TemporaryPlaceRepository temporaryPlaceRepository;
-
+
+ @Autowired
+ private PlaceStatisticsRepository placeStatisticsRepository;
+
@Autowired
private PlaceService placeService;
-
+
@Autowired
private TemporaryPlaceBuilder temporaryPlaceBuilder;
-
- @Autowired
- private PlaceBuilder placeBuilder;
-
+
@Autowired
private PlayerBuilder playerBuilder;
-
+
@Transactional
@Test
void ์ฅ์๋ฅผ_๋ฑ๋กํ_๋ค_๊ธฐ์กด์_๊ฒ์_์ฅ์_๋ฐ์ดํฐ๋_์ญ์ ํ๋ค() {
// given
final Player player = playerBuilder.init()
.build();
-
+
final TemporaryPlace temporaryPlace = temporaryPlaceBuilder.init()
.build();
-
+
final Long temporaryPlaceId = temporaryPlace.getId();
-
+
final CreatePlaceCommand createPlaceCommand = new CreatePlaceCommand("๋ฃจํฐํ๊ด",
- "์ด๊ณณ์ ๋ฃจํฐํ๊ด์ด๋ค ์๊ฒ ๋",
- Position.of(1.23, 4.56),
- "image/url",
- player.getId(),
- temporaryPlaceId);
-
+ "์ด๊ณณ์ ๋ฃจํฐํ๊ด์ด๋ค ์๊ฒ ๋",
+ Position.of(1.23, 4.56),
+ "image/url",
+ player.getId(),
+ temporaryPlaceId);
+
// when
final Place actual = placeService.createPlace(createPlaceCommand);
-
+
// then
final Place expected = new Place(createPlaceCommand.name(),
- createPlaceCommand.description(),
- createPlaceCommand.position(),
- createPlaceCommand.imageUrl(),
- player);
-
+ createPlaceCommand.description(),
+ createPlaceCommand.position(),
+ createPlaceCommand.imageUrl(),
+ player);
+
final TemporaryPlace found = temporaryPlaceRepository.findById(temporaryPlaceId)
.orElse(null);
-
- assertSoftly(softAssertions -> {
- assertThat(actual).usingRecursiveComparison()
- .ignoringExpectedNullFields()
- .isEqualTo(expected);
- assertThat(found).isNull();
- });
+
+ assertAll(
+ () -> assertThat(actual).usingRecursiveComparison()
+ .ignoringExpectedNullFields()
+ .isEqualTo(expected),
+ () -> assertThat(found).isNull()
+ );
}
-
+
@Test
- void ์ฅ์_๋ฑ๋ก_์_์ฃผ๋ณ_๋ฐ๊ฒฝ_20M_๋ด์_๋ฑ๋ก๋_์ฅ์๊ฐ_์กด์ฌํ๋ค๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ void ์ฅ์_๋ฑ๋ก_์_์ฅ์_ํต๊ณ๋_ํจ๊ป_๋ฑ๋ก๋๋ค() {
// given
final Player player = playerBuilder.init()
.build();
-
- placeBuilder.init()
- .position(Position.of(1.234567, 1.234567))
- .build();
-
+
+ final TemporaryPlace temporaryPlace = temporaryPlaceBuilder.init()
+ .build();
+
+ final Long temporaryPlaceId = temporaryPlace.getId();
+
final CreatePlaceCommand createPlaceCommand = new CreatePlaceCommand("๋ฃจํฐํ๊ด",
- "์ด๊ณณ์ ๋ฃจํฐํ๊ด์ด๋ค ์๊ฒ ๋",
- Position.of(1.23456, 1.23456),
- "image/url",
- player.getId(),
- 1L);
-
+ "์ด๊ณณ์ ๋ฃจํฐํ๊ด์ด๋ค ์๊ฒ ๋",
+ Position.of(1.23, 4.56),
+ "image/url",
+ player.getId(),
+ temporaryPlaceId);
+
// when
- final BaseExceptionType baseExceptionType = assertThrows(PlaceException.class,
- () -> placeService.createPlace(createPlaceCommand)
- ).exceptionType();
-
+ final Place place = placeService.createPlace(createPlaceCommand);
+
// then
- assertThat(baseExceptionType).isEqualTo(PlaceExceptionType.ALREADY_EXIST_NEARBY);
+ final Optional placeStatistics = placeStatisticsRepository.findByPlaceId(place.getId());
+ assertAll(
+ () -> assertThat(placeStatistics).isNotEmpty()
+ );
}
-}
\ No newline at end of file
+}
diff --git a/backend/src/test/java/com/now/naaga/place/application/PlaceStatisticsServiceTest.java b/backend/src/test/java/com/now/naaga/place/application/PlaceStatisticsServiceTest.java
new file mode 100644
index 000000000..c9e8b5692
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/place/application/PlaceStatisticsServiceTest.java
@@ -0,0 +1,146 @@
+package com.now.naaga.place.application;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.now.naaga.common.builder.PlaceBuilder;
+import com.now.naaga.common.builder.PlaceStatisticsBuilder;
+import com.now.naaga.common.exception.BaseExceptionType;
+import com.now.naaga.place.application.dto.CreatePlaceStatisticsCommand;
+import com.now.naaga.place.application.dto.FindPlaceStatisticsByPlaceIdCommand;
+import com.now.naaga.place.application.dto.PlusLikeCommand;
+import com.now.naaga.place.application.dto.SubtractLikeCommand;
+import com.now.naaga.place.domain.Place;
+import com.now.naaga.place.domain.PlaceStatistics;
+import com.now.naaga.place.exception.PlaceException;
+import com.now.naaga.place.exception.PlaceExceptionType;
+import com.now.naaga.place.exception.PlaceStatisticsException;
+import com.now.naaga.place.exception.PlaceStatisticsExceptionType;
+import com.now.naaga.place.repository.PlaceStatisticsRepository;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.transaction.annotation.Transactional;
+
+@SuppressWarnings("NonAsciiCharacters")
+@DisplayNameGeneration(ReplaceUnderscores.class)
+@Sql("/truncate.sql")
+@ActiveProfiles("test")
+@SpringBootTest
+class PlaceStatisticsServiceTest {
+
+ @Autowired
+ private PlaceStatisticsRepository placeStatisticsRepository;
+
+ @Autowired
+ private PlaceStatisticsService placeStatisticsService;
+
+ @Autowired
+ private PlaceStatisticsBuilder placeStatisticsBuilder;
+
+ @Autowired
+ private PlaceBuilder placeBuilder;
+
+ @Transactional
+ @Test
+ void ์ฅ์ํต๊ณ๋ฅผ_์์ฑํ๋ค() {
+ // given
+ final Place place = placeBuilder.init()
+ .build();
+
+ // when
+ final CreatePlaceStatisticsCommand command = new CreatePlaceStatisticsCommand(place.getId());
+ final PlaceStatistics actual = placeStatisticsService.createPlaceStatistics(command);
+
+ // then
+ final PlaceStatistics expected = new PlaceStatistics(place, PlaceStatistics.LIKE_COUNT_DEFAULT_VALUE);
+ assertThat(actual).usingRecursiveComparison()
+ .ignoringExpectedNullFields()
+ .isEqualTo(expected);
+ }
+
+ @Test
+ void ์ฅ์ํต๊ณ์์_์ข์์_์_1๊ฐ๋ฅผ_์ฌ๋ฆฐ๋ค() {
+ // given
+ final PlaceStatistics placeStatistics = placeStatisticsBuilder.init()
+ .likeCount(5L)
+ .build();
+
+ // when
+ placeStatisticsService.plusLike(new PlusLikeCommand(placeStatistics.getPlace().getId()));
+
+ // then
+ final PlaceStatistics actual = placeStatisticsRepository.findByPlaceId(placeStatistics.getPlace().getId()).get();
+ assertThat(actual.getLikeCount()).isEqualTo(6L);
+ }
+
+ @Test
+ void ์ฅ์ํต๊ณ์_์ข์์_์๋ฅผ_์ฌ๋ฆด๋_์ฅ์ํต๊ณ๋ฅผ_์ฐพ์_์_์๋ค๋ฉด_์ฅ์_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ // given
+ final PlaceStatistics placeStatistics = placeStatisticsBuilder.init()
+ .build();
+
+ // when
+ final PlusLikeCommand plusLikeCommand = new PlusLikeCommand(placeStatistics.getPlace().getId() + 1);
+ final BaseExceptionType baseExceptionType = assertThrows(PlaceException.class,
+ () -> placeStatisticsService.plusLike(plusLikeCommand)
+ ).exceptionType();
+
+ // then
+ assertThat(baseExceptionType).isEqualTo(PlaceExceptionType.NO_EXIST);
+ }
+
+ @Test
+ void ์ฅ์ํต๊ณ_1๊ฐ๋ฅผ_์ค์ธ๋ค() {
+ //given
+ final long beforeLikeCount = 10L;
+ final PlaceStatistics placeStatistics = placeStatisticsBuilder.init()
+ .likeCount(beforeLikeCount)
+ .build();
+ final Place place = placeStatistics.getPlace();
+
+ //when
+ final SubtractLikeCommand subtractLikeCommand = new SubtractLikeCommand(place.getId());
+ placeStatisticsService.subtractLike(subtractLikeCommand);
+
+ //then
+ final PlaceStatistics findPlaceStatistics = placeStatisticsRepository.findByPlaceId(place.getId()).get();
+ assertThat(findPlaceStatistics.getLikeCount()).isEqualTo(beforeLikeCount - 1);
+ }
+
+ @Transactional
+ @Test
+ void ์ฅ์ํต๊ณ๋ฅผ_์ฅ์์์ด๋๋ก_์กฐํํ๋ค() {
+ // given
+ final PlaceStatistics expected = placeStatisticsBuilder.init()
+ .likeCount(123L)
+ .build();
+
+ // when
+ final Long placeId = expected.getPlace().getId();
+ final FindPlaceStatisticsByPlaceIdCommand findPlaceStatisticsByPlaceIdCommand = new FindPlaceStatisticsByPlaceIdCommand(placeId);
+ final PlaceStatistics actual = placeStatisticsService.findPlaceStatisticsByPlaceId(findPlaceStatisticsByPlaceIdCommand);
+
+ assertThat(actual)
+ .usingRecursiveComparison()
+ .isEqualTo(expected);
+ }
+
+ @Test
+ void ์ฅ์ํต๊ณ๋ฅผ_์ฅ์์์ด๋๋ก_์กฐํ_์_์์ผ๋ฉด_์์ธ๋ฅผ_๋ฐ์ํ๋ค() {
+ // given & when
+ final FindPlaceStatisticsByPlaceIdCommand findPlaceStatisticsByPlaceIdCommand = new FindPlaceStatisticsByPlaceIdCommand(1L);
+
+ // then
+ assertAll(() -> {
+ final BaseExceptionType baseExceptionType = assertThrows(PlaceStatisticsException.class, () -> placeStatisticsService.findPlaceStatisticsByPlaceId(findPlaceStatisticsByPlaceIdCommand))
+ .exceptionType();
+ assertThat(baseExceptionType).isEqualTo(PlaceStatisticsExceptionType.NOT_FOUND);
+ });
+ }
+}
diff --git a/backend/src/test/java/com/now/naaga/place/domain/PlaceStatisticsTest.java b/backend/src/test/java/com/now/naaga/place/domain/PlaceStatisticsTest.java
new file mode 100644
index 000000000..59dd74f95
--- /dev/null
+++ b/backend/src/test/java/com/now/naaga/place/domain/PlaceStatisticsTest.java
@@ -0,0 +1,43 @@
+package com.now.naaga.place.domain;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.now.naaga.common.fixture.PlaceFixture;
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Test;
+import org.springframework.test.context.ActiveProfiles;
+
+@SuppressWarnings("NonAsciiCharacters")
+@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+@ActiveProfiles("test")
+class PlaceStatisticsTest {
+
+ @Test
+ void ์ฅ์_ํต๊ณ์์_์ข์์๋ฅผ_1๊ฐ_๋บ๋ค() {
+ // given
+ final Place place = PlaceFixture.PLACE();
+ final long beforeLikeCount = 10L;
+ final PlaceStatistics placeStatistics = new PlaceStatistics(place, beforeLikeCount);
+
+ // when
+ placeStatistics.subtractLike();
+
+ // then
+ assertThat(placeStatistics.getLikeCount()).isEqualTo(beforeLikeCount - 1);
+ }
+
+ @Test
+ void ์ฅ์_ํต๊ณ_์ข์์๋_0๊ฐ_์ดํ๋ก_์ค์ด๋ค์ง_์๋๋ค() {
+ // given
+ final Place place = PlaceFixture.PLACE();
+ final long beforeLikeCount = 0L;
+ final PlaceStatistics placeStatistics = new PlaceStatistics(place, beforeLikeCount);
+
+ // when
+ placeStatistics.subtractLike();
+
+ // then
+ assertThat(placeStatistics.getLikeCount()).isEqualTo(0L);
+ }
+}
diff --git "a/backend/src/test/java/com/now/naaga/place/fixture/\353\243\250\355\204\260\355\232\214\352\264\200.png" "b/backend/src/test/java/com/now/naaga/place/fixture/\353\243\250\355\204\260\355\232\214\352\264\200.png"
deleted file mode 100644
index 34126c328..000000000
Binary files "a/backend/src/test/java/com/now/naaga/place/fixture/\353\243\250\355\204\260\355\232\214\352\264\200.png" and /dev/null differ
diff --git a/backend/src/test/java/com/now/naaga/place/presentation/PlaceControllerTest.java b/backend/src/test/java/com/now/naaga/place/presentation/PlaceControllerTest.java
index 074487753..6643490bc 100644
--- a/backend/src/test/java/com/now/naaga/place/presentation/PlaceControllerTest.java
+++ b/backend/src/test/java/com/now/naaga/place/presentation/PlaceControllerTest.java
@@ -56,49 +56,49 @@ protected void setUp() {
super.setUp();
}
- @Test
- void ์ฅ์_๋ฑ๋ก_์์ฒญ์ด_์ฑ๊ณตํ๋ฉด_201_์ํ์ฝ๋์_์์ฑ๋_์ฅ์๋ฅผ_์๋ตํ๋ค() {
- // given
- final Player player = playerBuilder.init()
- .build();
-
- final CreatePlaceRequest createPlaceRequest = new CreatePlaceRequest("๋ฃจํฐํ๊ด",
- "์ด๊ณณ์ ์ญ์ฌ์ ์ ํต์ด ๊น์ ๋ฃจํฐํ๊ด์
๋๋ค.",
- 1.234,
- 5.6789,
- "image/url",
- player.getId(),
- 1L);
-
- // when
- final ExtractableResponse extract = given()
- .log().all()
- .auth().preemptive().basic(id, password)
- .contentType(MediaType.APPLICATION_JSON_VALUE)
- .body(createPlaceRequest)
- .when()
- .post("/places")
- .then()
- .log().all()
- .extract();
-
- // then
- final int statusCode = extract.statusCode();
- final PlaceResponse actual = extract.as(PlaceResponse.class);
- final Position position = Position.of(createPlaceRequest.latitude(),
- createPlaceRequest.longitude());
- final PlaceResponse expected = new PlaceResponse(getIdFromLocationHeader(extract),
- createPlaceRequest.name(),
- CoordinateResponse.from(position),
- createPlaceRequest.imageUrl(),
- createPlaceRequest.description());
- assertSoftly(softAssertions -> {
- softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.CREATED.value());
- softAssertions.assertThat(actual)
- .usingRecursiveComparison()
- .isEqualTo(expected);
- });
- }
+// @Test
+// void ์ฅ์_๋ฑ๋ก_์์ฒญ์ด_์ฑ๊ณตํ๋ฉด_201_์ํ์ฝ๋์_์์ฑ๋_์ฅ์๋ฅผ_์๋ตํ๋ค() {
+// // given
+// final Player player = playerBuilder.init()
+// .build();
+//
+// final CreatePlaceRequest createPlaceRequest = new CreatePlaceRequest("๋ฃจํฐํ๊ด",
+// "์ด๊ณณ์ ์ญ์ฌ์ ์ ํต์ด ๊น์ ๋ฃจํฐํ๊ด์
๋๋ค.",
+// 1.234,
+// 5.6789,
+// "image/url",
+// player.getId(),
+// 1L);
+//
+// // when
+// final ExtractableResponse extract = given()
+// .log().all()
+// .auth().preemptive().basic(id, password)
+// .contentType(MediaType.APPLICATION_JSON_VALUE)
+// .body(createPlaceRequest)
+// .when()
+// .post("/places")
+// .then()
+// .log().all()
+// .extract();
+//
+// // then
+// final int statusCode = extract.statusCode();
+// final PlaceResponse actual = extract.as(PlaceResponse.class);
+// final Position position = Position.of(createPlaceRequest.latitude(),
+// createPlaceRequest.longitude());
+// final PlaceResponse expected = new PlaceResponse(getIdFromLocationHeader(extract),
+// createPlaceRequest.name(),
+// CoordinateResponse.from(position),
+// createPlaceRequest.imageUrl(),
+// createPlaceRequest.description());
+// assertSoftly(softAssertions -> {
+// softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.CREATED.value());
+// softAssertions.assertThat(actual)
+// .usingRecursiveComparison()
+// .isEqualTo(expected);
+// });
+// }
@Test
void ์ฅ์๋ฅผ_์์ด๋๋ก_์กฐํํ๋ค() {
diff --git a/backend/src/test/java/com/now/naaga/place/service/PlaceServiceTest.java b/backend/src/test/java/com/now/naaga/place/service/PlaceServiceTest.java
index 75fa82586..c2e3f225d 100644
--- a/backend/src/test/java/com/now/naaga/place/service/PlaceServiceTest.java
+++ b/backend/src/test/java/com/now/naaga/place/service/PlaceServiceTest.java
@@ -1,5 +1,9 @@
package com.now.naaga.place.service;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
import com.now.naaga.common.builder.PlaceBuilder;
import com.now.naaga.common.exception.BaseExceptionType;
import com.now.naaga.common.fixture.PositionFixture;
@@ -9,8 +13,6 @@
import com.now.naaga.place.domain.Position;
import com.now.naaga.place.exception.PlaceException;
import com.now.naaga.place.exception.PlaceExceptionType;
-import io.restassured.internal.common.assertion.Assertion;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -19,11 +21,6 @@
import org.springframework.test.context.jdbc.Sql;
import org.springframework.transaction.annotation.Transactional;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
@ActiveProfiles("test")
@Sql("/truncate.sql")
@SpringBootTest
diff --git a/backend/src/test/java/com/now/naaga/player/application/PlayerServiceTest.java b/backend/src/test/java/com/now/naaga/player/application/PlayerServiceTest.java
index 593aa8b2b..c5a24b2e8 100644
--- a/backend/src/test/java/com/now/naaga/player/application/PlayerServiceTest.java
+++ b/backend/src/test/java/com/now/naaga/player/application/PlayerServiceTest.java
@@ -14,8 +14,6 @@
import com.now.naaga.score.domain.Score;
import java.util.ArrayList;
import java.util.List;
-
-import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
diff --git a/backend/src/test/java/com/now/naaga/player/persistence/repository/PlayerRepositoryTest.java b/backend/src/test/java/com/now/naaga/player/persistence/repository/PlayerRepositoryTest.java
index 6f554ce97..e977ebffa 100644
--- a/backend/src/test/java/com/now/naaga/player/persistence/repository/PlayerRepositoryTest.java
+++ b/backend/src/test/java/com/now/naaga/player/persistence/repository/PlayerRepositoryTest.java
@@ -5,13 +5,11 @@
import com.now.naaga.common.builder.PlayerBuilder;
import com.now.naaga.player.domain.Player;
import org.junit.jupiter.api.DisplayNameGeneration;
-import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
-import org.springframework.transaction.annotation.Transactional;
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(ReplaceUnderscores.class)
diff --git a/backend/src/test/java/com/now/naaga/player/presentation/PlayerControllerTest.java b/backend/src/test/java/com/now/naaga/player/presentation/PlayerControllerTest.java
index 26a0ea32e..327c177a5 100644
--- a/backend/src/test/java/com/now/naaga/player/presentation/PlayerControllerTest.java
+++ b/backend/src/test/java/com/now/naaga/player/presentation/PlayerControllerTest.java
@@ -1,5 +1,9 @@
package com.now.naaga.player.presentation;
+import static com.now.naaga.common.exception.CommonExceptionType.INVALID_REQUEST_PARAMETERS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+
import com.now.naaga.auth.domain.AuthToken;
import com.now.naaga.auth.infrastructure.AuthType;
import com.now.naaga.auth.infrastructure.jwt.AuthTokenGenerator;
@@ -13,6 +17,8 @@
import io.restassured.common.mapper.TypeRef;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
+import java.time.LocalDateTime;
+import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
@@ -21,13 +27,6 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
-import java.time.LocalDateTime;
-import java.util.List;
-
-import static com.now.naaga.common.exception.CommonExceptionType.INVALID_REQUEST_PARAMETERS;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(ReplaceUnderscores.class)
public class PlayerControllerTest extends CommonControllerTest {
diff --git a/backend/src/test/java/com/now/naaga/temporaryplace/application/TemporaryPlaceServiceTest.java b/backend/src/test/java/com/now/naaga/temporaryplace/application/TemporaryPlaceServiceTest.java
index 6261eeb8a..c94edf149 100644
--- a/backend/src/test/java/com/now/naaga/temporaryplace/application/TemporaryPlaceServiceTest.java
+++ b/backend/src/test/java/com/now/naaga/temporaryplace/application/TemporaryPlaceServiceTest.java
@@ -1,15 +1,21 @@
package com.now.naaga.temporaryplace.application;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
import com.now.naaga.common.builder.TemporaryPlaceBuilder;
+import com.now.naaga.common.infrastructure.AwsS3FileManager;
import com.now.naaga.temporaryplace.domain.TemporaryPlace;
import com.now.naaga.temporaryplace.repository.TemporaryPlaceRepository;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
@@ -19,31 +25,58 @@
@ActiveProfiles("test")
@SpringBootTest
class TemporaryPlaceServiceTest {
-
+
@Autowired
private TemporaryPlaceRepository temporaryPlaceRepository;
-
+
@Autowired
private TemporaryPlaceService temporaryPlaceService;
-
+
@Autowired
private TemporaryPlaceBuilder temporaryPlaceBuilder;
-
+
+ @MockBean
+ private AwsS3FileManager awsS3FileManager;
+
@Test
- void ID๋ก_๊ฒ์_์ฅ์_๋ฐ์ดํฐ๋ฅผ_์ญ์ ํ๋ค() {
+ void ์ฅ์๊ฐ_์์ฑ๋ _๋_ID๋ก_๊ฒ์_์ฅ์_๋ฐ์ดํฐ๋ง_์ญ์ ๋๋ค() {
// given
final TemporaryPlace temporaryPlace = temporaryPlaceBuilder.init()
.build();
-
+
final Long id = temporaryPlace.getId();
-
+
// when
- temporaryPlaceService.deleteById(id);
-
+ temporaryPlaceService.deleteByIdWhenPlaceCreated(id);
+
// then
final TemporaryPlace actual = temporaryPlaceRepository.findById(id)
.orElse(null);
-
- assertThat(actual).isNull();
+
+ assertAll(
+ () -> assertThat(actual).isNull(),
+ () -> verify(awsS3FileManager, times(0)).deleteFile(anyString())
+ );
+ }
+
+ @Test
+ void ๊ฒ์_์ฅ์_๋ฑ๋ก์ด_๊ฑฐ์ ๋ _๋_ID๋ก_๊ฒ์_์ฅ์_๋ฐ์ดํฐ_์ญ์ _๋ฐ_S3_์ด๋ฏธ์ง_ํ์ผ์ด_ํจ๊ป_์ญ์ ๋๋ค() {
+ // given
+ final TemporaryPlace temporaryPlace = temporaryPlaceBuilder.init()
+ .build();
+
+ final Long id = temporaryPlace.getId();
+
+ // when
+ temporaryPlaceService.deleteByIdWhenTemporaryPlaceDenied(id);
+
+ // then
+ final TemporaryPlace actual = temporaryPlaceRepository.findById(id)
+ .orElse(null);
+
+ assertAll(
+ () -> assertThat(actual).isNull(),
+ () -> verify(awsS3FileManager, times(1)).deleteFile(anyString())
+ );
}
}
diff --git a/backend/src/test/java/com/now/naaga/temporaryplace/presentation/TemporaryPlaceControllerTest.java b/backend/src/test/java/com/now/naaga/temporaryplace/presentation/TemporaryPlaceControllerTest.java
index cfb51f20b..a20681bf9 100644
--- a/backend/src/test/java/com/now/naaga/temporaryplace/presentation/TemporaryPlaceControllerTest.java
+++ b/backend/src/test/java/com/now/naaga/temporaryplace/presentation/TemporaryPlaceControllerTest.java
@@ -1,46 +1,34 @@
package com.now.naaga.temporaryplace.presentation;
+import static io.restassured.RestAssured.given;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.now.naaga.auth.domain.AuthToken;
-import com.now.naaga.auth.infrastructure.AuthType;
import com.now.naaga.auth.infrastructure.jwt.AuthTokenGenerator;
import com.now.naaga.common.CommonControllerTest;
import com.now.naaga.common.builder.PlaceBuilder;
import com.now.naaga.common.builder.PlayerBuilder;
import com.now.naaga.common.builder.TemporaryPlaceBuilder;
-import com.now.naaga.common.infrastructure.FileManager;
-import com.now.naaga.player.domain.Player;
import com.now.naaga.temporaryplace.domain.TemporaryPlace;
import com.now.naaga.temporaryplace.presentation.dto.TemporaryPlaceResponse;
import io.restassured.RestAssured;
-import io.restassured.builder.MultiPartSpecBuilder;
import io.restassured.common.mapper.TypeRef;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
+
+import java.io.FileNotFoundException;
+import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.ActiveProfiles;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.math.RoundingMode;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-
-import static com.now.naaga.common.fixture.TemporaryPlaceFixture.TEMPORARY_PLACE;
-import static io.restassured.RestAssured.given;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.SoftAssertions.assertSoftly;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doReturn;
@SuppressWarnings("NonAsciiCharacters")
@DisplayNameGeneration(ReplaceUnderscores.class)
@@ -59,8 +47,8 @@ class TemporaryPlaceControllerTest extends CommonControllerTest {
@Autowired
private AuthTokenGenerator authTokenGenerator;
- @SpyBean
- private FileManager fileManager;
+// @SpyBean
+// private FileManager fileManager;
@Value("${manager.id}")
private String id;
@@ -73,56 +61,56 @@ void setup() {
super.setUp();
}
- @Test
- void ๊ฒ์ํ _์ฅ์_๋ฑ๋ก_์์ฒญ์_๋ฐ์ผ๋ฉด_201_์ํ์ฝ๋์_ํจ๊ป_์ถ๊ฐ๋_๊ฒ์ํ _์ฅ์_์ ๋ณด๋ฅผ_์๋ตํ๋ค() throws FileNotFoundException {
- //given
- final Player player = playerBuilder.init()
- .build();
- final AuthToken generate = authTokenGenerator.generate(player.getMember(), 1L, AuthType.KAKAO);
- final String accessToken = generate.getAccessToken();
- final TemporaryPlace temporaryPlace = TEMPORARY_PLACE();
-
- doReturn(new File("/์์๊ฒฝ๋ก", "์ด๋ฏธ์ง.png")).when(fileManager)
- .save(any());
- //when
- final ExtractableResponse extract = given()
- .log().all()
- .multiPart(new MultiPartSpecBuilder(temporaryPlace.getName()).controlName("name").charset(StandardCharsets.UTF_8).build())
- .multiPart(new MultiPartSpecBuilder(temporaryPlace.getDescription()).controlName("description").charset(StandardCharsets.UTF_8).build())
- .multiPart(
- new MultiPartSpecBuilder(temporaryPlace.getPosition().getLatitude().setScale(6, RoundingMode.HALF_DOWN).doubleValue()).controlName(
- "latitude").charset(StandardCharsets.UTF_8).build())
- .multiPart(
- new MultiPartSpecBuilder(temporaryPlace.getPosition().getLongitude().setScale(6, RoundingMode.HALF_DOWN).doubleValue()).controlName(
- "longitude").charset(StandardCharsets.UTF_8).build())
- .multiPart(new MultiPartSpecBuilder(new FileInputStream(new File("src/test/java/com/now/naaga/temporaryplace/fixture/๋ฃจํฐํ๊ด.png"))).controlName(
- "imageFile").charset(StandardCharsets.UTF_8)
- .fileName(
- "src/test/java/com/now/naaga/temporaryplace/fixture/๋ฃจํฐํ๊ด.png")
- .mimeType(
- "image/png")
- .build())
- .header("Authorization", "Bearer " + accessToken)
- .when()
- .post("/temporary-places")
- .then()
- .log().all()
- .extract();
- final int statusCode = extract.statusCode();
- final String location = extract.header("Location");
- final TemporaryPlaceResponse actual = extract.as(TemporaryPlaceResponse.class);
- final TemporaryPlaceResponse expected = TemporaryPlaceResponse.from(temporaryPlace);
-
- //then
- assertSoftly(softAssertions -> {
- softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.CREATED.value());
- softAssertions.assertThat(location).isEqualTo("/temporary-places/" + actual.id());
- softAssertions.assertThat(actual)
- .usingRecursiveComparison()
- .ignoringFields("id", "imageUrl", "registeredPlayerId")
- .isEqualTo(expected);
- });
- }
+// @Test
+// void ๊ฒ์ํ _์ฅ์_๋ฑ๋ก_์์ฒญ์_๋ฐ์ผ๋ฉด_201_์ํ์ฝ๋์_ํจ๊ป_์ถ๊ฐ๋_๊ฒ์ํ _์ฅ์_์ ๋ณด๋ฅผ_์๋ตํ๋ค() throws FileNotFoundException {
+// //given
+// final Player player = playerBuilder.init()
+// .build();
+// final AuthToken generate = authTokenGenerator.generate(player.getMember(), 1L, AuthType.KAKAO);
+// final String accessToken = generate.getAccessToken();
+// final TemporaryPlace temporaryPlace = TEMPORARY_PLACE();
+//
+// doReturn(new File("/์์๊ฒฝ๋ก", "์ด๋ฏธ์ง.png")).when(fileManager)
+// .save(any());
+// //when
+// final ExtractableResponse extract = given()
+// .log().all()
+// .multiPart(new MultiPartSpecBuilder(temporaryPlace.getName()).controlName("name").charset(StandardCharsets.UTF_8).build())
+// .multiPart(new MultiPartSpecBuilder(temporaryPlace.getDescription()).controlName("description").charset(StandardCharsets.UTF_8).build())
+// .multiPart(
+// new MultiPartSpecBuilder(temporaryPlace.getPosition().getLatitude().setScale(6, RoundingMode.HALF_DOWN).doubleValue()).controlName(
+// "latitude").charset(StandardCharsets.UTF_8).build())
+// .multiPart(
+// new MultiPartSpecBuilder(temporaryPlace.getPosition().getLongitude().setScale(6, RoundingMode.HALF_DOWN).doubleValue()).controlName(
+// "longitude").charset(StandardCharsets.UTF_8).build())
+// .multiPart(new MultiPartSpecBuilder(new FileInputStream(new File("src/test/java/com/now/naaga/temporaryplace/fixture/๋ฃจํฐํ๊ด.png"))).controlName(
+// "imageFile").charset(StandardCharsets.UTF_8)
+// .fileName(
+// "src/test/java/com/now/naaga/temporaryplace/fixture/๋ฃจํฐํ๊ด.png")
+// .mimeType(
+// "image/png")
+// .build())
+// .header("Authorization", "Bearer " + accessToken)
+// .when()
+// .post("/temporary-places")
+// .then()
+// .log().all()
+// .extract();
+// final int statusCode = extract.statusCode();
+// final String location = extract.header("Location");
+// final TemporaryPlaceResponse actual = extract.as(TemporaryPlaceResponse.class);
+// final TemporaryPlaceResponse expected = TemporaryPlaceResponse.from(temporaryPlace);
+//
+// //then
+// assertSoftly(softAssertions -> {
+// softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.CREATED.value());
+// softAssertions.assertThat(location).isEqualTo("/temporary-places/" + actual.id());
+// softAssertions.assertThat(actual)
+// .usingRecursiveComparison()
+// .ignoringFields("id", "imageUrl", "registeredPlayerId")
+// .isEqualTo(expected);
+// });
+// }
@Test
void ๊ฒ์ํ _์ฅ์_๋ชฉ๋ก_์กฐํ_์์ฒญ์_๋ฐ์ผ๋ฉด_200_์ํ์ฝ๋์_ํจ๊ป_๊ฒ์ํ _์ฅ์_๋ชฉ๋ก์_์๋ตํ๋ค() throws FileNotFoundException, JsonProcessingException {
diff --git a/backend/src/test/resources/truncate.sql b/backend/src/test/resources/truncate.sql
index 59397b49b..b05fa514a 100644
--- a/backend/src/test/resources/truncate.sql
+++ b/backend/src/test/resources/truncate.sql
@@ -1,6 +1,7 @@
-SET
-FOREIGN_KEY_CHECKS = 0;
+SET FOREIGN_KEY_CHECKS = 0;
+TRUNCATE TABLE place_statistics;
+TRUNCATE TABLE place_like;
TRUNCATE TABLE place;
TRUNCATE TABLE member;
TRUNCATE TABLE player;
@@ -8,6 +9,8 @@ TRUNCATE TABLE game_result;
TRUNCATE TABLE game;
TRUNCATE TABLE hint;
TRUNCATE TABLE auth_token;
+TRUNCATE TABLE letter;
+TRUNCATE TABLE read_letter_log;
+TRUNCATE TABLE write_letter_log;
-SET
-FOREIGN_KEY_CHECKS = 1;
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/etc/images/google play store.png b/etc/images/google play store.png
new file mode 100644
index 000000000..6313ad11d
Binary files /dev/null and b/etc/images/google play store.png differ
diff --git a/etc/images/header.png b/etc/images/header.png
new file mode 100644
index 000000000..d637cedaa
Binary files /dev/null and b/etc/images/header.png differ
diff --git a/etc/images/service intro.png b/etc/images/service intro.png
new file mode 100644
index 000000000..edd044876
Binary files /dev/null and b/etc/images/service intro.png differ