diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a77ef705..22eccb54 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,7 +38,7 @@ jobs: shell: bash - name: ๐Ÿ˜ Gradle๋กœ ๋นŒ๋“œ ์‹คํ–‰ - run: ./gradlew build -x test + run: ./gradlew build - name: ๐Ÿ’ก ๋ฐฐํฌ ์ƒํƒœ๋ฅผ Slack์„ ํ†ตํ•ด ์ „์†กํ•ฉ๋‹ˆ๋‹ค. uses: rtCamp/action-slack-notify@v2 diff --git a/.github/workflows/deploy-test.yml b/.github/workflows/deploy-test.yml index c1c70f9a..f81407b9 100644 --- a/.github/workflows/deploy-test.yml +++ b/.github/workflows/deploy-test.yml @@ -46,7 +46,7 @@ jobs: shell: bash - name: ๐Ÿ˜ Gradle๋กœ ๋นŒ๋“œ ์‹คํ–‰ - run: ./gradlew build -x test + run: ./gradlew build - name: ๐Ÿ“ฆ ๋ฐฐํฌ๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•œ .zip ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. run: | diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 350e4eb4..f9b1ed79 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -46,7 +46,7 @@ jobs: shell: bash - name: ๐Ÿ˜ Gradle๋กœ ๋นŒ๋“œ ์‹คํ–‰ - run: ./gradlew build -x test + run: ./gradlew build - name: ๐Ÿ“ฆ ๋ฐฐํฌ๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•œ .zip ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9436ed8f..ae81427d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,9 +14,8 @@ on: branches: [ "develop", "staging" ] permissions: - contents: write checks: write - id-token: write + pull-requests: write jobs: build: @@ -52,7 +51,7 @@ jobs: run: ./gradlew test - name: ๐Ÿ’ฌ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ์ฝ”๋ฉ˜ํŠธ๋กœ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. - uses: EnricoMi/publish-unit-test-result-action@v1 + uses: EnricoMi/publish-unit-test-result-action@v2 if: always() with: files: '**/build/test-results/test/TEST-*.xml' diff --git a/.gitignore b/.gitignore index f0bc2dc8..bf013630 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,4 @@ firebase*.json ### monitoring ### monitoring/prometheus/volume -monitoring/grafana \ No newline at end of file +monitoring/grafana diff --git a/build.gradle b/build.gradle index 5098fcf6..ed6683ef 100644 --- a/build.gradle +++ b/build.gradle @@ -1,24 +1,27 @@ -buildscript { - ext { - queryDslVersion = "5.0.0" - } -} - plugins { id 'java' id 'org.springframework.boot' version '2.7.4' id 'io.spring.dependency-management' version '1.0.15.RELEASE' - id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10' + id "org.asciidoctor.jvm.convert" version "3.3.2" + id 'jacoco' } group = 'com.yello' version = '0.0.1-SNAPSHOT' +sourceCompatibility = '17' + +ext { + snippetsDir = file('build/generated-snippets') +} -java { - sourceCompatibility = '17' +test { + useJUnitPlatform() + finalizedBy 'jacocoTestReport' + outputs.dir snippetsDir } configurations { + asciidoctorExt compileOnly { extendsFrom annotationProcessor } @@ -32,31 +35,23 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.2' - // JPA & Database + // Repositories implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-data-redis' + implementation 'org.springframework.amqp:spring-rabbit:2.3.12' + + runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.mysql:mysql-connector-j:8.0.31' // Validations implementation 'org.springframework.boot:spring-boot-starter-validation' - // Health Check - implementation 'org.springframework.boot:spring-boot-starter-actuator' - runtimeOnly 'io.micrometer:micrometer-registry-prometheus' - - // JWT implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2' implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2' implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2' - - // Swagger - implementation 'org.springdoc:springdoc-openapi-ui:1.5.4' - // p6spy implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.7' @@ -67,20 +62,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'io.netty:netty-resolver-dns-native-macos:4.1.79.Final:osx-aarch_64' - - // QueryDSL - implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" - implementation "com.querydsl:querydsl-apt:${queryDslVersion}" - - runtimeOnly 'com.h2database:h2' - runtimeOnly 'com.mysql:mysql-connector-j:8.0.31' - // FCM implementation 'com.google.firebase:firebase-admin:9.2.0' - // rabbitmq - implementation 'org.springframework.amqp:spring-rabbit:2.3.12' - // slack-webhook implementation "net.gpedro.integrations.slack:slack-webhook:1.4.0" @@ -90,32 +74,72 @@ dependencies { // gson implementation 'com.google.code.gson:gson:2.10.1' -} -tasks.named('test') { - useJUnitPlatform() + // Testing + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.2' + asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' + testImplementation 'org.springframework.security:spring-security-test' } +asciidoctor { + inputs.dir snippetsDir + configurations 'asciidoctorExt' + dependsOn test +} -def querydslDir = "$buildDir/generated/querydsl" - -querydsl { - jpa = true - querydslSourcesDir = querydslDir +asciidoctor.doFirst { + delete file('src/docs/asciidocs') } -sourceSets { - main.java.srcDir querydslDir + +bootJar { + dependsOn asciidoctor + copy { + from asciidoctor.outputDir + into "src/main/resources/static/docs" + } } + configurations { compileOnly { extendsFrom annotationProcessor } - querydsl.extendsFrom compileClasspath -} -compileQuerydsl { - options.annotationProcessorPath = configurations.querydsl } -jar { - enabled = false -} \ No newline at end of file +jar.enabled = false + +jacoco.toolVersion = "0.8.7" +jacocoTestReport { + reports { + xml.enabled false + csv.enabled true + html.enabled true + + csv.destination file("${buildDir}/jacoco/index.csv") + html.destination file("${buildDir}/jacoco/index.html") + } +// finalizedBy 'jacocoTestCoverageVerification' +} +//jacocoTestCoverageVerification { +// violationRules { +// rule { +// enabled = true +// element = 'CLASS' +// +// limit { +// counter = 'METHOD' +// value = 'COVEREDRATIO' +// minimum = 0.60 +// } +// +// limit { +// counter = 'INSTRUCTION' +// value = 'COVEREDRATIO' +// minimum = 0.60 +// } +// +// excludes = ["*.dto", "*.dto.*", "*.ServerApplication", "*.configuration.*", "*.security.*", "*.exception.*", "*.util.*"] +// } +// } +//} diff --git a/src/docs/asciidoc/add-friend.adoc b/src/docs/asciidoc/add-friend.adoc new file mode 100644 index 00000000..aaa42bf8 --- /dev/null +++ b/src/docs/asciidoc/add-friend.adoc @@ -0,0 +1,13 @@ +== ์นœ๊ตฌ ์ถ”๊ฐ€ํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/friend/addFriend/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/friend/addFriend/path-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/friend/addFriend/http-response.adoc[] diff --git a/src/docs/asciidoc/apple.adoc b/src/docs/asciidoc/apple.adoc new file mode 100644 index 00000000..086e50a4 --- /dev/null +++ b/src/docs/asciidoc/apple.adoc @@ -0,0 +1,29 @@ +== Apple ๊ตฌ๋… ๊ตฌ๋งค ๊ฒ€์ฆํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/purchase/verifyAppleSubscriptionTransaction/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/purchase/verifyAppleSubscriptionTransaction/http-response.adoc[] + +== Apple ์—ด๋žŒ๊ถŒ ๊ตฌ๋งค ๊ฒ€์ฆํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/purchase/verifyAppleTicketTransaction/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/purchase/verifyAppleTicketTransaction/http-response.adoc[] + +== Apple ํ™˜๋ถˆํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/purchase/refundInAppApple/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/purchase/refundInAppApple/http-response.adoc[] diff --git a/src/docs/asciidoc/check-keyword.adoc b/src/docs/asciidoc/check-keyword.adoc new file mode 100644 index 00000000..9a9e6107 --- /dev/null +++ b/src/docs/asciidoc/check-keyword.adoc @@ -0,0 +1,13 @@ +== ํˆฌํ‘œ ํ‚ค์›Œ๋“œ ํ™•์ธํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/vote/checkKeyword/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/vote/checkKeyword/path-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/vote/checkKeyword/http-response.adoc[] diff --git a/src/docs/asciidoc/check-user-by-id.adoc b/src/docs/asciidoc/check-user-by-id.adoc new file mode 100644 index 00000000..941d2a53 --- /dev/null +++ b/src/docs/asciidoc/check-user-by-id.adoc @@ -0,0 +1,9 @@ +== ์œ ์ € ์ •๋ณด ์กฐํšŒํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/user/findUserById/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/user/findUserById/http-response.adoc[] diff --git a/src/docs/asciidoc/check-user.adoc b/src/docs/asciidoc/check-user.adoc new file mode 100644 index 00000000..f51ef64f --- /dev/null +++ b/src/docs/asciidoc/check-user.adoc @@ -0,0 +1,9 @@ +== ๋‚ด ์ •๋ณด ์กฐํšŒํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/user/findUser/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/user/findUser/http-response.adoc[] diff --git a/src/docs/asciidoc/check-vote-available.adoc b/src/docs/asciidoc/check-vote-available.adoc new file mode 100644 index 00000000..0d67b25f --- /dev/null +++ b/src/docs/asciidoc/check-vote-available.adoc @@ -0,0 +1,9 @@ +== ํˆฌํ‘œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ์กฐํšŒ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/vote/checkVoteAvailable/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/vote/checkVoteAvailable/http-response.adoc[] diff --git a/src/docs/asciidoc/create-vote.adoc b/src/docs/asciidoc/create-vote.adoc new file mode 100644 index 00000000..fb2b9761 --- /dev/null +++ b/src/docs/asciidoc/create-vote.adoc @@ -0,0 +1,10 @@ +== ํˆฌํ‘œ ์ƒ์„ฑํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/vote/createVote/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/vote/createVote/http-response.adoc[] + diff --git a/src/docs/asciidoc/delete-friend.adoc b/src/docs/asciidoc/delete-friend.adoc new file mode 100644 index 00000000..dd560fa5 --- /dev/null +++ b/src/docs/asciidoc/delete-friend.adoc @@ -0,0 +1,13 @@ +== ์นœ๊ตฌ ์‚ญ์ œํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/friend/deleteFriend/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/friend/deleteFriend/path-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/friend/deleteFriend/http-response.adoc[] diff --git a/src/docs/asciidoc/delete-user.adoc b/src/docs/asciidoc/delete-user.adoc new file mode 100644 index 00000000..910ab4bc --- /dev/null +++ b/src/docs/asciidoc/delete-user.adoc @@ -0,0 +1,9 @@ +== ์œ ์ € ํƒˆํ‡ดํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/user/deleteUser/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/user/deleteUser/http-response.adoc[] \ No newline at end of file diff --git a/src/docs/asciidoc/device-token.adoc b/src/docs/asciidoc/device-token.adoc new file mode 100644 index 00000000..6185c3da --- /dev/null +++ b/src/docs/asciidoc/device-token.adoc @@ -0,0 +1,9 @@ +== ๋””๋ฐ”์ด์Šค ํ† ํฐ ์ˆ˜์ •ํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/user/updateUserDeviceToken/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/user/updateUserDeviceToken/http-response.adoc[] diff --git a/src/docs/asciidoc/find-friend-votes.adoc b/src/docs/asciidoc/find-friend-votes.adoc new file mode 100644 index 00000000..c6bbe0d4 --- /dev/null +++ b/src/docs/asciidoc/find-friend-votes.adoc @@ -0,0 +1,13 @@ +== ์นœ๊ตฌ ํˆฌํ‘œ ์ „์ฒด ์กฐํšŒ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/vote/findAllFriendVotes/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/vote/findAllFriendVotes/request-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/vote/findAllFriendVotes/http-response.adoc[] diff --git a/src/docs/asciidoc/find-friends.adoc b/src/docs/asciidoc/find-friends.adoc new file mode 100644 index 00000000..6e1584ff --- /dev/null +++ b/src/docs/asciidoc/find-friends.adoc @@ -0,0 +1,14 @@ + +== ๋‚ด ์นœ๊ตฌ ์ „์ฒด ์กฐํšŒํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/friend/findAllFriend/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/friend/findAllFriend/request-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/friend/findAllFriend/http-response.adoc[] diff --git a/src/docs/asciidoc/find-group-friends.adoc b/src/docs/asciidoc/find-group-friends.adoc new file mode 100644 index 00000000..d252c9a1 --- /dev/null +++ b/src/docs/asciidoc/find-group-friends.adoc @@ -0,0 +1,13 @@ +== ๊ทธ๋ฃน ์ถ”์ฒœ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/friend/findAllRecommendSchoolFriends/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/friend/findAllRecommendSchoolFriends/request-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/friend/findAllRecommendSchoolFriends/http-response.adoc[] diff --git a/src/docs/asciidoc/find-kakao-friends.adoc b/src/docs/asciidoc/find-kakao-friends.adoc new file mode 100644 index 00000000..16b4ced0 --- /dev/null +++ b/src/docs/asciidoc/find-kakao-friends.adoc @@ -0,0 +1,13 @@ +== ์นด์นด์˜ค ์ถ”์ฒœ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/friend/findAllRecommendKakaoFriends/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/friend/findAllRecommendKakaoFriends/request-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/friend/findAllRecommendKakaoFriends/http-response.adoc[] diff --git a/src/docs/asciidoc/find-onboarding-friends.adoc b/src/docs/asciidoc/find-onboarding-friends.adoc new file mode 100644 index 00000000..f332948a --- /dev/null +++ b/src/docs/asciidoc/find-onboarding-friends.adoc @@ -0,0 +1,13 @@ +== ๊ฐ€์ž…ํ•œ ์นœ๊ตฌ ๋ชฉ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/auth/findOnBoardingFriends/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/auth/findOnBoardingFriends/request-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/auth/findOnBoardingFriends/http-response.adoc[] diff --git a/src/docs/asciidoc/find-question.adoc b/src/docs/asciidoc/find-question.adoc new file mode 100644 index 00000000..587fefec --- /dev/null +++ b/src/docs/asciidoc/find-question.adoc @@ -0,0 +1,9 @@ +== ํˆฌํ‘œ ์งˆ๋ฌธ ์กฐํšŒํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/vote/findVoteQuestions/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/vote/findVoteQuestions/http-response.adoc[] diff --git a/src/docs/asciidoc/find-vote.adoc b/src/docs/asciidoc/find-vote.adoc new file mode 100644 index 00000000..8b546e30 --- /dev/null +++ b/src/docs/asciidoc/find-vote.adoc @@ -0,0 +1,13 @@ +== ํˆฌํ‘œ ์ƒ์„ธ ์กฐํšŒ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/vote/findVoteById/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/vote/findVoteById/path-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/vote/findVoteById/http-response.adoc[] diff --git a/src/docs/asciidoc/find-votes.adoc b/src/docs/asciidoc/find-votes.adoc new file mode 100644 index 00000000..93df21d4 --- /dev/null +++ b/src/docs/asciidoc/find-votes.adoc @@ -0,0 +1,13 @@ +== ๋‚ด ํˆฌํ‘œ ์ „์ฒด ์กฐํšŒ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/vote/findAllMyVotes/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/vote/findAllMyVotes/request-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/vote/findAllMyVotes/http-response.adoc[] diff --git a/src/docs/asciidoc/get-unread-vote.adoc b/src/docs/asciidoc/get-unread-vote.adoc new file mode 100644 index 00000000..f8ddebda --- /dev/null +++ b/src/docs/asciidoc/get-unread-vote.adoc @@ -0,0 +1,9 @@ +== ์ฝ์ง€ ์•Š์€ ์ชฝ์ง€ ๊ฐœ์ˆ˜ ์กฐํšŒ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/vote/getUnreadVoteCount/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/vote/getUnreadVoteCount/http-response.adoc[] diff --git a/src/docs/asciidoc/google.adoc b/src/docs/asciidoc/google.adoc new file mode 100644 index 00000000..8b2450e5 --- /dev/null +++ b/src/docs/asciidoc/google.adoc @@ -0,0 +1,19 @@ +== Google ๊ตฌ๋… ๊ตฌ๋งค ๊ฒ€์ฆํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/purchase/verifyGoogleSubscriptionTransaction/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/purchase/verifyGoogleSubscriptionTransaction/http-response.adoc[] + +== Google ์—ด๋žŒ๊ถŒ ๊ตฌ๋งค ๊ฒ€์ฆํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/purchase/verifyGoogleTicketTransaction/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/purchase/verifyGoogleTicketTransaction/http-response.adoc[] \ No newline at end of file diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc new file mode 100644 index 00000000..d51d39c7 --- /dev/null +++ b/src/docs/asciidoc/index.adoc @@ -0,0 +1,84 @@ += YELL:O API ๋ฌธ์„œ +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toclevels: 3 +:sectlinks: + +[[API-List]] +== APIs + +=== Auth API + +* link:login.html[๋กœ๊ทธ์ธ] + +* link:signup.html[ํšŒ์›๊ฐ€์ž…] + +* link:find-onboarding-friends.html[๊ฐ€์ž…ํ•œ ์นœ๊ตฌ ๋ชฉ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ] + +* link:search-school.html[๋Œ€ํ•™๊ต ๊ฒ€์ƒ‰ํ•˜๊ธฐ] + +* link:search-department.html[๋Œ€ํ•™๊ต ํ•™๊ณผ ๊ฒ€์ƒ‰ํ•˜๊ธฐ] + +* link:reissue-token.html[ํ† ํฐ ์žฌ๋ฐœ๊ธ‰] + +=== User API + +* link:check-user.html[๋‚ด ์ •๋ณด ์กฐํšŒํ•˜๊ธฐ] + +* link:check-user-by-id.html[ํŠน์ • ์œ ์ € ์ •๋ณด ์กฐํšŒํ•˜๊ธฐ] + +* link:device-token.html[๋””๋ฐ”์ด์Šค ํ† ํฐ ์ˆ˜์ •ํ•˜๊ธฐ] + +* link:delete-user.html[์œ ์ € ํƒˆํ‡ด] + +=== Vote API + +* link:find-votes.html[๋‚ด ํˆฌํ‘œ ์ „์ฒด ์กฐํšŒํ•˜๊ธฐ] + +* link:find-friend-votes.html[์นœ๊ตฌ ํˆฌํ‘œ ์ „์ฒด ์กฐํšŒํ•˜๊ธฐ] + +* link:find-friend-votes.html[์ฝ์ง€ ์•Š์€ ์ชฝ์ง€ ๊ฐœ์ˆ˜ ์กฐํšŒํ•˜๊ธฐ] + +* link:find-vote.html[ํˆฌํ‘œ ์ƒ์„ธ ์กฐํšŒํ•˜๊ธฐ] + +* link:find-question.html[ํˆฌํ‘œ ์งˆ๋ฌธ ์กฐํšŒํ•˜๊ธฐ] + +* link:check-vote-available.html[ํˆฌํ‘œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ์กฐํšŒํ•˜๊ธฐ] + +* link:create-vote.html[ํˆฌํ‘œ ์ƒ์„ฑํ•˜๊ธฐ] + +* link:reveal-name.html[ํˆฌํ‘œ ์ด๋ฆ„ ๋ถ€๋ถ„ ์กฐํšŒํ•˜๊ธฐ] + +* link:reveal-full-name.html[ํˆฌํ‘œ ์ด๋ฆ„ ์ „์ฒด ์กฐํšŒํ•˜๊ธฐ] + +=== Friend API + +* link:add-friend.html[์นœ๊ตฌ ์ถ”๊ฐ€ํ•˜๊ธฐ] + +* link:find-friends.html[์นœ๊ตฌ ์ „์ฒด ์กฐํšŒํ•˜๊ธฐ] + +* link:shuffle-friends.html[์…”ํ”Œ๋œ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ] + +* link:find-group-friends.html[๊ทธ๋ฃน ์ถ”์ฒœ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ] + +* link:find-kakao-friends.html[์นด์นด์˜ค ์ถ”์ฒœ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ] + +* link:delete-friend.html[์นœ๊ตฌ ๋Š๊ธฐ] + +* link:search-friend.html[์นœ๊ตฌ ๊ฒ€์ƒ‰ํ•˜๊ธฐ] + +=== Purchase API + +* link:apple.html[Apple ๊ฒฐ์ œ ๊ด€๋ จ API] + +* link:google.html[Google ๊ฒฐ์ œ ๊ด€๋ จ API] + +* link:sub-check.html[๊ตฌ๋… ์—ฐ์žฅ ์œ ๋„ ํ•„์š” ์—ฌ๋ถ€ ํ™•์ธํ•˜๊ธฐ] + +* link:purchase-check.html[๊ตฌ๋… ์ƒํƒœ ๋ฐ ์—ด๋žŒ๊ถŒ ๊ฐœ์ˆ˜ ์กฐํšŒํ•˜๊ธฐ] + +=== Pay API + +* link:pay.html[๊ฒฐ์ œ ์ „ํ™˜์œจ ์ฒดํฌ] diff --git a/src/docs/asciidoc/login.adoc b/src/docs/asciidoc/login.adoc new file mode 100644 index 00000000..76d52f76 --- /dev/null +++ b/src/docs/asciidoc/login.adoc @@ -0,0 +1,11 @@ +== ์†Œ์…œ ๋กœ๊ทธ์ธ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/auth/oauthLogin/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/auth/oauthLogin/http-response.adoc[] + + diff --git a/src/docs/asciidoc/overview.adoc b/src/docs/asciidoc/overview.adoc new file mode 100644 index 00000000..09d6069a --- /dev/null +++ b/src/docs/asciidoc/overview.adoc @@ -0,0 +1,40 @@ +[[overview]] +== Overview + +[[overview-host]] +=== Host + +|=== +| ํ™˜๊ฒฝ | Host + +| Development +| `BEํŒ€์—๊ฒŒ ๋ฌธ์˜` + +| Production +| `BEํŒ€์—๊ฒŒ ๋ฌธ์˜` +|=== + +[[overview-http-status-codes]] +=== HTTP status codes + +|=== +| ์ƒํƒœ ์ฝ”๋“œ | ์„ค๋ช… + +| `200 OK` +| ์„ฑ๊ณต + +| `400 Bad Request` +| ์ž˜๋ชป๋œ ์š”์ฒญ + +| `401 Unauthorized` +| ๋น„์ธ์ฆ ์ƒํƒœ + +| `403 Forbidden` +| ๊ถŒํ•œ ๊ฑฐ๋ถ€ + +| `404 Not Found` +| ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์š”์ฒญ ๋ฆฌ์†Œ์Šค + +| `500 Internal Server Error` +| ์„œ๋ฒ„ ์—๋Ÿฌ +|=== diff --git a/src/docs/asciidoc/pay.adoc b/src/docs/asciidoc/pay.adoc new file mode 100644 index 00000000..e20bec39 --- /dev/null +++ b/src/docs/asciidoc/pay.adoc @@ -0,0 +1,9 @@ +== ์นœ๊ตฌ ์ถ”๊ฐ€ํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/pay/postPayCount/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/pay/postPayCount/http-response.adoc[] diff --git a/src/docs/asciidoc/purchase-check.adoc b/src/docs/asciidoc/purchase-check.adoc new file mode 100644 index 00000000..43c648dd --- /dev/null +++ b/src/docs/asciidoc/purchase-check.adoc @@ -0,0 +1,9 @@ +== ๊ตฌ๋… ์ƒํƒœ ๋ฐ ์—ด๋žŒ๊ถŒ ๊ฐœ์ˆ˜ ์กฐํšŒํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/purchase/getUserPurchaseInfo/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/purchase/getUserPurchaseInfo/http-response.adoc[] diff --git a/src/docs/asciidoc/reissue-token.adoc b/src/docs/asciidoc/reissue-token.adoc new file mode 100644 index 00000000..663fb5b8 --- /dev/null +++ b/src/docs/asciidoc/reissue-token.adoc @@ -0,0 +1,12 @@ + +== ํ† ํฐ ์žฌ๋ฐœ๊ธ‰ + +operation::api/v1/auth/reIssueToken[snippets='http-request,http-response'] + +=== ์š”์ฒญ + +include::{snippets}/api/v1/auth/reIssueToken/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/auth/reIssueToken/http-response.adoc[] \ No newline at end of file diff --git a/src/docs/asciidoc/reveal-full-name.adoc b/src/docs/asciidoc/reveal-full-name.adoc new file mode 100644 index 00000000..c98234c9 --- /dev/null +++ b/src/docs/asciidoc/reveal-full-name.adoc @@ -0,0 +1,13 @@ +== ํˆฌํ‘œ ์ด๋ฆ„ ์ „์ฒด ์กฐํšŒ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/vote/revealFullName/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/vote/revealFullName/path-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/vote/revealFullName/http-response.adoc[] \ No newline at end of file diff --git a/src/docs/asciidoc/reveal-name.adoc b/src/docs/asciidoc/reveal-name.adoc new file mode 100644 index 00000000..d40c61fa --- /dev/null +++ b/src/docs/asciidoc/reveal-name.adoc @@ -0,0 +1,13 @@ +== ํˆฌํ‘œ ์ด๋ฆ„ ๋ถ€๋ถ„ ์กฐํšŒ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/vote/revealNameHint/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/vote/revealNameHint/path-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/vote/revealNameHint/http-response.adoc[] \ No newline at end of file diff --git a/src/docs/asciidoc/search-department.adoc b/src/docs/asciidoc/search-department.adoc new file mode 100644 index 00000000..467e457a --- /dev/null +++ b/src/docs/asciidoc/search-department.adoc @@ -0,0 +1,13 @@ +== ๋Œ€ํ•™๊ต ํ•™๊ณผ ๊ฒ€์ƒ‰ํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/auth/findDepartmentsByKeyword/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/auth/findDepartmentsByKeyword/request-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/auth/findDepartmentsByKeyword/http-response.adoc[] diff --git a/src/docs/asciidoc/search-friend.adoc b/src/docs/asciidoc/search-friend.adoc new file mode 100644 index 00000000..f2cef4f3 --- /dev/null +++ b/src/docs/asciidoc/search-friend.adoc @@ -0,0 +1,15 @@ + + +== ์นœ๊ตฌ ๊ฒ€์ƒ‰ํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/friend/searchFriend/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/friend/searchFriend/request-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/friend/searchFriend/http-response.adoc[] diff --git a/src/docs/asciidoc/search-school.adoc b/src/docs/asciidoc/search-school.adoc new file mode 100644 index 00000000..e3713fa6 --- /dev/null +++ b/src/docs/asciidoc/search-school.adoc @@ -0,0 +1,13 @@ +== ๋Œ€ํ•™๊ต ๊ฒ€์ƒ‰ํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/auth/findSchoolsByKeyword/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/auth/findSchoolsByKeyword/request-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/auth/findSchoolsByKeyword/http-response.adoc[] diff --git a/src/docs/asciidoc/shuffle-friends.adoc b/src/docs/asciidoc/shuffle-friends.adoc new file mode 100644 index 00000000..77b77bac --- /dev/null +++ b/src/docs/asciidoc/shuffle-friends.adoc @@ -0,0 +1,9 @@ +== ์…”ํ”Œํ•œ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/friend/findShuffledFriend/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/friend/findShuffledFriend/http-response.adoc[] diff --git a/src/docs/asciidoc/signup.adoc b/src/docs/asciidoc/signup.adoc new file mode 100644 index 00000000..bd5481cb --- /dev/null +++ b/src/docs/asciidoc/signup.adoc @@ -0,0 +1,9 @@ +== ํšŒ์›๊ฐ€์ž… + +=== ์š”์ฒญ + +include::{snippets}/api/v1/auth/postSignUp/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/auth/postSignUp/http-response.adoc[] \ No newline at end of file diff --git a/src/docs/asciidoc/sub-check.adoc b/src/docs/asciidoc/sub-check.adoc new file mode 100644 index 00000000..00a19bdf --- /dev/null +++ b/src/docs/asciidoc/sub-check.adoc @@ -0,0 +1,9 @@ +== ๊ตฌ๋… ์—ฐ์žฅ ์œ ๋„ ํ•„์š” ์—ฌ๋ถ€ ํ™•์ธํ•˜๊ธฐ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/purchase/getUserSubscribeNeeded/http-request.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/purchase/getUserSubscribeNeeded/http-response.adoc[] diff --git a/src/docs/asciidoc/validate-yelloid.adoc b/src/docs/asciidoc/validate-yelloid.adoc new file mode 100644 index 00000000..a917061b --- /dev/null +++ b/src/docs/asciidoc/validate-yelloid.adoc @@ -0,0 +1,13 @@ +== ์˜๋กœ ์•„์ด๋”” ์ค‘๋ณต ํ™•์ธ + +=== ์š”์ฒญ + +include::{snippets}/api/v1/auth/getYelloIdValidation/http-request.adoc[] + +=== ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ + +include::{snippets}/api/v1/auth/getYelloIdValidation/request-parameters.adoc[] + +=== ์‘๋‹ต + +include::{snippets}/api/v1/auth/getYelloIdValidation/http-response.adoc[] diff --git a/src/main/java/com/yello/server/ServerApplication.java b/src/main/java/com/yello/server/ServerApplication.java index 925d86c1..91b6def6 100644 --- a/src/main/java/com/yello/server/ServerApplication.java +++ b/src/main/java/com/yello/server/ServerApplication.java @@ -2,10 +2,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -@EnableJpaAuditing @SpringBootApplication public class ServerApplication { diff --git a/src/main/java/com/yello/server/domain/authorization/controller/AuthController.java b/src/main/java/com/yello/server/domain/authorization/controller/AuthController.java index 35ff9291..492aa2f9 100644 --- a/src/main/java/com/yello/server/domain/authorization/controller/AuthController.java +++ b/src/main/java/com/yello/server/domain/authorization/controller/AuthController.java @@ -21,11 +21,6 @@ import com.yello.server.domain.authorization.service.AuthService; import com.yello.server.global.common.annotation.ServiceToken; import com.yello.server.global.common.dto.BaseResponse; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; import javax.validation.Valid; import javax.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; @@ -37,7 +32,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -@Tag(name = "03. Authentication") @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/auth") @@ -45,45 +39,24 @@ public class AuthController { private final AuthService authService; - @Operation(summary = "์†Œ์…œ ๋กœ๊ทธ์ธ API", responses = { - @ApiResponse( - responseCode = "201", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = OAuthResponse.class))), - }) @PostMapping("/oauth") public BaseResponse oauthLogin(@RequestBody OAuthRequest oAuthRequest) { val data = authService.oauthLogin(oAuthRequest); return BaseResponse.success(LOGIN_SUCCESS, data); } - @Operation(summary = "์˜๋กœ ์•„์ด๋”” ์ค‘๋ณต ํ™•์ธ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Boolean.class))), - }) @GetMapping("/valid") public BaseResponse getYelloIdValidation(@RequestParam("yelloId") String yelloId) { val data = authService.isYelloIdDuplicated(yelloId); return BaseResponse.success(YELLOID_VALIDATION_SUCCESS, data); } - @Operation(summary = "ํšŒ์›๊ฐ€์ž… API", responses = { - @ApiResponse( - responseCode = "201", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = SignUpResponse.class))), - }) @PostMapping("/signup") - public BaseResponse postSignUp( - @Valid @RequestBody SignUpRequest signUpRequest) { + public BaseResponse postSignUp(@Valid @RequestBody SignUpRequest signUpRequest) { val data = authService.signUp(signUpRequest); return BaseResponse.success(SIGN_UP_SUCCESS, data); } - @Operation(summary = "๊ฐ€์ž…ํ•œ ์นœ๊ตฌ ๋ชฉ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = OnBoardingFriendResponse.class))), - }) @PostMapping("/friend") public BaseResponse postFriendList( @Valid @RequestBody OnBoardingFriendRequest friendRequest, @@ -93,40 +66,25 @@ public BaseResponse postFriendList( return BaseResponse.success(ONBOARDING_FRIENDS_SUCCESS, data); } - @Operation(summary = "๋Œ€ํ•™๊ต ์ด๋ฆ„ ๊ฒ€์ƒ‰ํ•˜๊ธฐ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = GroupNameSearchResponse.class))), - }) - @GetMapping("/school/school") + @GetMapping("/school") public BaseResponse getSchoolList( - @NotNull @RequestParam("search") String keyword, + @NotNull @RequestParam("keyword") String keyword, @NotNull @RequestParam("page") Integer page ) { - val data = authService.findSchoolsBySearch(keyword, createPageable(page)); + val data = authService.findSchoolsByKeyword(keyword, createPageable(page)); return BaseResponse.success(SCHOOL_NAME_SEARCH_SCHOOL_SUCCESS, data); } - @Operation(summary = "๋Œ€ํ•™๊ต ์ด๋ฆ„์œผ๋กœ ํ•™๊ณผ ์ด๋ฆ„ ๊ฒ€์ƒ‰ํ•˜๊ธฐ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = DepartmentSearchResponse.class))), - }) @GetMapping("/school/department") public BaseResponse getDepartmentList( @NotNull @RequestParam("school") String schoolName, - @NotNull @RequestParam("search") String keyword, + @NotNull @RequestParam("keyword") String keyword, @NotNull @RequestParam("page") Integer page ) { - val data = authService.findDepartmentsBySearch(schoolName, keyword, createPageable(page)); + val data = authService.findDepartmentsByKeyword(schoolName, keyword, createPageable(page)); return BaseResponse.success(DEPARTMENT_NAME_SEARCH_BY_SCHOOL_NAME_SCHOOL_SUCCESS, data); } - @Operation(summary = "ํ† ํฐ ์žฌ๋ฐœ๊ธ‰ API", responses = { - @ApiResponse( - responseCode = "201", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = ServiceTokenVO.class))), - }) @PostMapping("/token/issue") public BaseResponse postReIssueToken(@ServiceToken ServiceTokenVO tokens) { val data = authService.reIssueToken(tokens); diff --git a/src/main/java/com/yello/server/domain/authorization/filter/JwtExceptionFilter.java b/src/main/java/com/yello/server/domain/authorization/filter/JwtExceptionFilter.java index 92c603e3..ecd3df30 100644 --- a/src/main/java/com/yello/server/domain/authorization/filter/JwtExceptionFilter.java +++ b/src/main/java/com/yello/server/domain/authorization/filter/JwtExceptionFilter.java @@ -41,7 +41,7 @@ protected void doFilterInternal( val requestPath = request.getServletPath(); if (requestPath.equals("/") - || requestPath.startsWith("/swagger-ui") || requestPath.startsWith("/v3/api-docs") + || requestPath.startsWith("/docs") || requestPath.startsWith("/actuator") || requestPath.startsWith("/prometheus") || requestPath.startsWith("/api/v1/auth")) { filterChain.doFilter(request, response); diff --git a/src/main/java/com/yello/server/domain/authorization/filter/JwtFilter.java b/src/main/java/com/yello/server/domain/authorization/filter/JwtFilter.java index 1dc63784..d96e535f 100644 --- a/src/main/java/com/yello/server/domain/authorization/filter/JwtFilter.java +++ b/src/main/java/com/yello/server/domain/authorization/filter/JwtFilter.java @@ -34,7 +34,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse final String requestPath = request.getServletPath(); if (requestPath.equals("/") - || requestPath.startsWith("/swagger-ui") || requestPath.startsWith("/v3/api-docs") + || requestPath.startsWith("/docs") || requestPath.startsWith("/actuator") || requestPath.startsWith("/prometheus") || requestPath.startsWith("/api/v1/auth")) { filterChain.doFilter(request, response); diff --git a/src/main/java/com/yello/server/domain/authorization/service/AuthManagerImpl.java b/src/main/java/com/yello/server/domain/authorization/service/AuthManagerImpl.java index d46e7bae..b161037d 100644 --- a/src/main/java/com/yello/server/domain/authorization/service/AuthManagerImpl.java +++ b/src/main/java/com/yello/server/domain/authorization/service/AuthManagerImpl.java @@ -71,7 +71,7 @@ public void validateSignupRequest(SignUpRequest signUpRequest) { throw new UserConflictException(UUID_CONFLICT_USER_EXCEPTION); }); - userRepository.findByYelloId(signUpRequest.yelloId()) + userRepository.findByYelloIdNotFiltered(signUpRequest.yelloId()) .ifPresent(action -> { throw new UserConflictException(YELLOID_CONFLICT_USER_EXCEPTION); }); @@ -81,7 +81,7 @@ public void validateSignupRequest(SignUpRequest signUpRequest) { public Boolean renewUserData(User user) { final Long userId = user.getId(); - if (user.getDeletedAt()!=null) { + if (user.getDeletedAt() != null) { user.renew(); friendRepository.findAllByUserIdNotFiltered(userId) diff --git a/src/main/java/com/yello/server/domain/authorization/service/AuthService.java b/src/main/java/com/yello/server/domain/authorization/service/AuthService.java index d5349c89..972e0b28 100644 --- a/src/main/java/com/yello/server/domain/authorization/service/AuthService.java +++ b/src/main/java/com/yello/server/domain/authorization/service/AuthService.java @@ -80,7 +80,7 @@ public Boolean isYelloIdDuplicated(String yelloId) { throw new AuthBadRequestException(YELLOID_REQUIRED_EXCEPTION); } - return userRepository.findByYelloId(yelloId).isPresent(); + return userRepository.findByYelloIdNotFiltered(yelloId).isPresent(); } @Transactional @@ -103,7 +103,7 @@ public SignUpResponse signUp(SignUpRequest signUpRequest) { @Transactional public void recommendUser(String recommendYelloId, String userYelloId) { - if (recommendYelloId!=null && !recommendYelloId.isEmpty()) { + if (recommendYelloId != null && !recommendYelloId.isEmpty()) { User recommendedUser = userRepository.getByYelloId(recommendYelloId); User user = userRepository.getByYelloId(userYelloId); @@ -147,14 +147,14 @@ public OnBoardingFriendResponse findOnBoardingFriends(OnBoardingFriendRequest fr return OnBoardingFriendResponse.of(kakaoFriends.size(), pageList); } - public GroupNameSearchResponse findSchoolsBySearch(String keyword, Pageable pageable) { + public GroupNameSearchResponse findSchoolsByKeyword(String keyword, Pageable pageable) { int totalCount = schoolRepository.countDistinctSchoolNameContaining(keyword); final List nameList = schoolRepository.findDistinctSchoolNameContaining(keyword, pageable); return GroupNameSearchResponse.of(totalCount, nameList); } - public DepartmentSearchResponse findDepartmentsBySearch(String schoolName, String keyword, + public DepartmentSearchResponse findDepartmentsByKeyword(String schoolName, String keyword, Pageable pageable) { int totalCount = schoolRepository.countAllBySchoolNameContaining(schoolName, keyword); final List schoolResult = schoolRepository.findAllBySchoolNameContaining(schoolName, diff --git a/src/main/java/com/yello/server/domain/friend/controller/FriendController.java b/src/main/java/com/yello/server/domain/friend/controller/FriendController.java index a59d6370..85838714 100644 --- a/src/main/java/com/yello/server/domain/friend/controller/FriendController.java +++ b/src/main/java/com/yello/server/domain/friend/controller/FriendController.java @@ -18,13 +18,6 @@ import com.yello.server.global.common.annotation.AccessTokenUser; import com.yello.server.global.common.dto.BaseResponse; import com.yello.server.infrastructure.firebase.service.NotificationService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.ArraySchema; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; import javax.validation.Valid; import lombok.RequiredArgsConstructor; @@ -39,7 +32,6 @@ import org.springframework.web.bind.annotation.RestController; -@Tag(name = "02. Friend") @RestController @RequestMapping("/api/v1/friend") @RequiredArgsConstructor @@ -48,57 +40,27 @@ public class FriendController { private final FriendService friendService; private final NotificationService notificationService; - @Operation(summary = "์นœ๊ตฌ ์ถ”๊ฐ€ํ•˜๊ธฐ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json") - ) - }) @PostMapping("/{targetId}") - public BaseResponse addFriend( - @Parameter(name = "targetId", description = "์นœ๊ตฌ ์‹ ์ฒญํ•  ์ƒ๋Œ€ ์œ ์ €์˜ ์•„์ด๋”” ๊ฐ’ ์ž…๋‹ˆ๋‹ค.") - @Valid @PathVariable Long targetId, - @AccessTokenUser User user) { + public BaseResponse addFriend(@Valid @PathVariable Long targetId, @AccessTokenUser User user) { val data = friendService.addFriend(user.getId(), targetId); notificationService.sendFriendNotification(data); return BaseResponse.success(ADD_FRIEND_SUCCESS); } - @Operation(summary = "๋‚ด ์นœ๊ตฌ ์ „์ฒด ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = FriendsResponse.class)) - ) - }) @GetMapping - public BaseResponse findAllFriend( - @Parameter(name = "page", description = "ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค.", example = "1") - @Valid @RequestParam Integer page, - @AccessTokenUser User user) { + public BaseResponse findAllFriend(@Valid @RequestParam Integer page, @AccessTokenUser User user) { val data = friendService.findAllFriends(createPageableLimitTen(page), user.getId()); return BaseResponse.success(READ_FRIEND_SUCCESS, data); } - @Operation(summary = "์นœ๊ตฌ ์…”ํ”Œ ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = FriendShuffleResponse.class)))) - }) @GetMapping("/shuffle") - public BaseResponse> findShuffledFriend( - @AccessTokenUser User user) { + public BaseResponse> findShuffledFriend(@AccessTokenUser User user) { val friendShuffleResponse = friendService.findShuffledFriend(user.getId()); return BaseResponse.success(SHUFFLE_FRIEND_SUCCESS, friendShuffleResponse); } - @Operation(summary = "๊ทธ๋ฃน ์ถ”์ฒœ์นœ๊ตฌ ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = RecommendFriendResponse.class))) - }) @GetMapping("/recommend/school") public BaseResponse recommendSchoolFriend( - @Parameter(name = "page", description = "ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค.", example = "1") @Valid @RequestParam Integer page, @AccessTokenUser User user ) { @@ -107,51 +69,37 @@ public BaseResponse recommendSchoolFriend( return BaseResponse.success(READ_FRIEND_SUCCESS, data); } - @Operation(summary = "์นด์นด์˜ค ์ถ”์ฒœ ์นœ๊ตฌ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = RecommendFriendResponse.class))) - }) @PostMapping("/recommend/kakao") public BaseResponse recommendKakaoFriend( @RequestBody KakaoRecommendRequest request, @Valid @RequestParam Integer page, @AccessTokenUser User user ) { - val data = - friendService.findAllRecommendKakaoFriends(createPageableByNameSort(page), user.getId(), - request); + val data = friendService.findAllRecommendKakaoFriends( + createPageableByNameSort(page), + user.getId(), + request + ); return BaseResponse.success(READ_FRIEND_SUCCESS, data); } - @Operation(summary = "์นœ๊ตฌ ์‚ญ์ œํ•˜๊ธฐ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json")) - }) @DeleteMapping("/{targetId}") - public BaseResponse deleteFriend( - @Parameter(name = "targetId", description = "์‚ญ์ œํ•  ์นœ๊ตฌ ์œ ์ €์˜ ์•„์ด๋”” ๊ฐ’ ์ž…๋‹ˆ๋‹ค.") - @Valid @PathVariable Long targetId, - @AccessTokenUser User user) { + public BaseResponse deleteFriend(@Valid @PathVariable Long targetId, @AccessTokenUser User user) { friendService.deleteFriend(user.getId(), targetId); return BaseResponse.success(DELETE_FRIEND_SUCCESS); } - @Operation(summary = "์นœ๊ตฌ ๊ฒ€์ƒ‰ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = RecommendFriendResponse.class))) - }) @GetMapping("/search") public BaseResponse searchFriend( @AccessTokenUser User user, @Valid @RequestParam("page") Integer page, @Valid @RequestParam("keyword") String keyword ) { - val data = - friendService.searchFriend(user.getId(), createPageableLimitTen(page), keyword); - // ์ด๋ฆ„์ด ํ•œ๊ธ€์ธ๊ฒฝ์šฐ, ์˜์–ด์ธ๊ฒฝ์šฐ ์ฒดํฌ + val data = friendService.searchFriend( + user.getId(), + createPageableLimitTen(page), + keyword + ); return BaseResponse.success(FRIEND_SEARCH_SUCCESS, data); } } diff --git a/src/main/java/com/yello/server/domain/friend/dto/response/RecommendFriendResponse.java b/src/main/java/com/yello/server/domain/friend/dto/response/RecommendFriendResponse.java index 3a7306de..296744ee 100644 --- a/src/main/java/com/yello/server/domain/friend/dto/response/RecommendFriendResponse.java +++ b/src/main/java/com/yello/server/domain/friend/dto/response/RecommendFriendResponse.java @@ -1,16 +1,12 @@ package com.yello.server.domain.friend.dto.response; -import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; import lombok.Builder; @Builder public record RecommendFriendResponse( - @Schema(description = "ํ•ด๋‹น ์œ ์ €์˜ ์นœ๊ตฌ๋“ค์ด ๋ฐ›์€ ์ด ํˆฌํ‘œ ๊ฐœ์ˆ˜") Integer totalCount, - @Schema(description = "ํ•ด๋‹น ์œ ์ €์˜ ์นœ๊ตฌ๋“ค์ด ๋ฐ›์€ ์ด ํˆฌํ‘œ") List friends - ) { public static RecommendFriendResponse of(Integer totalCount, List friends) { @@ -19,5 +15,4 @@ public static RecommendFriendResponse of(Integer totalCount, List verifyGoogleSubscriptionTransaction( + @PostMapping("/google/verify/subscribe") + @SlackPurchaseNotification + public BaseResponse verifyGoogleSubscriptionTransaction( @AccessTokenUser User user, - @RequestBody GoogleSubscriptionV2GetRequest request + @RequestBody GoogleSubscriptionGetRequest request ) throws IOException { val data = purchaseService.verifyGoogleSubscriptionTransaction(user.getId(), request); return BaseResponse.success(GOOGLE_PURCHASE_SUBSCRIPTION_VERIFY_SUCCESS, data); } - @Operation(summary = "๊ตฌ๊ธ€ ์—ด๋žŒ๊ถŒ ๊ฒฐ์ œ ์ •๋ณด ๊ฒ€์ฆํ•˜๊ธฐ API", responses = { - @ApiResponse( - responseCode = "201", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = GoogleInAppGetResponse.class)) - ) - }) - @PostMapping("/google/inapp/verify") - public BaseResponse verifyGoogleInAppTransaction( + @PostMapping("/google/verify/ticket") + @SlackPurchaseNotification + public BaseResponse verifyGoogleTicketTransaction( @AccessTokenUser User user, - @RequestBody GoogleInAppGetRequest request + @RequestBody GoogleTicketGetRequest request ) throws IOException { - val data = purchaseService.verifyGoogleInAppTransaction(user.getId(), request); + val data = purchaseService.verifyGoogleTicketTransaction(user.getId(), request); return BaseResponse.success(GOOGLE_PURCHASE_INAPP_VERIFY_SUCCESS, data); } - @Operation(summary = "๊ตฌ๋… ์—ฐ์žฅ ์œ ๋„ ํ•„์š” ์—ฌ๋ถ€ ํ™•์ธ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserSubscribeNeededResponse.class)) - ) - }) - @GetMapping("/subscribeNeed") + @GetMapping("/subscribe") public BaseResponse getUserSubscribeNeeded( @AccessTokenUser User user) { val data = purchaseService.getUserSubscribe(user, LocalDateTime.now()); return BaseResponse.success(USER_SUBSCRIBE_NEEDED_READ_SUCCESS, data); } - @Operation(summary = "Apple ํ™˜๋ถˆ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = AppleOrderResponse.class)) - ) - }) @DeleteMapping("/apple/refund") public BaseResponse refundInAppApple( @AccessTokenUser User user, AppleInAppRefundRequest request ) { purchaseService.refundInAppApple(user.getId(), request); - return BaseResponse.success(VERIFY_RECEIPT_SUCCESS); } - @Operation(summary = "๊ตฌ๋… ์ƒํƒœ ๋ฐ ๊ตฌ๋…๊ถŒ ๊ฐฏ์ˆ˜ ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserPurchaseInfoResponse.class)) - ) - }) - @GetMapping("/purchaseInfo") + @GetMapping() public BaseResponse getUserPurchaseInfo(@AccessTokenUser User user) { val data = UserPurchaseInfoResponse.of(user); return BaseResponse.success(USER_PURCHASE_INFO_READ_SUCCESS, data); diff --git a/src/main/java/com/yello/server/domain/purchase/dto/apple/AppleOrderResponse.java b/src/main/java/com/yello/server/domain/purchase/dto/apple/AppleOrderResponse.java index 15502202..d1d884de 100644 --- a/src/main/java/com/yello/server/domain/purchase/dto/apple/AppleOrderResponse.java +++ b/src/main/java/com/yello/server/domain/purchase/dto/apple/AppleOrderResponse.java @@ -5,8 +5,7 @@ @Builder public record AppleOrderResponse( int appAppleId, - String environment, - String JWSTransaction + String environment ) { } diff --git a/src/main/java/com/yello/server/domain/purchase/dto/apple/AppleTransaction.java b/src/main/java/com/yello/server/domain/purchase/dto/apple/AppleTransaction.java index a17b58f4..b6d3524d 100644 --- a/src/main/java/com/yello/server/domain/purchase/dto/apple/AppleTransaction.java +++ b/src/main/java/com/yello/server/domain/purchase/dto/apple/AppleTransaction.java @@ -4,10 +4,8 @@ @Builder public record AppleTransaction( - String transactionId, String productId - ) { } diff --git a/src/main/java/com/yello/server/domain/purchase/dto/request/GoogleSubscriptionV2GetRequest.java b/src/main/java/com/yello/server/domain/purchase/dto/request/GoogleSubscriptionGetRequest.java similarity index 87% rename from src/main/java/com/yello/server/domain/purchase/dto/request/GoogleSubscriptionV2GetRequest.java rename to src/main/java/com/yello/server/domain/purchase/dto/request/GoogleSubscriptionGetRequest.java index 112d0070..a0322d12 100644 --- a/src/main/java/com/yello/server/domain/purchase/dto/request/GoogleSubscriptionV2GetRequest.java +++ b/src/main/java/com/yello/server/domain/purchase/dto/request/GoogleSubscriptionGetRequest.java @@ -3,7 +3,7 @@ import lombok.Builder; @Builder -public record GoogleSubscriptionV2GetRequest( +public record GoogleSubscriptionGetRequest( String orderId, String packageName, String productId, diff --git a/src/main/java/com/yello/server/domain/purchase/dto/request/GoogleInAppGetRequest.java b/src/main/java/com/yello/server/domain/purchase/dto/request/GoogleTicketGetRequest.java similarity index 88% rename from src/main/java/com/yello/server/domain/purchase/dto/request/GoogleInAppGetRequest.java rename to src/main/java/com/yello/server/domain/purchase/dto/request/GoogleTicketGetRequest.java index 42c968b8..fc447186 100644 --- a/src/main/java/com/yello/server/domain/purchase/dto/request/GoogleInAppGetRequest.java +++ b/src/main/java/com/yello/server/domain/purchase/dto/request/GoogleTicketGetRequest.java @@ -3,7 +3,7 @@ import lombok.Builder; @Builder -public record GoogleInAppGetRequest( +public record GoogleTicketGetRequest( String orderId, String packageName, String productId, diff --git a/src/main/java/com/yello/server/domain/purchase/dto/response/GoogleSubscriptionV2GetResponse.java b/src/main/java/com/yello/server/domain/purchase/dto/response/GoogleSubscriptionGetResponse.java similarity index 62% rename from src/main/java/com/yello/server/domain/purchase/dto/response/GoogleSubscriptionV2GetResponse.java rename to src/main/java/com/yello/server/domain/purchase/dto/response/GoogleSubscriptionGetResponse.java index 3565692a..765615ee 100644 --- a/src/main/java/com/yello/server/domain/purchase/dto/response/GoogleSubscriptionV2GetResponse.java +++ b/src/main/java/com/yello/server/domain/purchase/dto/response/GoogleSubscriptionGetResponse.java @@ -4,13 +4,13 @@ import lombok.Builder; @Builder -public record GoogleSubscriptionV2GetResponse( +public record GoogleSubscriptionGetResponse( String productId, String expiredAt ) { - public static GoogleSubscriptionV2GetResponse of(String productId) { - return GoogleSubscriptionV2GetResponse.builder() + public static GoogleSubscriptionGetResponse of(String productId) { + return GoogleSubscriptionGetResponse.builder() .productId(productId) .expiredAt(LocalDateTime.now().toString()) .build(); diff --git a/src/main/java/com/yello/server/domain/purchase/dto/response/GoogleInAppV1GetResponse.java b/src/main/java/com/yello/server/domain/purchase/dto/response/GoogleTicketGetResponse.java similarity index 64% rename from src/main/java/com/yello/server/domain/purchase/dto/response/GoogleInAppV1GetResponse.java rename to src/main/java/com/yello/server/domain/purchase/dto/response/GoogleTicketGetResponse.java index bb77670d..374a5846 100644 --- a/src/main/java/com/yello/server/domain/purchase/dto/response/GoogleInAppV1GetResponse.java +++ b/src/main/java/com/yello/server/domain/purchase/dto/response/GoogleTicketGetResponse.java @@ -4,13 +4,13 @@ import lombok.Builder; @Builder -public record GoogleInAppV1GetResponse( +public record GoogleTicketGetResponse( String productId, Integer ticketCount ) { - public static GoogleInAppV1GetResponse of(String productId, User user) { - return GoogleInAppV1GetResponse.builder() + public static GoogleTicketGetResponse of(String productId, User user) { + return GoogleTicketGetResponse.builder() .productId(productId) .ticketCount(user.getTicketCount()) .build(); diff --git a/src/main/java/com/yello/server/domain/purchase/service/PurchaseService.java b/src/main/java/com/yello/server/domain/purchase/service/PurchaseService.java index c28e8e1e..9cb9ed0d 100644 --- a/src/main/java/com/yello/server/domain/purchase/service/PurchaseService.java +++ b/src/main/java/com/yello/server/domain/purchase/service/PurchaseService.java @@ -4,6 +4,7 @@ import static com.yello.server.global.common.ErrorCode.GOOGLE_SUBSCRIPTIONS_FORBIDDEN_EXCEPTION; import static com.yello.server.global.common.ErrorCode.GOOGLE_SUBSCRIPTIONS_SUBSCRIPTION_EXCEPTION; import static com.yello.server.global.common.ErrorCode.GOOGLE_SUBSCRIPTION_DUPLICATED_CANCEL_EXCEPTION; +import static com.yello.server.global.common.ErrorCode.GOOGLE_SUBSCRIPTION_TRANSACTION_EXPIRED_EXCEPTION; import static com.yello.server.global.common.ErrorCode.GOOGLE_SUBSCRIPTION_USED_EXCEPTION; import static com.yello.server.global.common.ErrorCode.GOOGLE_TOKEN_FIELD_NOT_FOUND_EXCEPTION; import static com.yello.server.global.common.ErrorCode.GOOGLE_TOKEN_FORBIDDEN_EXCEPTION; @@ -22,10 +23,10 @@ import com.yello.server.domain.purchase.dto.apple.AppleOrderResponse; import com.yello.server.domain.purchase.dto.apple.AppleTransaction; import com.yello.server.domain.purchase.dto.request.AppleInAppRefundRequest; -import com.yello.server.domain.purchase.dto.request.GoogleInAppGetRequest; -import com.yello.server.domain.purchase.dto.request.GoogleSubscriptionV2GetRequest; -import com.yello.server.domain.purchase.dto.response.GoogleInAppV1GetResponse; -import com.yello.server.domain.purchase.dto.response.GoogleSubscriptionV2GetResponse; +import com.yello.server.domain.purchase.dto.request.GoogleSubscriptionGetRequest; +import com.yello.server.domain.purchase.dto.request.GoogleTicketGetRequest; +import com.yello.server.domain.purchase.dto.response.GoogleSubscriptionGetResponse; +import com.yello.server.domain.purchase.dto.response.GoogleTicketGetResponse; import com.yello.server.domain.purchase.dto.response.UserSubscribeNeededResponse; import com.yello.server.domain.purchase.entity.Gateway; import com.yello.server.domain.purchase.entity.ProductType; @@ -102,7 +103,7 @@ public void verifyAppleSubscriptionTransaction(Long userId, } purchaseManager.createSubscribe(user, Gateway.APPLE, request.transactionId()); - user.changeTicketCount(3); + user.addTicketCount(3); } @Transactional @@ -115,19 +116,17 @@ public void verifyAppleTicketTransaction(Long userId, AppleTransaction request) switch (request.productId()) { case ONE_TICKET_ID: - purchaseManager.createTicket(user, ProductType.ONE_TICKET, Gateway.APPLE, - request.transactionId()); - user.changeTicketCount(1); + purchaseManager.createTicket(user, ProductType.ONE_TICKET, Gateway.APPLE, request.transactionId()); + user.addTicketCount(1); break; case TWO_TICKET_ID: - purchaseManager.createTicket(user, ProductType.TWO_TICKET, Gateway.APPLE, - request.transactionId()); - user.changeTicketCount(2); + purchaseManager.createTicket(user, ProductType.TWO_TICKET, Gateway.APPLE, request.transactionId()); + user.addTicketCount(2); break; case FIVE_TICKET_ID: purchaseManager.createTicket(user, ProductType.FIVE_TICKET, Gateway.APPLE, request.transactionId()); - user.changeTicketCount(5); + user.addTicketCount(5); break; default: throw new PurchaseException(NOT_FOUND_TRANSACTION_EXCEPTION); @@ -135,8 +134,8 @@ public void verifyAppleTicketTransaction(Long userId, AppleTransaction request) } @Transactional - public GoogleSubscriptionV2GetResponse verifyGoogleSubscriptionTransaction(Long userId, - GoogleSubscriptionV2GetRequest request) throws IOException { + public GoogleSubscriptionGetResponse verifyGoogleSubscriptionTransaction(Long userId, + GoogleSubscriptionGetRequest request) throws IOException { User user = userRepository.getById(userId); // exception @@ -144,9 +143,9 @@ public GoogleSubscriptionV2GetResponse verifyGoogleSubscriptionTransaction(Long throw new PurchaseConflictException(GOOGLE_SUBSCRIPTIONS_FORBIDDEN_EXCEPTION); } - purchaseRepository.findByTransactionId(request.orderId()) + purchaseRepository.findByTransactionId(request.orderId().toString()) .ifPresent(action -> { - throw new PurchaseConflictException(GOOGLE_SUBSCRIPTIONS_SUBSCRIPTION_EXCEPTION); + throw new PurchaseConflictException(GOOGLE_SUBSCRIPTION_USED_EXCEPTION); }); final GoogleToken googleToken = @@ -176,28 +175,33 @@ public GoogleSubscriptionV2GetResponse verifyGoogleSubscriptionTransaction(Long Gson gson = new Gson(); JsonObject object = gson.fromJson(subscribeResponse.getBody(), JsonObject.class); - String subscriptionState = object.get("subscriptionState").toString(); - - if (subscriptionState.equals(ConstantUtil.GOOGLE_PURCHASE_SUBSCRIPTION_EXPIRED)) { - throw new GoogleBadRequestException(GOOGLE_SUBSCRIPTION_USED_EXCEPTION); - } else if (subscriptionState.equals(ConstantUtil.GOOGLE_PURCHASE_SUBSCRIPTION_CANCELED)) { - if (user.getSubscribe()==Subscribe.CANCELED) { - throw new GoogleBadRequestException( - GOOGLE_SUBSCRIPTION_DUPLICATED_CANCEL_EXCEPTION); + final String subscriptionState = object.get("subscriptionState").toString().replaceAll("\"", ""); + + switch (subscriptionState) { + case ConstantUtil.GOOGLE_PURCHASE_SUBSCRIPTION_EXPIRED -> { + user.setSubscribe(Subscribe.NORMAL); + throw new GoogleBadRequestException(GOOGLE_SUBSCRIPTION_TRANSACTION_EXPIRED_EXCEPTION); + } + case ConstantUtil.GOOGLE_PURCHASE_SUBSCRIPTION_CANCELED -> { + if (user.getSubscribe()==Subscribe.CANCELED) { + throw new GoogleBadRequestException(GOOGLE_SUBSCRIPTION_DUPLICATED_CANCEL_EXCEPTION); + } else { + // TODO messageQueue ๋ฅผ ์ด์šฉํ•œ ๊ฒฐ์ œ ๋งŒ๋ฃŒ์ผ ๋„๋‹ฌ ์‹œ, ์œ ์ € ๊ตฌ๋… ์ƒํƒœ ๋ณ€๊ฒฝํ•˜๊ธฐ + user.setSubscribe(Subscribe.CANCELED); + } + } + case ConstantUtil.GOOGLE_PURCHASE_SUBSCRIPTION_ACTIVE -> { + final Purchase subscribe = + purchaseManager.createSubscribe(user, Gateway.GOOGLE, request.orderId()); + subscribe.setTransactionId(request.orderId()); } - } else if (subscriptionState.equals(ConstantUtil.GOOGLE_PURCHASE_SUBSCRIPTION_ACTIVE)) { - final Purchase subscribe = - purchaseManager.createSubscribe(user, Gateway.GOOGLE, request.orderId()); - user.changeTicketCount(3); - subscribe.setTransactionId(request.orderId()); } - return GoogleSubscriptionV2GetResponse.of(request.productId()); + return GoogleSubscriptionGetResponse.of(request.productId()); } @Transactional - public GoogleInAppV1GetResponse verifyGoogleInAppTransaction(Long userId, - GoogleInAppGetRequest request) + public GoogleTicketGetResponse verifyGoogleTicketTransaction(Long userId, GoogleTicketGetRequest request) throws IOException { final User user = userRepository.getById(userId); @@ -206,8 +210,7 @@ public GoogleInAppV1GetResponse verifyGoogleInAppTransaction(Long userId, throw new PurchaseConflictException(GOOGLE_SUBSCRIPTIONS_SUBSCRIPTION_EXCEPTION); }); - final GoogleToken googleToken = - googleTokenRepository.getById(googleTokenRepository.tokenId); + final GoogleToken googleToken = googleTokenRepository.getById(googleTokenRepository.tokenId); if (googleToken.getAccessToken().isEmpty() || googleToken.getRefreshToken().isEmpty()) { throw new GoogleTokenNotFoundException(GOOGLE_TOKEN_FIELD_NOT_FOUND_EXCEPTION); } @@ -233,20 +236,18 @@ public GoogleInAppV1GetResponse verifyGoogleInAppTransaction(Long userId, if (inAppResponse.getBody().purchaseState()==0) { purchaseRepository.findByTransactionId(inAppResponse.getBody().orderId()) .ifPresent(action -> { - throw new PurchaseConflictException( - GOOGLE_SUBSCRIPTIONS_SUBSCRIPTION_EXCEPTION); + throw new PurchaseConflictException(GOOGLE_SUBSCRIPTIONS_SUBSCRIPTION_EXCEPTION); }); - Purchase ticket = - purchaseManager.createTicket(user, getProductType(request.productId()), - Gateway.GOOGLE, request.orderId()); - user.changeTicketCount(getTicketAmount(request.productId()) * request.quantity()); + Purchase ticket = purchaseManager.createTicket(user, getProductType(request.productId()), + Gateway.GOOGLE, request.orderId()); + user.addTicketCount(getTicketAmount(request.productId()) * request.quantity()); ticket.setTransactionId(inAppResponse.getBody().orderId()); } else { throw new GoogleBadRequestException(GOOGLE_INAPP_BAD_REQUEST_EXCEPTION); } - return GoogleInAppV1GetResponse.of(request.productId(), user); + return GoogleTicketGetResponse.of(request.productId(), user); } public String reissueGoogleAccessToken(String refreshToken) throws IOException { @@ -270,7 +271,6 @@ public void refundInAppApple(Long userId, AppleInAppRefundRequest request) { purchaseRepository.delete(purchase); user.setSubscribe(Subscribe.NORMAL); - } public ProductType getProductType(String googleInAppId) { diff --git a/src/main/java/com/yello/server/domain/question/dto/response/QuestionVO.java b/src/main/java/com/yello/server/domain/question/dto/response/QuestionVO.java index 67e11a4c..c7c5010a 100644 --- a/src/main/java/com/yello/server/domain/question/dto/response/QuestionVO.java +++ b/src/main/java/com/yello/server/domain/question/dto/response/QuestionVO.java @@ -1,25 +1,15 @@ package com.yello.server.domain.question.dto.response; import com.yello.server.domain.question.entity.Question; -import io.swagger.v3.oas.annotations.media.Schema; import java.util.Objects; import lombok.Builder; @Builder public record QuestionVO( - @Schema(description = "ํˆฌํ‘œ ์งˆ๋ฌธ id", example = "1") Long questionId, - - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ ์ค‘ ์ด๋ฆ„ ์•ž ๋ถ€๋ถ„", example = "๋‚˜๋Š”") String nameHead, - - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ ์ค‘ ์ด๋ฆ„ ๋’ท ๋ถ€๋ถ„", example = "๋ž‘") String nameFoot, - - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ ์ค‘ ํ‚ค์›Œ๋“œ ์•ž ๋ถ€๋ถ„", example = "ํ•œ๊ฐ•์—์„œ") String keywordHead, - - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ ์ค‘ ํ‚ค์›Œ๋“œ ๋’ท ๋ถ€๋ถ„", example = "ํ•˜๊ณ  ์‹ถ์–ด") String keywordFoot ) { diff --git a/src/main/java/com/yello/server/domain/user/controller/UserController.java b/src/main/java/com/yello/server/domain/user/controller/UserController.java index 8032d24a..49ebff1d 100644 --- a/src/main/java/com/yello/server/domain/user/controller/UserController.java +++ b/src/main/java/com/yello/server/domain/user/controller/UserController.java @@ -12,11 +12,6 @@ import com.yello.server.global.common.annotation.AccessTokenUser; import com.yello.server.global.common.dto.BaseResponse; import com.yello.server.global.common.dto.EmptyObject; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.val; import org.springframework.web.bind.annotation.DeleteMapping; @@ -27,7 +22,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -@Tag(name = "04. User") @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/user") @@ -35,46 +29,27 @@ public class UserController { private final UserService userService; - @Operation(summary = "๋‚ด ์ •๋ณด ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDetailResponse.class))), - }) @GetMapping public BaseResponse findUser(@AccessTokenUser User user) { val data = userService.findMyProfile(user.getId()); return BaseResponse.success(READ_USER_SUCCESS, data); } - @Operation(summary = "์œ ์ € ์ •๋ณด ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserResponse.class))), - }) @GetMapping("/{userId}") public BaseResponse findUserById(@PathVariable Long userId) { val data = userService.findUserById(userId); return BaseResponse.success(READ_USER_SUCCESS, data); } - @Operation(summary = "๋””๋ฐ”์ด์Šค ํ† ํฐ ์ˆ˜์ • API", responses = { - @ApiResponse( - responseCode = "201", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = EmptyObject.class))), - }) - @PutMapping("/deviceToken") + @PutMapping("/device") public BaseResponse putUserDeviceToken( @AccessTokenUser User user, - @RequestBody UserDeviceTokenRequest request) { + @RequestBody UserDeviceTokenRequest request + ) { val data = userService.updateUserDeviceToken(user, request); return BaseResponse.success(UPDATE_DEVICE_TOKEN_USER_SUCCESS, data); } - @Operation(summary = "์œ ์ € ํƒˆํ‡ด API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json")) - }) @DeleteMapping public BaseResponse deleteUser(@AccessTokenUser User user) { userService.delete(user); diff --git a/src/main/java/com/yello/server/domain/user/entity/User.java b/src/main/java/com/yello/server/domain/user/entity/User.java index 333323c3..ba3bfb37 100644 --- a/src/main/java/com/yello/server/domain/user/entity/User.java +++ b/src/main/java/com/yello/server/domain/user/entity/User.java @@ -172,7 +172,7 @@ public void setSubscribe(Subscribe subscribe) { this.subscribe = subscribe; } - public void changeTicketCount(int ticketCount) { + public void addTicketCount(int ticketCount) { this.ticketCount += ticketCount; } diff --git a/src/main/java/com/yello/server/domain/user/repository/UserJpaRepository.java b/src/main/java/com/yello/server/domain/user/repository/UserJpaRepository.java index f0cceea9..dcfd13a9 100644 --- a/src/main/java/com/yello/server/domain/user/repository/UserJpaRepository.java +++ b/src/main/java/com/yello/server/domain/user/repository/UserJpaRepository.java @@ -28,6 +28,10 @@ public interface UserJpaRepository extends JpaRepository { "and u.deletedAt is null") Optional findByYelloId(@Param("yelloId") String yelloId); + @Query("select u from User u " + + "where u.yelloId = :yelloId") + Optional findByYelloIdNotFiltered(@Param("yelloId") String yelloId); + @Query("select u from User u " + "where u.group.id = :groupId " + "and u.deletedAt is null") diff --git a/src/main/java/com/yello/server/domain/user/repository/UserRepository.java b/src/main/java/com/yello/server/domain/user/repository/UserRepository.java index 8196c4fe..1ba44451 100644 --- a/src/main/java/com/yello/server/domain/user/repository/UserRepository.java +++ b/src/main/java/com/yello/server/domain/user/repository/UserRepository.java @@ -20,6 +20,8 @@ public interface UserRepository { Optional findByYelloId(String yelloId); + Optional findByYelloIdNotFiltered(String yelloId); + User getByYelloId(String yelloId); Optional findByDeviceToken(String deviceToken); diff --git a/src/main/java/com/yello/server/domain/user/repository/UserRepositoryImpl.java b/src/main/java/com/yello/server/domain/user/repository/UserRepositoryImpl.java index f1cf794c..8303653c 100644 --- a/src/main/java/com/yello/server/domain/user/repository/UserRepositoryImpl.java +++ b/src/main/java/com/yello/server/domain/user/repository/UserRepositoryImpl.java @@ -57,6 +57,11 @@ public Optional findByYelloId(String yelloId) { return userJpaRepository.findByYelloId(yelloId); } + @Override + public Optional findByYelloIdNotFiltered(String yelloId) { + return userJpaRepository.findByYelloIdNotFiltered(yelloId); + } + @Override public User getByYelloId(String yelloId) { return userJpaRepository.findByYelloId(yelloId) diff --git a/src/main/java/com/yello/server/domain/vote/controller/VoteController.java b/src/main/java/com/yello/server/domain/vote/controller/VoteController.java index 54347930..7b8796a1 100644 --- a/src/main/java/com/yello/server/domain/vote/controller/VoteController.java +++ b/src/main/java/com/yello/server/domain/vote/controller/VoteController.java @@ -24,13 +24,6 @@ import com.yello.server.global.common.annotation.AccessTokenUser; import com.yello.server.global.common.dto.BaseResponse; import com.yello.server.infrastructure.firebase.service.NotificationService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.ArraySchema; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.val; @@ -43,7 +36,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -@Tag(name = "01. Vote") @RestController @RequestMapping("api/v1/vote") @RequiredArgsConstructor @@ -52,108 +44,48 @@ public class VoteController { private final VoteService voteService; private final NotificationService notificationService; - @Operation(summary = "๋‚ด ํˆฌํ‘œ ์ „์ฒด ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = VoteListResponse.class))), - }) @GetMapping - public BaseResponse findAllMyVotes( - @Parameter(name = "page", description = "ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค.", example = "1") - @RequestParam Integer page, - @AccessTokenUser User user - ) { + public BaseResponse findAllMyVotes(@RequestParam Integer page, @AccessTokenUser User user) { val data = voteService.findAllVotes(user.getId(), createPageableLimitTen(page)); return BaseResponse.success(READ_VOTE_SUCCESS, data); } - @Operation(summary = "์ฝ์ง€ ์•Š์€ ์ชฝ์ง€ ๊ฐœ์ˆ˜ ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = VoteUnreadCountResponse.class))), - }) @GetMapping("/count") - public BaseResponse getUnreadVoteCount( - @AccessTokenUser User user - ) { + public BaseResponse getUnreadVoteCount(@AccessTokenUser User user) { val data = voteService.getUnreadVoteCount(user.getId()); return BaseResponse.success(READ_VOTE_SUCCESS, data); } - @Operation(summary = "์นœ๊ตฌ ํˆฌํ‘œ ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = VoteFriendResponse.class))), - }) @GetMapping("/friend") - public BaseResponse findAllFriendVotes( - @Parameter(name = "page", description = "ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค.", example = "1") - @RequestParam Integer page, - @AccessTokenUser User user - ) { + public BaseResponse findAllFriendVotes(@RequestParam Integer page, @AccessTokenUser User user) { val data = voteService.findAllFriendVotes(user.getId(), createPageableLimitTen(page)); return BaseResponse.success(READ_VOTE_SUCCESS, data); } - @Operation(summary = "ํˆฌํ‘œ ์ƒ์„ธ ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = VoteDetailResponse.class))), - }) @GetMapping("/{voteId}") - public BaseResponse findVote( - @PathVariable Long voteId, - @AccessTokenUser User user) { + public BaseResponse findVote(@PathVariable Long voteId, @AccessTokenUser User user) { val data = voteService.findVoteById(voteId, user.getId()); return BaseResponse.success(READ_VOTE_SUCCESS, data); } - @Operation(summary = "ํ‚ค์›Œ๋“œ ํ™•์ธ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = KeywordCheckResponse.class))), - }) @PatchMapping("/{voteId}/keyword") - public BaseResponse checkKeyword( - @Parameter(name = "voteId", description = "ํ•ด๋‹น ํˆฌํ‘œ ์•„์ด๋”” ๊ฐ’ ์ž…๋‹ˆ๋‹ค.") - @PathVariable Long voteId, - @AccessTokenUser User user - ) { + public BaseResponse checkKeyword(@PathVariable Long voteId, @AccessTokenUser User user) { val keywordCheckResponse = voteService.checkKeyword(user.getId(), voteId); return BaseResponse.success(CHECK_KEYWORD_SUCCESS, keywordCheckResponse); } - @Operation(summary = "ํˆฌํ‘œ 8๊ฐœ ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = QuestionForVoteResponse.class)))), - }) @GetMapping("/question") - public BaseResponse> findVoteQuestions( - @AccessTokenUser User user - ) { + public BaseResponse> findVoteQuestions(@AccessTokenUser User user) { val data = voteService.findVoteQuestionList(user.getId()); return BaseResponse.success(READ_YELLO_VOTE_SUCCESS, data); } - @Operation(summary = "ํˆฌํ‘œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = VoteAvailableResponse.class))), - }) @GetMapping("/available") - public BaseResponse checkVoteAvailable( - @AccessTokenUser User user - ) { + public BaseResponse checkVoteAvailable(@AccessTokenUser User user) { val data = voteService.checkVoteAvailable(user.getId()); return BaseResponse.success(READ_YELLO_START_SUCCESS, data); } - @Operation(summary = "ํˆฌํ‘œ ์ƒ์„ฑ API", responses = { - @ApiResponse( - responseCode = "201", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = VoteCreateResponse.class))), - }) @PostMapping public BaseResponse createVote( @AccessTokenUser User user, @@ -166,33 +98,16 @@ public BaseResponse createVote( return BaseResponse.success(CREATE_VOTE_SUCCESS, response); } - @Operation(summary = "ํˆฌํ‘œ ์ด๋ฆ„ ๋ถ€๋ถ„ ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = RevealNameResponse.class))), - }) @PatchMapping("/{voteId}/name") - public BaseResponse revealNameHint( - @AccessTokenUser User user, - @PathVariable Long voteId - ) { + public BaseResponse revealNameHint(@AccessTokenUser User user, @PathVariable Long voteId) { val data = voteService.revealNameHint(user.getId(), voteId); - return BaseResponse.success(SuccessCode.REVEAL_NAME_HINT_SUCCESS, data); } - @Operation(summary = "ํˆฌํ‘œ ์ด๋ฆ„ ์ „์ฒด ์กฐํšŒ API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = RevealFullNameResponse.class))), - }) @PatchMapping("/{voteId}/fullname") - public BaseResponse revealFullName( - @AccessTokenUser User user, - @PathVariable Long voteId - ) { + public BaseResponse revealFullName(@AccessTokenUser User user, @PathVariable Long voteId) { val data = voteService.revealFullName(user.getId(), voteId); - return BaseResponse.success(SuccessCode.REVEAL_NAME_HINT_SUCCESS, data); + return BaseResponse.success(SuccessCode.REVEAL_NAME_SUCCESS, data); } } diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteAvailableResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteAvailableResponse.java index d0b5335a..9f7ecaef 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteAvailableResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteAvailableResponse.java @@ -6,19 +6,13 @@ import com.yello.server.domain.cooldown.entity.Cooldown; import com.yello.server.domain.user.entity.User; -import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDateTime; import lombok.Builder; @Builder public record VoteAvailableResponse( - @Schema(description = "ํˆฌํ‘œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ (true=๊ฐ€๋Šฅ, false=๋ถˆ๊ฐ€๋Šฅ)", example = "false") Boolean isPossible, - - @Schema(description = "ํ˜„์žฌ ๋ณด์œ ์ค‘์ธ ํฌ์ธํŠธ", example = "200") Integer point, - - @Schema(description = "๋งˆ์ง€๋ง‰ ํˆฌํ‘œ ์‹œ์ ") String createdAt ) { diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteContentVO.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteContentVO.java index aa11ff36..86f3e5c5 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteContentVO.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteContentVO.java @@ -1,29 +1,19 @@ package com.yello.server.domain.vote.dto.response; import com.yello.server.domain.vote.entity.Vote; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.val; @Builder public record VoteContentVO( - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ ์ค‘ ์ด๋ฆ„ ์•ž ๋ถ€๋ถ„", example = "๋‚˜๋Š”") String nameHead, - - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ ์ค‘ ์ด๋ฆ„ ๋’ท ๋ถ€๋ถ„", example = "๋ž‘") String nameFoot, - - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ ์ค‘ ํ‚ค์›Œ๋“œ ์•ž ๋ถ€๋ถ„", example = "ํ•œ๊ฐ•์—์„œ") String keywordHead, - - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ ์ค‘ ํ‚ค์›Œ๋“œ ํ‚ค์›Œ๋“œ ๋ถ€๋ถ„", example = "์ˆ˜์˜") String keyword, - - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ ์ค‘ ํ‚ค์›Œ๋“œ ๋’ท ๋ถ€๋ถ„", example = "ํ•˜๊ณ  ์‹ถ์–ด") String keywordFoot ) { - static VoteContentVO of(Vote vote) { + public static VoteContentVO of(Vote vote) { return VoteContentVO.builder() .nameHead(vote.getQuestion().getNameHead()) .nameFoot(deleteBracket(vote.getQuestion().getNameFoot())) @@ -35,6 +25,6 @@ static VoteContentVO of(Vote vote) { private static String deleteBracket(String target) { val slashIndex = target.indexOf('/'); - return slashIndex != -1 ? target.substring(slashIndex + 1) : target; + return slashIndex!=-1 ? target.substring(slashIndex + 1) : target; } } diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteDetailResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteDetailResponse.java index 201904bf..a1dfe2d0 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteDetailResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteDetailResponse.java @@ -3,41 +3,18 @@ import com.yello.server.domain.user.entity.Subscribe; import com.yello.server.domain.user.entity.User; import com.yello.server.domain.vote.entity.Vote; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; @Builder public record VoteDetailResponse( - @Schema(description = "ํˆฌํ‘œ ์ปฌ๋Ÿฌ ์ธ๋ฑ์Šค") Integer colorIndex, - - @Schema(description = "ํ˜„์žฌ ๋ณด์œ ์ค‘์ธ ํฌ์ธํŠธ") Integer currentPoint, - - @Schema(description = "์ด๋ฆ„ ํžŒํŠธ ์ธ๋ฑ์Šค" - + "\n-3 โ†’ ์ฒซ ์ชฝ์ง€ (ํŠน๋ณ„๊ฐ’)" - + "\n-2 โ†’ ๊ตฌ๋…๊ถŒ์„ ์‚ฌ์šฉํ•ด์„œ ์ด๋ฆ„ ์ „์ฒด ํ™•์ธ" - + "\n-1 โ†’ ์ด๋ฆ„ ํžŒํŠธ๊ฐ€ ์•„์ง ๋ฐํ˜€์ง€์ง€ ์•Š์Œ" - + "\n0 โ†’ ์ฒซ๋ฒˆ์งธ ์œ„์น˜์— ์ด๋ฆ„ ํžŒํŠธ๊ฐ€ ๋ฐํ˜€์ง" - + "\n1 โ†’ ๋‘๋ฒˆ์งธ ์œ„์น˜์— ์ด๋ฆ„ ํžŒํŠธ๊ฐ€ ๋ฐํ˜€์ง") Integer nameHint, - - @Schema(description = "ํ‚ค์›Œ๋“œ ๊ณต๊ฐœ ์—ฌ๋ถ€") Boolean isAnswerRevealed, - - @Schema(description = "ํˆฌํ‘œ๋ฅผ ์ž‘์„ฑํ•œ ์œ ์ €์˜ ์ด๋ฆ„") String senderName, - - @Schema(description = "ํˆฌํ‘œ๋ฅผ ๋ณด๋‚ธ ์œ ์ €์˜ ์„ฑ๋ณ„", example = "MALE | FEMALE") String senderGender, - - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ") VoteContentVO vote, - - @Schema(description = "์—ด๋žŒ๊ถŒ ๊ฐœ์ˆ˜") Integer ticketCount, - - @Schema(description = "๊ตฌ๋…๊ถŒ ์—ฌ๋ถ€", example = "true | false") Boolean isSubscribe ) { @@ -51,7 +28,7 @@ public static VoteDetailResponse of(Vote vote, User user) { .senderGender(vote.getSender().getGender().name()) .vote(VoteContentVO.of(vote)) .ticketCount(user.getTicketCount()) - .isSubscribe(user.getSubscribe() != Subscribe.NORMAL) + .isSubscribe(user.getSubscribe()!=Subscribe.NORMAL) .build(); } } diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteFriendVO.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteFriendVO.java index 97367592..c83a5147 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteFriendVO.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteFriendVO.java @@ -3,27 +3,15 @@ import static com.yello.server.global.common.factory.TimeFactory.toFormattedString; import com.yello.server.domain.vote.entity.Vote; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; @Builder public record VoteFriendVO( - @Schema(description = "ํˆฌํ‘œ ๊ณ ์œ  Id ๊ฐ’") Long id, - - @Schema(description = "ํˆฌํ‘œ๋ฅผ ๋ฐ›์€ ์œ ์ €์˜ ์ด๋ฆ„", example = "๊ถŒ์„ธํ›ˆ") String receiverName, - - @Schema(description = "ํˆฌํ‘œ๋ฅผ ๋ณด๋‚ธ ์œ ์ €์˜ ์„ฑ๋ณ„", example = "MALE") String senderGender, - - @Schema(description = "ํˆฌํ‘œ์˜ ์ „์ฒด ๋ฌธ์žฅ") VoteContentVO vote, - - @Schema(description = "ํžŒํŠธ ์‚ฌ์šฉ ์—ฌ๋ถ€") Boolean isHintUsed, - - @Schema(description = "ํˆฌํ‘œ ์ƒ์„ฑ ์ผ์ž", example = "1์‹œ๊ฐ„ ์ „") String createdAt ) { diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteListResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteListResponse.java index 668aeb45..ca97e794 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteListResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteListResponse.java @@ -1,25 +1,17 @@ package com.yello.server.domain.vote.dto.response; import com.yello.server.domain.user.entity.User; -import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; import lombok.Builder; @Builder public record VoteListResponse( - @Schema(description = "๋‚ด ์ชฝ์ง€ ์ „์ฒด ๊ฐœ์ˆ˜") Integer totalCount, - @Schema(description = "์—ด๋žŒ๊ถŒ ์ˆ˜") Integer ticketCount, - @Schema(description = "์˜คํ”ˆํ•œ ์ชฝ์ง€ ์ˆ˜") Integer openCount, - @Schema(description = "์˜คํ”ˆํ•œ ํ‚ค์›Œ๋“œ ์ชฝ์ง€ ์ˆ˜") Integer openKeywordCount, - @Schema(description = "์˜คํ”ˆํ•œ ์ดˆ์„ฑ ์ชฝ์ง€ ์ˆ˜") Integer openNameCount, - @Schema(description = "์˜คํ”ˆํ•œ ์ „์ฒด ์ด๋ฆ„ ์ชฝ์ง€ ์ˆ˜") Integer openFullNameCount, - @Schema(description = "๋‚ด ์ชฝ์ง€ ๋ฆฌ์ŠคํŠธ") List votes ) { diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteResponse.java index 4ab04676..55412b4d 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteResponse.java @@ -3,33 +3,17 @@ import static com.yello.server.global.common.factory.TimeFactory.toFormattedString; import com.yello.server.domain.vote.entity.Vote; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; @Builder public record VoteResponse( - @Schema(description = "ํˆฌํ‘œ ๊ณ ์œ  Id ๊ฐ’") Long id, - - @Schema(description = "ํˆฌํ‘œ๋ฅผ ๋ณด๋‚ธ ์œ ์ €์˜ ์„ฑ๋ณ„", example = "MALE") String senderGender, - - @Schema(description = "ํˆฌํ‘œ๋ฅผ ๋ณด๋‚ธ ์œ ์ €์˜ ์ด๋ฆ„", example = "๊ถŒ์„ธํ›ˆ") String senderName, - - @Schema(description = "์ด๋ฆ„ ํžŒํŠธ ์ธ๋ฑ์Šค", example = "-1") Integer nameHint, - - @Schema(description = "ํˆฌํ‘œ ๋‚ด์šฉ") VoteContentVO vote, - - @Schema(description = "ํžŒํŠธ ์‚ฌ์šฉ ์—ฌ๋ถ€") Boolean isHintUsed, - - @Schema(description = "ํˆฌํ‘œ ์ฝ์Œ ์—ฌ๋ถ€") Boolean isRead, - - @Schema(description = "ํˆฌํ‘œ ์ƒ์„ฑ ์ผ์ž", example = "1์‹œ๊ฐ„ ์ „") String createdAt ) { diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteUnreadCountResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteUnreadCountResponse.java index 11d56605..42c3f527 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteUnreadCountResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteUnreadCountResponse.java @@ -1,11 +1,9 @@ package com.yello.server.domain.vote.dto.response; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; @Builder public record VoteUnreadCountResponse( - @Schema(description = "์ฝ์ง€ ์•Š์€ ์ชฝ์ง€ ๊ฐœ์ˆ˜", example = "1") Integer totalCount ) { diff --git a/src/main/java/com/yello/server/domain/vote/service/VoteManagerImpl.java b/src/main/java/com/yello/server/domain/vote/service/VoteManagerImpl.java index c1950f05..90e1d740 100644 --- a/src/main/java/com/yello/server/domain/vote/service/VoteManagerImpl.java +++ b/src/main/java/com/yello/server/domain/vote/service/VoteManagerImpl.java @@ -1,9 +1,9 @@ package com.yello.server.domain.vote.service; -import static com.yello.server.domain.vote.common.WeightedRandomFactory.randomPoint; import static com.yello.server.global.common.ErrorCode.DUPLICATE_VOTE_EXCEPTION; import static com.yello.server.global.common.ErrorCode.INVALID_VOTE_EXCEPTION; import static com.yello.server.global.common.ErrorCode.LACK_POINT_EXCEPTION; +import static com.yello.server.global.common.factory.WeightedRandomFactory.randomPoint; import static com.yello.server.global.common.util.ConstantUtil.KEYWORD_HINT_POINT; import static com.yello.server.global.common.util.ConstantUtil.NAME_HINT_DEFAULT; import static com.yello.server.global.common.util.ConstantUtil.NAME_HINT_POINT; @@ -34,7 +34,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; import java.util.stream.IntStream; import lombok.Builder; import lombok.RequiredArgsConstructor; @@ -107,7 +107,7 @@ public List generateVoteQuestion(User user, List getShuffledKeywords(Question question) { } private Vote createFirstVote(User sender, User receiver, Question question) { - Random random = new Random(); + final ThreadLocalRandom random = ThreadLocalRandom.current(); final String answer = "๋„ ๊ธฐ๋‹ค๋ ธ์–ด"; return Vote.builder() diff --git a/src/main/java/com/yello/server/domain/vote/service/VoteService.java b/src/main/java/com/yello/server/domain/vote/service/VoteService.java index 1a1174b1..4e893782 100644 --- a/src/main/java/com/yello/server/domain/vote/service/VoteService.java +++ b/src/main/java/com/yello/server/domain/vote/service/VoteService.java @@ -195,7 +195,7 @@ public RevealFullNameResponse revealFullName(Long userId, Long voteId) { } vote.checkNameIndexOf(CHECK_FULL_NAME); - sender.changeTicketCount(MINUS_TICKET_COUNT); + sender.addTicketCount(MINUS_TICKET_COUNT); return RevealFullNameResponse.of(vote.getSender()); } diff --git a/src/main/java/com/yello/server/global/HealthCheckController.java b/src/main/java/com/yello/server/global/HealthCheckController.java index 01f00f37..34431b25 100644 --- a/src/main/java/com/yello/server/global/HealthCheckController.java +++ b/src/main/java/com/yello/server/global/HealthCheckController.java @@ -1,11 +1,9 @@ package com.yello.server.global; -import io.swagger.v3.oas.annotations.Hidden; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -@Hidden @RestController @RequiredArgsConstructor public class HealthCheckController { @@ -14,4 +12,9 @@ public class HealthCheckController { public String healthCheck() { return "Yell:o world!"; } + + @GetMapping("/abc") + public void text() throws Exception { + throw new Exception("Abc"); + } } diff --git a/src/main/java/com/yello/server/global/common/ErrorCode.java b/src/main/java/com/yello/server/global/common/ErrorCode.java index 1d21a625..ce6a4b5b 100644 --- a/src/main/java/com/yello/server/global/common/ErrorCode.java +++ b/src/main/java/com/yello/server/global/common/ErrorCode.java @@ -59,6 +59,7 @@ public enum ErrorCode { GOOGLE_TOKEN_FORBIDDEN_EXCEPTION(FORBIDDEN, "์œ ํšจํ•˜์ง€ ์•Š๋Š” Google OAuth 2.0 refreshToken์ž…๋‹ˆ๋‹ค. DBA์—๊ฒŒ ๋ฌธ์˜ํ•ด์ฃผ์„ธ์š”."), GOOGLE_SUBSCRIPTIONS_FORBIDDEN_EXCEPTION(FORBIDDEN, "์ด๋ฏธ YELLO: PLUS๋ฅผ ๊ตฌ๋…ํ•œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค."), + GOOGLE_SUBSCRIPTION_TRANSACTION_EXPIRED_EXCEPTION(FORBIDDEN, "์ด๋ฏธ ๋งŒ๋ฃŒ๋œ ๊ฒฐ์ œ ๋‚ด์—ญ์˜ ์˜์ˆ˜์ฆ์ž…๋‹ˆ๋‹ค."), /** * 404 NOT FOUND diff --git a/src/main/java/com/yello/server/global/common/SuccessCode.java b/src/main/java/com/yello/server/global/common/SuccessCode.java index 98d2210a..654d61a5 100644 --- a/src/main/java/com/yello/server/global/common/SuccessCode.java +++ b/src/main/java/com/yello/server/global/common/SuccessCode.java @@ -31,7 +31,8 @@ public enum SuccessCode { ONBOARDING_FRIENDS_SUCCESS(OK, "์ถ”์ฒœ ์นœ๊ตฌ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."), SCHOOL_NAME_SEARCH_SCHOOL_SUCCESS(OK, "ํ•™๊ต ๊ฒ€์ƒ‰์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."), DEPARTMENT_NAME_SEARCH_BY_SCHOOL_NAME_SCHOOL_SUCCESS(OK, "ํ•™๊ณผ ๊ฒ€์ƒ‰์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."), - REVEAL_NAME_HINT_SUCCESS(OK, "์ด๋ฆ„ ์ดˆ์„ฑ ํ™•์ธํ•˜๋Š”๋ฐ ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."), + REVEAL_NAME_HINT_SUCCESS(OK, "์ด๋ฆ„ ์ดˆ์„ฑ ํ™•์ธ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."), + REVEAL_NAME_SUCCESS(OK, "์ „์ฒด ์ด๋ฆ„ ํ™•์ธ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."), FRIEND_SEARCH_SUCCESS(OK, "์นœ๊ตฌ ๊ฒ€์ƒ‰ํ•˜๊ธฐ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."), VERIFY_RECEIPT_SUCCESS(OK, "์ธ์•ฑ๊ฒฐ์ œ ๊ฒ€์ฆ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."), diff --git a/src/main/java/com/yello/server/global/common/annotation/AccessTokenUser.java b/src/main/java/com/yello/server/global/common/annotation/AccessTokenUser.java index 572520cb..fc204ea0 100644 --- a/src/main/java/com/yello/server/global/common/annotation/AccessTokenUser.java +++ b/src/main/java/com/yello/server/global/common/annotation/AccessTokenUser.java @@ -1,6 +1,5 @@ package com.yello.server.global.common.annotation; -import io.swagger.v3.oas.annotations.Parameter; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -8,7 +7,6 @@ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) -@Parameter(hidden = true) public @interface AccessTokenUser { } diff --git a/src/main/java/com/yello/server/global/common/factory/PaginationFactory.java b/src/main/java/com/yello/server/global/common/factory/PaginationFactory.java index 4f433360..b2b26bae 100644 --- a/src/main/java/com/yello/server/global/common/factory/PaginationFactory.java +++ b/src/main/java/com/yello/server/global/common/factory/PaginationFactory.java @@ -29,7 +29,6 @@ public static Pageable createPageableLimitTen(Integer page) { return PageRequest.of(page, PAGE_LIMIT_TEN); } - public static Page getPage(List list, Pageable pageable) { int start = (int) pageable.getOffset(); int end = Math.min((start + pageable.getPageSize()), list.size()); diff --git a/src/main/java/com/yello/server/global/common/factory/TokenFactory.java b/src/main/java/com/yello/server/global/common/factory/TokenFactory.java index a9a3dc84..9d84eda1 100644 --- a/src/main/java/com/yello/server/global/common/factory/TokenFactory.java +++ b/src/main/java/com/yello/server/global/common/factory/TokenFactory.java @@ -4,7 +4,6 @@ import io.jsonwebtoken.SignatureAlgorithm; import java.security.KeyFactory; import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Calendar; import java.util.Date; import lombok.SneakyThrows; import org.apache.commons.codec.binary.Base64; @@ -15,35 +14,34 @@ public class TokenFactory { @Value("${kid}") - private String KID; + private String kid; + @Value("${iss}") - private String ISS; + private String iss; + @Value("${aud}") - private String AUD; + private String aud; + @Value("${bid}") - private String BID; + private String bid; + @Value("${sig}") - private String SIG; + private String sig; @SneakyThrows public String generateAppleToken() { - String jws = Jwts.builder() - // header - .setHeaderParam("kid", KID) - // payload - .setIssuer(ISS) - .setIssuedAt(new Date(Calendar.getInstance().getTimeInMillis())) // ๋ฐœํ–‰ ์‹œ๊ฐ„ - UNIX ์‹œ๊ฐ„ - .setExpiration( - new Date(Calendar.getInstance().getTimeInMillis() + (3 * 60 - * 1000))) // ๋งŒ๋ฃŒ ์‹œ๊ฐ„ (๋ฐœํ–‰ ์‹œ๊ฐ„ + 3๋ถ„) - .setAudience(AUD) - .claim("bid", BID) - // sign - .signWith(SignatureAlgorithm.ES256, - KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec( - Base64.decodeBase64(SIG)))) + return Jwts.builder() + .setHeaderParam("kid", kid) + .setIssuer(iss) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + (3 * 60 * 1000))) + .setAudience(aud) + .claim("bid", bid) + .signWith( + SignatureAlgorithm.ES256, + KeyFactory.getInstance("EC") + .generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(sig))) + ) .compact(); - - return jws; } } diff --git a/src/main/java/com/yello/server/domain/vote/common/WeightedRandomFactory.java b/src/main/java/com/yello/server/global/common/factory/WeightedRandomFactory.java similarity index 88% rename from src/main/java/com/yello/server/domain/vote/common/WeightedRandomFactory.java rename to src/main/java/com/yello/server/global/common/factory/WeightedRandomFactory.java index d54200ab..8aba23c4 100644 --- a/src/main/java/com/yello/server/domain/vote/common/WeightedRandomFactory.java +++ b/src/main/java/com/yello/server/global/common/factory/WeightedRandomFactory.java @@ -1,4 +1,4 @@ -package com.yello.server.domain.vote.common; +package com.yello.server.global.common.factory; import static com.yello.server.global.common.util.ConstantUtil.EIGHT_POINT_WEIGHT; import static com.yello.server.global.common.util.ConstantUtil.FIFTH_POINT_WEIGHT; @@ -13,6 +13,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; public class WeightedRandomFactory { @@ -32,9 +33,11 @@ public static Integer randomPoint() { weight.put(MIN_POINT + 16, SEVENTH_POINT_WEIGHT); weight.put(MIN_POINT + 20, EIGHT_POINT_WEIGHT); - final double pivot = Math.random() % REMINDER_NUMBER; + final ThreadLocalRandom random = ThreadLocalRandom.current(); + + final double pivot = random.nextDouble(1) % REMINDER_NUMBER; double currentWeight = 0; - + for (int key : weight.keySet()) { currentWeight += weight.getOrDefault(key, 0.0); if (currentWeight >= pivot) { diff --git a/src/main/java/com/yello/server/global/configuration/JpaConfiguration.java b/src/main/java/com/yello/server/global/configuration/JpaConfiguration.java new file mode 100644 index 00000000..cb092039 --- /dev/null +++ b/src/main/java/com/yello/server/global/configuration/JpaConfiguration.java @@ -0,0 +1,10 @@ +package com.yello.server.global.configuration; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@EnableJpaAuditing +@Configuration +public class JpaConfiguration { + +} diff --git a/src/main/java/com/yello/server/global/configuration/QueryDslConfiguration.java b/src/main/java/com/yello/server/global/configuration/QueryDslConfiguration.java deleted file mode 100644 index 79454eee..00000000 --- a/src/main/java/com/yello/server/global/configuration/QueryDslConfiguration.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.yello.server.global.configuration; - -import com.querydsl.jpa.impl.JPAQueryFactory; -import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import javax.persistence.EntityManager; - -@Configuration -@RequiredArgsConstructor -public class QueryDslConfiguration { - - private final EntityManager entityManager; - - @Bean - public JPAQueryFactory queryFactory() { - return new JPAQueryFactory(entityManager); - } - -} diff --git a/src/main/java/com/yello/server/global/configuration/SwaggerConfiguration.java b/src/main/java/com/yello/server/global/configuration/SwaggerConfiguration.java deleted file mode 100644 index 50fcd700..00000000 --- a/src/main/java/com/yello/server/global/configuration/SwaggerConfiguration.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.yello.server.global.configuration; - -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.security.SecurityRequirement; -import io.swagger.v3.oas.models.security.SecurityScheme; -import java.util.Arrays; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class SwaggerConfiguration { - - @Bean - public OpenAPI openAPI() { - Info info = new Info() - .title("YELL:O API Documentation") - .description("YELL:O API ๊ณต์‹ ๋ช…์„ธ์„œ ์ž…๋‹ˆ๋‹ค.") - .version("v1"); - - SecurityScheme securityScheme = new SecurityScheme() - .type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT") - .in(SecurityScheme.In.HEADER).name("Authorization"); - - SecurityRequirement securityRequirement = new SecurityRequirement().addList("Bearer Token"); - - return new OpenAPI() - .components(new Components().addSecuritySchemes("Bearer Token", securityScheme)) - .security(Arrays.asList(securityRequirement)) - .info(info); - } -} diff --git a/src/main/java/com/yello/server/global/exception/ControllerExceptionAdvice.java b/src/main/java/com/yello/server/global/exception/ControllerExceptionAdvice.java index 24b0c6d3..a91b9ee4 100644 --- a/src/main/java/com/yello/server/global/exception/ControllerExceptionAdvice.java +++ b/src/main/java/com/yello/server/global/exception/ControllerExceptionAdvice.java @@ -17,7 +17,6 @@ import com.yello.server.domain.authorization.exception.NotSignedInException; import com.yello.server.domain.authorization.exception.NotValidTokenForbiddenException; import com.yello.server.domain.authorization.exception.OAuthException; -import com.yello.server.domain.authorization.service.TokenProvider; import com.yello.server.domain.friend.exception.FriendException; import com.yello.server.domain.friend.exception.FriendNotFoundException; import com.yello.server.domain.group.exception.GroupNotFoundException; @@ -31,39 +30,24 @@ import com.yello.server.domain.purchase.exception.SubscriptionConflictException; import com.yello.server.domain.question.exception.QuestionException; import com.yello.server.domain.question.exception.QuestionNotFoundException; -import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.exception.UserBadRequestException; import com.yello.server.domain.user.exception.UserConflictException; import com.yello.server.domain.user.exception.UserException; import com.yello.server.domain.user.exception.UserNotFoundException; -import com.yello.server.domain.user.repository.UserRepository; import com.yello.server.domain.vote.exception.VoteForbiddenException; import com.yello.server.domain.vote.exception.VoteNotFoundException; import com.yello.server.global.common.dto.BaseResponse; import com.yello.server.infrastructure.redis.exception.RedisException; import com.yello.server.infrastructure.redis.exception.RedisNotFoundException; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import com.yello.server.infrastructure.slack.factory.SlackWebhookMessageFactory; import javax.servlet.http.HttpServletRequest; -import lombok.RequiredArgsConstructor; import net.gpedro.integrations.slack.SlackApi; -import net.gpedro.integrations.slack.SlackAttachment; -import net.gpedro.integrations.slack.SlackField; import net.gpedro.integrations.slack.SlackMessage; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.task.TaskExecutor; -import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConversionException; import org.springframework.http.converter.HttpMessageNotReadableException; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StreamUtils; import org.springframework.validation.BindException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MissingServletRequestParameterException; @@ -71,122 +55,33 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice -@RequiredArgsConstructor public class ControllerExceptionAdvice { - private final UserRepository userRepository; + private final SlackApi slackErrorApi; + private final SlackWebhookMessageFactory slackWebhookMessageFactory; private final TaskExecutor taskExecutor; - private final TokenProvider tokenProvider; - private final List slackSender; + public ControllerExceptionAdvice( + @Qualifier("slackErrorApi") SlackApi slackErrorApi, + SlackWebhookMessageFactory slackWebhookMessageFactory, + TaskExecutor taskExecutor + ) { + this.slackWebhookMessageFactory = slackWebhookMessageFactory; + this.taskExecutor = taskExecutor; + this.slackErrorApi = slackErrorApi; + } @ExceptionHandler(Exception.class) void handleException(HttpServletRequest request, Exception exception) throws Exception { - SlackAttachment slackAttachment = new SlackAttachment(); - slackAttachment.setFallback("Error"); - slackAttachment.setColor("danger"); - slackAttachment.setTitle("๊ธด๊ธ‰ ํ™˜์ž๊ฐ€ ์ด์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค"); - slackAttachment.setTitleLink(request.getContextPath()); - slackAttachment.setText(Arrays.toString(exception.getStackTrace())); - slackAttachment.setColor("danger"); - - List slackFieldList = new ArrayList<>(); - slackFieldList.add( - new SlackField().setTitle("Request URL").setValue(request.getRequestURL().toString())); - slackFieldList.add( - new SlackField().setTitle("Request Method").setValue(request.getMethod())); - slackFieldList.add(new SlackField().setTitle("Request Time").setValue( - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()))); - slackFieldList.add( - new SlackField().setTitle("Request IP").setValue(request.getRemoteAddr())); - slackFieldList.add( - new SlackField().setTitle("Request User-Agent") - .setValue(request.getHeader(HttpHeaders.USER_AGENT))); - slackFieldList.add( - new SlackField().setTitle("์ธ์ฆ/์ธ๊ฐ€ ์ •๋ณด - Authorization") - .setValue(request.getHeader(HttpHeaders.AUTHORIZATION))); - slackFieldList.add( - new SlackField().setTitle("Request Body") - .setValue( - StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8))); - - final String token = - request.getHeader(HttpHeaders.AUTHORIZATION).substring("Bearer ".length()); - final Long userId = tokenProvider.getUserId(token); - final Optional user = userRepository.findById(userId); - String userInfo = "userId : " + userId - + "\nyelloId : " + (user.isPresent() ? user.get().getYelloId() : "null") - + "\ndeviceToken : " + (user.isPresent() ? user.get().getDeviceToken() : "null"); - slackFieldList.add( - new SlackField().setTitle("์ธ์ฆ/์ธ๊ฐ€ ์ •๋ณด - ์œ ์ €").setValue(userInfo)); - - slackAttachment.setFields(slackFieldList); - - SlackMessage slackMessage = new SlackMessage(); - slackMessage.setAttachments(Collections.singletonList(slackAttachment)); - slackMessage.setText("๊ธด๊ธ‰ ํ™˜์ž๊ฐ€ ์ด์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค"); - slackMessage.setUsername("์˜๋กœ ์†Œ๋ฐฉ์„œ"); - - Runnable runnable = () -> slackSender.get(0).call(slackMessage); + SlackMessage slackMessage = slackWebhookMessageFactory.generateSlackErrorMessage( + request, + exception + ); + Runnable runnable = () -> slackErrorApi.call(slackMessage); taskExecutor.execute(runnable); throw exception; } - @ExceptionHandler(CustomException.class) - public void handlePurchase(HttpServletRequest request, CustomException exception) throws IOException { - if (request.getRequestURL().toString().contains("purchase")) { - SlackAttachment slackAttachment = new SlackAttachment(); - - slackAttachment.setColor("green"); - slackAttachment.setTitle("ํ†ต์žฅ์— ๋ˆ์ด ์ž…๊ธˆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค"); - slackAttachment.setTitleLink(request.getContextPath()); - slackAttachment.setText(Arrays.toString(exception.getStackTrace())); - slackAttachment.setColor("green"); - - List slackFieldList = new ArrayList<>(); - slackFieldList.add( - new SlackField().setTitle("Request URL").setValue(request.getRequestURL().toString())); - slackFieldList.add( - new SlackField().setTitle("Request Method").setValue(request.getMethod())); - slackFieldList.add(new SlackField().setTitle("Request Time").setValue( - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()))); - slackFieldList.add( - new SlackField().setTitle("Request IP").setValue(request.getRemoteAddr())); - slackFieldList.add( - new SlackField().setTitle("Request User-Agent") - .setValue(request.getHeader(HttpHeaders.USER_AGENT))); - slackFieldList.add( - new SlackField().setTitle("์ธ์ฆ/์ธ๊ฐ€ ์ •๋ณด - Authorization") - .setValue(ObjectUtils.isEmpty(request.getHeader(HttpHeaders.AUTHORIZATION)) ? - "์—†์Œ" : request.getHeader(HttpHeaders.AUTHORIZATION))); - slackFieldList.add( - new SlackField().setTitle("Request Body") - .setValue(StreamUtils.copyToString(request.getInputStream(), - StandardCharsets.UTF_8))); - - final String token = - request.getHeader(HttpHeaders.AUTHORIZATION).substring("Bearer ".length()); - final Long userId = tokenProvider.getUserId(token); - final Optional user = userRepository.findById(userId); - String userInfo = "userId : " + userId - + "\nyelloId : " + (user.isPresent() ? user.get().getYelloId() : "null") - + "\ndeviceToken : " + (user.isPresent() ? user.get().getDeviceToken() : "null"); - slackFieldList.add( - new SlackField().setTitle("์ธ์ฆ/์ธ๊ฐ€ ์ •๋ณด - ์œ ์ €").setValue(userInfo)); - - slackAttachment.setFields(slackFieldList); - - SlackMessage slackMessage = new SlackMessage(); - slackMessage.setAttachments(Collections.singletonList(slackAttachment)); - slackMessage.setText("๋ˆ์ด ์ดค๋ผ๋ฝ"); - slackMessage.setUsername("์˜๋กœ ์€ํ–‰"); - - Runnable runnable = () -> slackSender.get(1).call(slackMessage); - taskExecutor.execute(runnable); - throw exception; - } - } - /** * 400 BAD REQUEST */ diff --git a/src/main/java/com/yello/server/infrastructure/firebase/manager/FCMManagerImpl.java b/src/main/java/com/yello/server/infrastructure/firebase/manager/FCMManagerImpl.java index 256452c4..3e49021c 100644 --- a/src/main/java/com/yello/server/infrastructure/firebase/manager/FCMManagerImpl.java +++ b/src/main/java/com/yello/server/infrastructure/firebase/manager/FCMManagerImpl.java @@ -7,9 +7,11 @@ import com.google.firebase.messaging.Notification; import com.yello.server.domain.vote.repository.VoteRepository; import com.yello.server.infrastructure.firebase.dto.request.NotificationMessage; +import lombok.Builder; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +@Builder @Service @RequiredArgsConstructor public class FCMManagerImpl implements FCMManager { diff --git a/src/main/java/com/yello/server/infrastructure/rabbitmq/service/ConsumerRabbitmqService.java b/src/main/java/com/yello/server/infrastructure/rabbitmq/service/ConsumerRabbitmqService.java index df9fa653..f73c26b9 100644 --- a/src/main/java/com/yello/server/infrastructure/rabbitmq/service/ConsumerRabbitmqService.java +++ b/src/main/java/com/yello/server/infrastructure/rabbitmq/service/ConsumerRabbitmqService.java @@ -5,12 +5,14 @@ import com.yello.server.infrastructure.firebase.service.NotificationService; import com.yello.server.infrastructure.rabbitmq.dto.response.VoteAvailableQueueResponse; import java.io.IOException; +import lombok.Builder; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Service; +@Builder @Service @RequiredArgsConstructor @Log4j2 diff --git a/src/main/java/com/yello/server/infrastructure/slack/annotation/SlackPurchaseNotification.java b/src/main/java/com/yello/server/infrastructure/slack/annotation/SlackPurchaseNotification.java new file mode 100644 index 00000000..78ad5ac3 --- /dev/null +++ b/src/main/java/com/yello/server/infrastructure/slack/annotation/SlackPurchaseNotification.java @@ -0,0 +1,12 @@ +package com.yello.server.infrastructure.slack.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SlackPurchaseNotification { + +} diff --git a/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackPurchaseNotificationAspect.java b/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackPurchaseNotificationAspect.java new file mode 100644 index 00000000..1a1d9853 --- /dev/null +++ b/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackPurchaseNotificationAspect.java @@ -0,0 +1,47 @@ +package com.yello.server.infrastructure.slack.aspect; + +import com.yello.server.infrastructure.slack.factory.SlackWebhookMessageFactory; +import javax.servlet.http.HttpServletRequest; +import net.gpedro.integrations.slack.SlackApi; +import net.gpedro.integrations.slack.SlackMessage; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.task.TaskExecutor; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +@Aspect +@Component +public class SlackPurchaseNotificationAspect { + + private final SlackApi slackPurchaseApi; + private final SlackWebhookMessageFactory slackWebhookMessageFactory; + private final TaskExecutor taskExecutor; + + public SlackPurchaseNotificationAspect( + @Qualifier("slackPurchaseApi") SlackApi slackPurchaseApi, + SlackWebhookMessageFactory slackWebhookMessageFactory, + TaskExecutor taskExecutor) { + this.slackPurchaseApi = slackPurchaseApi; + this.slackWebhookMessageFactory = slackWebhookMessageFactory; + this.taskExecutor = taskExecutor; + } + + @Around("@annotation(com.yello.server.infrastructure.slack.annotation.SlackPurchaseNotification)") + Object purchaseNotification(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()) + .getRequest(); + + SlackMessage slackMessage = slackWebhookMessageFactory.generateSlackPurchaseMessage( + request + ); + + Runnable runnable = () -> slackPurchaseApi.call(slackMessage); + taskExecutor.execute(runnable); + + return proceedingJoinPoint.proceed(); + } +} diff --git a/src/main/java/com/yello/server/infrastructure/slack/configuration/SlackConfiguration.java b/src/main/java/com/yello/server/infrastructure/slack/configuration/SlackConfiguration.java index d8fb64f1..495d7af2 100644 --- a/src/main/java/com/yello/server/infrastructure/slack/configuration/SlackConfiguration.java +++ b/src/main/java/com/yello/server/infrastructure/slack/configuration/SlackConfiguration.java @@ -9,18 +9,18 @@ public class SlackConfiguration { @Value("${slack.token.ambulence}") - String slackTokenAmbulence; + String slackTokenForError; @Value("${slack.token.bank}") - String slackTokenBank; + String slackTokenForPurchase; @Bean - SlackApi slackAmbulenceApi() { - return new SlackApi("https://hooks.slack.com/services/" + slackTokenAmbulence); + SlackApi slackErrorApi() { + return new SlackApi("https://hooks.slack.com/services/" + slackTokenForError); } @Bean - SlackApi slackBankApi() { - return new SlackApi("https://hooks.slack.com/services/" + slackTokenBank); + SlackApi slackPurchaseApi() { + return new SlackApi("https://hooks.slack.com/services/" + slackTokenForPurchase); } } diff --git a/src/main/java/com/yello/server/infrastructure/slack/factory/SlackWebhookMessageFactory.java b/src/main/java/com/yello/server/infrastructure/slack/factory/SlackWebhookMessageFactory.java new file mode 100644 index 00000000..6738b667 --- /dev/null +++ b/src/main/java/com/yello/server/infrastructure/slack/factory/SlackWebhookMessageFactory.java @@ -0,0 +1,111 @@ +package com.yello.server.infrastructure.slack.factory; + +import com.yello.server.domain.authorization.service.TokenProvider; +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.user.repository.UserRepository; +import com.yello.server.global.common.factory.TimeFactory; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import javax.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import net.gpedro.integrations.slack.SlackAttachment; +import net.gpedro.integrations.slack.SlackField; +import net.gpedro.integrations.slack.SlackMessage; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.util.StreamUtils; + +@Component +@RequiredArgsConstructor +public class SlackWebhookMessageFactory { + + private static final String ERROR_TITLE = "๊ธด๊ธ‰ ํ™˜์ž๊ฐ€ ์ด์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค"; + private static final String ERROR_USERNAME = "์˜๋กœ ์†Œ๋ฐฉ์„œ"; + private static final String PURCHASE_TITLE = "๋ˆ์ด ์ž…๊ธˆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."; + private static final String PURCHASE_USERNAME = "์˜๋กœ ๋ฑ…ํฌ"; + + private final UserRepository userRepository; + private final TokenProvider tokenProvider; + + public SlackMessage generateSlackErrorMessage( + HttpServletRequest request, + Exception exception + ) throws IOException { + return new SlackMessage() + .setAttachments(generateSlackErrorAttachment(request, exception)) + .setText(ERROR_TITLE) + .setUsername(ERROR_USERNAME); + } + + public SlackMessage generateSlackPurchaseMessage( + HttpServletRequest request + ) throws IOException { + return new SlackMessage() + .setAttachments(generateSlackPurchaseAttachment(request)) + .setText(PURCHASE_TITLE) + .setUsername(PURCHASE_USERNAME); + } + + private List generateSlackErrorAttachment( + HttpServletRequest request, + Exception exception + ) throws IOException { + final SlackAttachment slackAttachment = new SlackAttachment() + .setFallback("Error") + .setColor("danger") + .setTitle(ERROR_TITLE) + .setTitleLink(request.getContextPath()) + .setText(Arrays.toString(exception.getStackTrace())) + .setColor("danger") + .setFields(generateSlackFieldList(request)); + return Collections.singletonList(slackAttachment); + } + + private List generateSlackPurchaseAttachment( + HttpServletRequest request + ) throws IOException { + final SlackAttachment slackAttachment = new SlackAttachment() + .setColor("good") + .setTitle(PURCHASE_TITLE) + .setTitleLink(request.getContextPath()) + .setText(PURCHASE_TITLE) + .setFields(generateSlackFieldList(request)); + return Collections.singletonList(slackAttachment); + } + + private List generateSlackFieldList( + HttpServletRequest request + ) throws IOException { + final String token = + request.getHeader(HttpHeaders.AUTHORIZATION).substring("Bearer ".length()); + final Long userId = tokenProvider.getUserId(token); + final Optional user = userRepository.findById(userId); + final String yelloId = user.isPresent() ? user.get().getYelloId() : "null"; + final String deviceToken = user.isPresent() ? user.get().getDeviceToken() : "null"; + + String userInfo = + String.format("userId : %d %nyelloId : %s %ndeviceToken : %s", userId, yelloId, + deviceToken); + + return Arrays.asList( + new SlackField().setTitle("Request URL").setValue(request.getRequestURL().toString()), + new SlackField().setTitle("Request Time") + .setValue(TimeFactory.toDateFormattedString(LocalDateTime.now())), + new SlackField().setTitle("Request IP").setValue(request.getRemoteAddr()), + new SlackField().setTitle("Request User-Agent") + .setValue(request.getHeader(HttpHeaders.USER_AGENT)), + new SlackField().setTitle("์ธ์ฆ/์ธ๊ฐ€ ์ •๋ณด - Authorization") + .setValue(request.getHeader(HttpHeaders.AUTHORIZATION)), + new SlackField().setTitle("Request Body") + .setValue( + StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8)), + new SlackField().setTitle("์ธ์ฆ/์ธ๊ฐ€ ์ •๋ณด - ์œ ์ €").setValue(userInfo) + ); + } + +} diff --git a/src/main/resources/static/docs/add-friend.html b/src/main/resources/static/docs/add-friend.html new file mode 100644 index 00000000..c11c538f --- /dev/null +++ b/src/main/resources/static/docs/add-friend.html @@ -0,0 +1,501 @@ + + + + + + + +์นœ๊ตฌ ์ถ”๊ฐ€ํ•˜๊ธฐ + + + + + +
+
+

์นœ๊ตฌ ์ถ”๊ฐ€ํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/friend/1 HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ + ++++ + + + + + + + + + + + + +
Table 1. /api/v1/friend/{targetId}
ParameterDescription

targetId

์นœ๊ตฌ ์‹ ์ฒญํ•  ์ƒ๋Œ€ ์œ ์ €์˜ ์•„์ด๋”” ๊ฐ’

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์นœ๊ตฌ ์ถ”๊ฐ€์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/apple.html b/src/main/resources/static/docs/apple.html new file mode 100644 index 00000000..3ff3b5c0 --- /dev/null +++ b/src/main/resources/static/docs/apple.html @@ -0,0 +1,549 @@ + + + + + + + +Apple ๊ตฌ๋… ๊ตฌ๋งค ๊ฒ€์ฆํ•˜๊ธฐ + + + + + +
+
+

Apple ๊ตฌ๋… ๊ตฌ๋งค ๊ฒ€์ฆํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/purchase/apple/verify/subscribe HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Authorization: Bearer your-access-token
+Content-Length: 68
+
+{
+  "transactionId" : "transactionId",
+  "productId" : "productId"
+}
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์ธ์•ฑ๊ฒฐ์ œ ๊ฒ€์ฆ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."
+}
+
+
+
+
+
+
+

Apple ์—ด๋žŒ๊ถŒ ๊ตฌ๋งค ๊ฒ€์ฆํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/purchase/apple/verify/ticket HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Authorization: Bearer your-access-token
+Content-Length: 68
+
+{
+  "transactionId" : "transactionId",
+  "productId" : "productId"
+}
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์ธ์•ฑ๊ฒฐ์ œ ๊ฒ€์ฆ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."
+}
+
+
+
+
+
+
+

Apple ํ™˜๋ถˆํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
DELETE /api/v1/purchase/apple/refund HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์ธ์•ฑ๊ฒฐ์ œ ๊ฒ€์ฆ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/check-keyword.html b/src/main/resources/static/docs/check-keyword.html new file mode 100644 index 00000000..97598443 --- /dev/null +++ b/src/main/resources/static/docs/check-keyword.html @@ -0,0 +1,504 @@ + + + + + + + +ํˆฌํ‘œ ํ‚ค์›Œ๋“œ ํ™•์ธํ•˜๊ธฐ + + + + + +
+
+

ํˆฌํ‘œ ํ‚ค์›Œ๋“œ ํ™•์ธํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
PATCH /api/v1/vote/1/keyword HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ + ++++ + + + + + + + + + + + + +
Table 1. /api/v1/vote/{voteId}/keyword
ParameterDescription

voteId

ํˆฌํ‘œ ์•„์ด๋”” ๊ฐ’

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "ํ‚ค์›Œ๋“œ ํ™•์ธ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "answer" : "test"
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/check-user-by-id.html b/src/main/resources/static/docs/check-user-by-id.html new file mode 100644 index 00000000..a29df723 --- /dev/null +++ b/src/main/resources/static/docs/check-user-by-id.html @@ -0,0 +1,488 @@ + + + + + + + +์œ ์ € ์ •๋ณด ์กฐํšŒํ•˜๊ธฐ + + + + + +
+
+

์œ ์ € ์ •๋ณด ์กฐํšŒํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/user/2 HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์œ ์ € ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "userId" : 2,
+    "name" : "test",
+    "profileImageUrl" : "profile",
+    "group" : "group",
+    "yelloId" : "yelloId",
+    "yelloCount" : 0,
+    "friendCount" : 0
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/check-user.html b/src/main/resources/static/docs/check-user.html new file mode 100644 index 00000000..4b0acfd6 --- /dev/null +++ b/src/main/resources/static/docs/check-user.html @@ -0,0 +1,489 @@ + + + + + + + +๋‚ด ์ •๋ณด ์กฐํšŒํ•˜๊ธฐ + + + + + +
+
+

๋‚ด ์ •๋ณด ์กฐํšŒํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/user HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์œ ์ € ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "userId" : 1,
+    "name" : "test",
+    "profileImageUrl" : "profile",
+    "group" : "group",
+    "yelloId" : "yelloId",
+    "yelloCount" : 0,
+    "friendCount" : 0,
+    "point" : 200
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/check-vote-available.html b/src/main/resources/static/docs/check-vote-available.html new file mode 100644 index 00000000..8633b56f --- /dev/null +++ b/src/main/resources/static/docs/check-vote-available.html @@ -0,0 +1,484 @@ + + + + + + + +ํˆฌํ‘œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ์กฐํšŒ + + + + + +
+
+

ํˆฌํ‘œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ์กฐํšŒ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/vote/available HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "ํˆฌํ‘œ ์‹œ์ž‘ํ•˜๊ธฐ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "isPossible" : false,
+    "point" : 200,
+    "createdAt" : "2023-08-27 23:08:50"
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/create-vote.html b/src/main/resources/static/docs/create-vote.html new file mode 100644 index 00000000..cb8ac7e9 --- /dev/null +++ b/src/main/resources/static/docs/create-vote.html @@ -0,0 +1,494 @@ + + + + + + + +ํˆฌํ‘œ ์ƒ์„ฑํ•˜๊ธฐ + + + + + +
+
+

ํˆฌํ‘œ ์ƒ์„ฑํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/vote HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Authorization: Bearer your-access-token
+Content-Length: 151
+
+{
+  "voteAnswerList" : [ {
+    "friendId" : 2,
+    "questionId" : 1,
+    "keywordName" : "ํ‚ค์›Œ๋“œ",
+    "colorIndex" : 0
+  } ],
+  "totalPoint" : 10
+}
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 201,
+  "message" : "ํˆฌํ‘œ๋ฅผ ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "point" : 10
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/delete-friend.html b/src/main/resources/static/docs/delete-friend.html new file mode 100644 index 00000000..4707d7f8 --- /dev/null +++ b/src/main/resources/static/docs/delete-friend.html @@ -0,0 +1,501 @@ + + + + + + + +์นœ๊ตฌ ์‚ญ์ œํ•˜๊ธฐ + + + + + +
+
+

์นœ๊ตฌ ์‚ญ์ œํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
DELETE /api/v1/friend/1 HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ + ++++ + + + + + + + + + + + + +
Table 1. /api/v1/friend/{targetId}
ParameterDescription

targetId

์‚ญ์ œํ•  ์ƒ๋Œ€ ์œ ์ €์˜ ์•„์ด๋”” ๊ฐ’

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์นœ๊ตฌ ์‚ญ์ œ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/delete-user.html b/src/main/resources/static/docs/delete-user.html new file mode 100644 index 00000000..63e884e2 --- /dev/null +++ b/src/main/resources/static/docs/delete-user.html @@ -0,0 +1,479 @@ + + + + + + + +์œ ์ € ํƒˆํ‡ดํ•˜๊ธฐ + + + + + +
+
+

์œ ์ € ํƒˆํ‡ดํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
DELETE /api/v1/user HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์œ ์ € ํƒˆํ‡ด์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/device-token.html b/src/main/resources/static/docs/device-token.html new file mode 100644 index 00000000..424399f4 --- /dev/null +++ b/src/main/resources/static/docs/device-token.html @@ -0,0 +1,486 @@ + + + + + + + +๋””๋ฐ”์ด์Šค ํ† ํฐ ์ˆ˜์ •ํ•˜๊ธฐ + + + + + +
+
+

๋””๋ฐ”์ด์Šค ํ† ํฐ ์ˆ˜์ •ํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
PUT /api/v1/user/device HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Authorization: Bearer your-access-token
+Content-Length: 39
+
+{
+  "deviceToken" : "testDeviceToken"
+}
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "deviceToken ์—…๋ฐ์ดํŠธ์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค",
+  "data" : { }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/find-friend-votes.html b/src/main/resources/static/docs/find-friend-votes.html new file mode 100644 index 00000000..21065f52 --- /dev/null +++ b/src/main/resources/static/docs/find-friend-votes.html @@ -0,0 +1,517 @@ + + + + + + + +์นœ๊ตฌ ํˆฌํ‘œ ์ „์ฒด ์กฐํšŒ + + + + + +
+
+

์นœ๊ตฌ ํˆฌํ‘œ ์ „์ฒด ์กฐํšŒ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/vote/friend?page=0 HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ ++++ + + + + + + + + + + + + +
ParameterDescription

page

ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "ํˆฌํ‘œ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "totalCount" : 1,
+    "friendVotes" : [ {
+      "id" : 1,
+      "receiverName" : "name2",
+      "senderGender" : "MALE",
+      "vote" : {
+        "nameHead" : "๋‚˜๋Š”",
+        "nameFoot" : "์™€",
+        "keywordHead" : "๋ฉ‹์ง„",
+        "keyword" : "test",
+        "keywordFoot" : "์—์„œ ๋†€๊ณ ์‹ถ์–ด"
+      },
+      "isHintUsed" : false,
+      "createdAt" : "0์ดˆ ์ „"
+    } ]
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/find-friends.html b/src/main/resources/static/docs/find-friends.html new file mode 100644 index 00000000..9948df48 --- /dev/null +++ b/src/main/resources/static/docs/find-friends.html @@ -0,0 +1,512 @@ + + + + + + + +๋‚ด ์นœ๊ตฌ ์ „์ฒด ์กฐํšŒํ•˜๊ธฐ + + + + + +
+
+

๋‚ด ์นœ๊ตฌ ์ „์ฒด ์กฐํšŒํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/friend?page=0 HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ ++++ + + + + + + + + + + + + +
ParameterDescription

page

ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์นœ๊ตฌ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "totalCount" : 0,
+    "friends" : [ {
+      "userId" : 1,
+      "name" : "name1",
+      "profileImageUrl" : "test image",
+      "group" : "ํ…Œ์ŠคํŠธ ๋Œ€ํ•™๊ต 1 ํ…Œ์ŠคํŠธ ํ•™๊ณผ 1 20ํ•™๋ฒˆ",
+      "yelloId" : "yelloId1",
+      "yelloCount" : 0,
+      "friendCount" : 0
+    } ]
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/find-group-friends.html b/src/main/resources/static/docs/find-group-friends.html new file mode 100644 index 00000000..dd2e1b4e --- /dev/null +++ b/src/main/resources/static/docs/find-group-friends.html @@ -0,0 +1,509 @@ + + + + + + + +๊ทธ๋ฃน ์ถ”์ฒœ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ + + + + + +
+
+

๊ทธ๋ฃน ์ถ”์ฒœ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/friend/recommend/school?page=0 HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ ++++ + + + + + + + + + + + + +
ParameterDescription

page

ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์นœ๊ตฌ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "totalCount" : 0,
+    "friends" : [ {
+      "id" : 1,
+      "name" : "name1",
+      "group" : "ํ…Œ์ŠคํŠธ ๋Œ€ํ•™๊ต 1 ํ…Œ์ŠคํŠธ ํ•™๊ณผ 1 20ํ•™๋ฒˆ",
+      "profileImage" : "test image"
+    } ]
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/find-kakao-friends.html b/src/main/resources/static/docs/find-kakao-friends.html new file mode 100644 index 00000000..fe65ed1e --- /dev/null +++ b/src/main/resources/static/docs/find-kakao-friends.html @@ -0,0 +1,506 @@ + + + + + + + +์นด์นด์˜ค ์ถ”์ฒœ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ + + + + + +
+
+

์นด์นด์˜ค ์ถ”์ฒœ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/friend/recommend/kakao?page=0 HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Authorization: Bearer your-access-token
+Content-Length: 41
+
+{
+  "friendKakaoId" : [ "testKakaoId" ]
+}
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ ++++ + + + + + + + + + + + + +
ParameterDescription

page

ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์นœ๊ตฌ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/find-onboarding-friends.html b/src/main/resources/static/docs/find-onboarding-friends.html new file mode 100644 index 00000000..3e3723d7 --- /dev/null +++ b/src/main/resources/static/docs/find-onboarding-friends.html @@ -0,0 +1,515 @@ + + + + + + + +๊ฐ€์ž…ํ•œ ์นœ๊ตฌ ๋ชฉ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + + + + + +
+
+

๊ฐ€์ž…ํ•œ ์นœ๊ตฌ ๋ชฉ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/auth/friend?page=0 HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Content-Length: 43
+
+{
+  "friendKakaoId" : [ "friendKakaoId" ]
+}
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ ++++ + + + + + + + + + + + + +
ParameterDescription

page

ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์ถ”์ฒœ ์นœ๊ตฌ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "totalCount" : 0,
+    "friendList" : [ {
+      "group" : "KAKAO",
+      "id" : 1,
+      "name" : "name1",
+      "profileImage" : "test image",
+      "groupName" : "ํ…Œ์ŠคํŠธ ๋Œ€ํ•™๊ต 1 ํ…Œ์ŠคํŠธ ํ•™๊ณผ 1"
+    } ]
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/find-question.html b/src/main/resources/static/docs/find-question.html new file mode 100644 index 00000000..e41d8086 --- /dev/null +++ b/src/main/resources/static/docs/find-question.html @@ -0,0 +1,496 @@ + + + + + + + +ํˆฌํ‘œ ์งˆ๋ฌธ ์กฐํšŒํ•˜๊ธฐ + + + + + +
+
+

ํˆฌํ‘œ ์งˆ๋ฌธ ์กฐํšŒํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/vote/question HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "ํˆฌํ‘œ ์งˆ๋ฌธ ๋ฆฌ์ŠคํŠธ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : [ {
+    "question" : {
+      "questionId" : 1,
+      "nameHead" : "๋‚˜๋Š”",
+      "nameFoot" : "์™€",
+      "keywordHead" : "๋ฉ‹์ง„",
+      "keywordFoot" : "์—์„œ ๋†€๊ณ ์‹ถ์–ด"
+    },
+    "friendList" : [ {
+      "friendId" : 2,
+      "friendName" : "name2",
+      "friendYelloId" : "yelloId2"
+    } ],
+    "keywordList" : [ "A", "B", "C", "D" ],
+    "questionPoint" : 10,
+    "subscribe" : "normal | active"
+  } ]
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/find-vote.html b/src/main/resources/static/docs/find-vote.html new file mode 100644 index 00000000..8e583c19 --- /dev/null +++ b/src/main/resources/static/docs/find-vote.html @@ -0,0 +1,518 @@ + + + + + + + +ํˆฌํ‘œ ์ƒ์„ธ ์กฐํšŒ + + + + + +
+
+

ํˆฌํ‘œ ์ƒ์„ธ ์กฐํšŒ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/vote/1 HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ + ++++ + + + + + + + + + + + + +
Table 1. /api/v1/vote/{voteId}
ParameterDescription

voteId

ํˆฌํ‘œ ์•„์ด๋”” ๊ฐ’

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "ํˆฌํ‘œ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "colorIndex" : 0,
+    "currentPoint" : 200,
+    "nameHint" : -1,
+    "isAnswerRevealed" : false,
+    "senderName" : "name1",
+    "senderGender" : "MALE",
+    "vote" : {
+      "nameHead" : "๋‚˜๋Š”",
+      "nameFoot" : "์™€",
+      "keywordHead" : "๋ฉ‹์ง„",
+      "keyword" : "test",
+      "keywordFoot" : "์—์„œ ๋†€๊ณ ์‹ถ์–ด"
+    },
+    "ticketCount" : 0,
+    "isSubscribe" : false
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/find-votes.html b/src/main/resources/static/docs/find-votes.html new file mode 100644 index 00000000..72e36426 --- /dev/null +++ b/src/main/resources/static/docs/find-votes.html @@ -0,0 +1,524 @@ + + + + + + + +๋‚ด ํˆฌํ‘œ ์ „์ฒด ์กฐํšŒ + + + + + +
+
+

๋‚ด ํˆฌํ‘œ ์ „์ฒด ์กฐํšŒ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/vote?page=0 HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ ++++ + + + + + + + + + + + + +
ParameterDescription

page

ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "ํˆฌํ‘œ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "totalCount" : 1,
+    "ticketCount" : 0,
+    "openCount" : 0,
+    "openKeywordCount" : 0,
+    "openNameCount" : 0,
+    "openFullNameCount" : 0,
+    "votes" : [ {
+      "id" : 1,
+      "senderGender" : "MALE",
+      "senderName" : "name1",
+      "nameHint" : -1,
+      "vote" : {
+        "nameHead" : "๋‚˜๋Š”",
+        "nameFoot" : "์™€",
+        "keywordHead" : "๋ฉ‹์ง„",
+        "keyword" : "test",
+        "keywordFoot" : "์—์„œ ๋†€๊ณ ์‹ถ์–ด"
+      },
+      "isHintUsed" : false,
+      "isRead" : false,
+      "createdAt" : "0์ดˆ ์ „"
+    } ]
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/get-unread-vote.html b/src/main/resources/static/docs/get-unread-vote.html new file mode 100644 index 00000000..332c20f5 --- /dev/null +++ b/src/main/resources/static/docs/get-unread-vote.html @@ -0,0 +1,482 @@ + + + + + + + +์ฝ์ง€ ์•Š์€ ์ชฝ์ง€ ๊ฐœ์ˆ˜ ์กฐํšŒ + + + + + +
+
+

์ฝ์ง€ ์•Š์€ ์ชฝ์ง€ ๊ฐœ์ˆ˜ ์กฐํšŒ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/vote/count HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "ํˆฌํ‘œ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "totalCount" : 1
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/google.html b/src/main/resources/static/docs/google.html new file mode 100644 index 00000000..7fd1a3ed --- /dev/null +++ b/src/main/resources/static/docs/google.html @@ -0,0 +1,542 @@ + + + + + + + +Google ๊ตฌ๋… ๊ตฌ๋งค ๊ฒ€์ฆํ•˜๊ธฐ + + + + + +
+
+

Google ๊ตฌ๋… ๊ตฌ๋งค ๊ฒ€์ฆํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/purchase/google/verify/subscribe HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Authorization: Bearer your-access-token
+Content-Length: 239
+
+{
+  "orderId" : "orderId",
+  "packageName" : "packageName",
+  "productId" : "productId",
+  "purchaseTime" : 1,
+  "purchaseState" : 1,
+  "purchaseToken" : "purchaseToken",
+  "quantity" : 1,
+  "autoRenewing" : true,
+  "acknowledged" : true
+}
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 201,
+  "message" : "๊ตฌ๊ธ€ ๊ตฌ๋… ๊ฒฐ์ œ ๊ฒ€์ฆ ๋ฐ ๋ฐ˜์˜์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "productId" : "productId",
+    "expiredAt" : "2023-08-27T23:08:49.542865"
+  }
+}
+
+
+
+
+
+
+

Google ์—ด๋žŒ๊ถŒ ๊ตฌ๋งค ๊ฒ€์ฆํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/purchase/google/verify/ticket HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Authorization: Bearer your-access-token
+Content-Length: 214
+
+{
+  "orderId" : "orderId",
+  "packageName" : "packageName",
+  "productId" : "productId",
+  "purchaseTime" : 1,
+  "purchaseState" : 1,
+  "purchaseToken" : "purchaseToken",
+  "quantity" : 1,
+  "acknowledged" : true
+}
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 201,
+  "message" : "๊ตฌ๊ธ€ ์ธ์•ฑ ๊ฒฐ์ œ ๊ฒ€์ฆ ๋ฐ ๋ฐ˜์˜์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "productId" : "productId",
+    "ticketCount" : 0
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/index.html b/src/main/resources/static/docs/index.html new file mode 100644 index 00000000..9601d2ea --- /dev/null +++ b/src/main/resources/static/docs/index.html @@ -0,0 +1,614 @@ + + + + + + + +YELL:O API ๋ฌธ์„œ + + + + + + +
+
+

APIs

+
+ + + + + + +
+
+
+ + + + + + \ No newline at end of file diff --git a/src/main/resources/static/docs/login.html b/src/main/resources/static/docs/login.html new file mode 100644 index 00000000..c5f4577b --- /dev/null +++ b/src/main/resources/static/docs/login.html @@ -0,0 +1,491 @@ + + + + + + + +์†Œ์…œ ๋กœ๊ทธ์ธ + + + + + +
+
+

์†Œ์…œ ๋กœ๊ทธ์ธ

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/auth/oauth HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Content-Length: 91
+
+{
+  "accessToken" : "accessToken",
+  "social" : "social",
+  "deviceToken" : "deviceToken"
+}
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 201,
+  "message" : "๋กœ๊ทธ์ธ์ด ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "isResigned" : false,
+    "accessToken" : "serviceAccessToken",
+    "refreshToken" : "serviceRefreshToken"
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/overview.html b/src/main/resources/static/docs/overview.html new file mode 100644 index 00000000..8b891673 --- /dev/null +++ b/src/main/resources/static/docs/overview.html @@ -0,0 +1,522 @@ + + + + + + + +Overview + + + + + +
+
+

Overview

+
+
+

Host

+ ++++ + + + + + + + + + + + + + + + + +
ํ™˜๊ฒฝHost

Development

BEํŒ€์—๊ฒŒ ๋ฌธ์˜

Production

BEํŒ€์—๊ฒŒ ๋ฌธ์˜

+
+
+

HTTP status codes

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
์ƒํƒœ ์ฝ”๋“œ์„ค๋ช…

200 OK

์„ฑ๊ณต

400 Bad Request

์ž˜๋ชป๋œ ์š”์ฒญ

401 Unauthorized

๋น„์ธ์ฆ ์ƒํƒœ

403 Forbidden

๊ถŒํ•œ ๊ฑฐ๋ถ€

404 Not Found

์กด์žฌํ•˜์ง€ ์•Š๋Š” ์š”์ฒญ ๋ฆฌ์†Œ์Šค

500 Internal Server Error

์„œ๋ฒ„ ์—๋Ÿฌ

+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/pay.html b/src/main/resources/static/docs/pay.html new file mode 100644 index 00000000..87595924 --- /dev/null +++ b/src/main/resources/static/docs/pay.html @@ -0,0 +1,485 @@ + + + + + + + +์นœ๊ตฌ ์ถ”๊ฐ€ํ•˜๊ธฐ + + + + + +
+
+

์นœ๊ตฌ ์ถ”๊ฐ€ํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/pay HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Authorization: Bearer your-access-token
+Content-Length: 17
+
+{
+  "index" : 1
+}
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 201,
+  "message" : "์ด์šฉ๊ถŒ ๋ฒ„ํŠผ ํด๋ฆญ ํšŸ์ˆ˜๊ฐ€ ์ €์žฅ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค."
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/purchase-check.html b/src/main/resources/static/docs/purchase-check.html new file mode 100644 index 00000000..400081bb --- /dev/null +++ b/src/main/resources/static/docs/purchase-check.html @@ -0,0 +1,484 @@ + + + + + + + +๊ตฌ๋… ์ƒํƒœ ๋ฐ ์—ด๋žŒ๊ถŒ ๊ฐœ์ˆ˜ ์กฐํšŒํ•˜๊ธฐ + + + + + +
+
+

๊ตฌ๋… ์ƒํƒœ ๋ฐ ์—ด๋žŒ๊ถŒ ๊ฐœ์ˆ˜ ์กฐํšŒํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/purchase HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์œ ์ € ๊ฒฐ์ œ ์ •๋ณด ์กฐํšŒ์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค",
+  "data" : {
+    "subscribeState" : "NORMAL",
+    "isSubscribe" : false,
+    "ticketCount" : 0
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/reissue-token.html b/src/main/resources/static/docs/reissue-token.html new file mode 100644 index 00000000..20957548 --- /dev/null +++ b/src/main/resources/static/docs/reissue-token.html @@ -0,0 +1,512 @@ + + + + + + + +ํ† ํฐ ์žฌ๋ฐœ๊ธ‰ + + + + + +
+
+

ํ† ํฐ ์žฌ๋ฐœ๊ธ‰

+
+
+

HTTP request

+
+
+
POST /api/v1/auth/token/issue HTTP/1.1
+X-ACCESS-AUTH: Bearer your-access-token
+X-REFRESH-AUTH: Bearer your-refresh-token
+
+
+
+
+

HTTP response

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 201,
+  "message" : "ํ† ํฐ ์žฌ๋ฐœ๊ธ‰์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "accessToken" : "new accessToken",
+    "refreshToken" : "new refreshToken"
+  }
+}
+
+
+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/auth/token/issue HTTP/1.1
+X-ACCESS-AUTH: Bearer your-access-token
+X-REFRESH-AUTH: Bearer your-refresh-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 201,
+  "message" : "ํ† ํฐ ์žฌ๋ฐœ๊ธ‰์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "accessToken" : "new accessToken",
+    "refreshToken" : "new refreshToken"
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/reveal-full-name.html b/src/main/resources/static/docs/reveal-full-name.html new file mode 100644 index 00000000..0972a3b8 --- /dev/null +++ b/src/main/resources/static/docs/reveal-full-name.html @@ -0,0 +1,504 @@ + + + + + + + +ํˆฌํ‘œ ์ด๋ฆ„ ์ „์ฒด ์กฐํšŒ + + + + + +
+
+

ํˆฌํ‘œ ์ด๋ฆ„ ์ „์ฒด ์กฐํšŒ

+
+
+

์š”์ฒญ

+
+
+
PATCH /api/v1/vote/1/fullname HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ + ++++ + + + + + + + + + + + + +
Table 1. /api/v1/vote/{voteId}/fullname
ParameterDescription

voteId

ํˆฌํ‘œ ์•„์ด๋”” ๊ฐ’

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์ „์ฒด ์ด๋ฆ„ ํ™•์ธ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "name" : "name1"
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/reveal-name.html b/src/main/resources/static/docs/reveal-name.html new file mode 100644 index 00000000..d07b83d4 --- /dev/null +++ b/src/main/resources/static/docs/reveal-name.html @@ -0,0 +1,505 @@ + + + + + + + +ํˆฌํ‘œ ์ด๋ฆ„ ๋ถ€๋ถ„ ์กฐํšŒ + + + + + +
+
+

ํˆฌํ‘œ ์ด๋ฆ„ ๋ถ€๋ถ„ ์กฐํšŒ

+
+
+

์š”์ฒญ

+
+
+
PATCH /api/v1/vote/1/name HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ + ++++ + + + + + + + + + + + + +
Table 1. /api/v1/vote/{voteId}/name
ParameterDescription

voteId

ํˆฌํ‘œ ์•„์ด๋”” ๊ฐ’

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์ด๋ฆ„ ์ดˆ์„ฑ ํ™•์ธ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "name" : "n",
+    "nameIndex" : 0
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/search-department.html b/src/main/resources/static/docs/search-department.html new file mode 100644 index 00000000..5ae8c19f --- /dev/null +++ b/src/main/resources/static/docs/search-department.html @@ -0,0 +1,514 @@ + + + + + + + +๋Œ€ํ•™๊ต ํ•™๊ณผ ๊ฒ€์ƒ‰ํ•˜๊ธฐ + + + + + +
+
+

๋Œ€ํ•™๊ต ํ•™๊ณผ ๊ฒ€์ƒ‰ํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/auth/school/department?page=0&school=school+name+here&keyword=keyword+here HTTP/1.1
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ ++++ + + + + + + + + + + + + + + + + + + + + +
ParameterDescription

page

ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ

school

ํ•™๊ต ์ด๋ฆ„

keyword

๊ฒ€์ƒ‰ํ•  ์ฟผ๋ฆฌ

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "ํ•™๊ณผ ๊ฒ€์ƒ‰์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "totalCount" : 0,
+    "groupList" : [ {
+      "groupId" : 1,
+      "departmentName" : "ํ…Œ์ŠคํŠธ ํ•™๊ณผ 1"
+    } ]
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/search-friend.html b/src/main/resources/static/docs/search-friend.html new file mode 100644 index 00000000..faa74135 --- /dev/null +++ b/src/main/resources/static/docs/search-friend.html @@ -0,0 +1,515 @@ + + + + + + + +์นœ๊ตฌ ๊ฒ€์ƒ‰ํ•˜๊ธฐ + + + + + +
+
+

์นœ๊ตฌ ๊ฒ€์ƒ‰ํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/friend/search?page=0&keyword=keyword+here HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ ++++ + + + + + + + + + + + + + + + + +
ParameterDescription

page

ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ

keyword

๊ฒ€์ƒ‰ํ•  ์ฟผ๋ฆฌ

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์นœ๊ตฌ ๊ฒ€์ƒ‰ํ•˜๊ธฐ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "totalCount" : 0,
+    "friendList" : [ {
+      "id" : 1,
+      "name" : "name1",
+      "group" : "ํ…Œ์ŠคํŠธ ๋Œ€ํ•™๊ต 1 ํ…Œ์ŠคํŠธ ํ•™๊ณผ 1 20ํ•™๋ฒˆ",
+      "profileImage" : "test image",
+      "yelloId" : "yelloId1",
+      "isFriend" : false
+    } ]
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/search-school.html b/src/main/resources/static/docs/search-school.html new file mode 100644 index 00000000..637a5812 --- /dev/null +++ b/src/main/resources/static/docs/search-school.html @@ -0,0 +1,507 @@ + + + + + + + +๋Œ€ํ•™๊ต ๊ฒ€์ƒ‰ํ•˜๊ธฐ + + + + + +
+
+

๋Œ€ํ•™๊ต ๊ฒ€์ƒ‰ํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/auth/school?page=0&keyword=keyword+here HTTP/1.1
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ ++++ + + + + + + + + + + + + + + + + +
ParameterDescription

page

ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ

keyword

๊ฒ€์ƒ‰ํ•  ์ฟผ๋ฆฌ

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "ํ•™๊ต ๊ฒ€์ƒ‰์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "totalCount" : 0,
+    "groupNameList" : [ "groupName" ]
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/shuffle-friends.html b/src/main/resources/static/docs/shuffle-friends.html new file mode 100644 index 00000000..6dd6752a --- /dev/null +++ b/src/main/resources/static/docs/shuffle-friends.html @@ -0,0 +1,484 @@ + + + + + + + +์…”ํ”Œํ•œ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ + + + + + +
+
+

์…”ํ”Œํ•œ ์นœ๊ตฌ ์กฐํšŒํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/friend/shuffle HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์นœ๊ตฌ ์…”ํ”Œ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : [ {
+    "friendId" : 2,
+    "friendName" : "name2",
+    "friendYelloId" : "yelloId2"
+  } ]
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/signup.html b/src/main/resources/static/docs/signup.html new file mode 100644 index 00000000..81c5ec72 --- /dev/null +++ b/src/main/resources/static/docs/signup.html @@ -0,0 +1,500 @@ + + + + + + + +ํšŒ์›๊ฐ€์ž… + + + + + +
+
+

ํšŒ์›๊ฐ€์ž…

+
+
+

์š”์ฒญ

+
+
+
POST /api/v1/auth/signup HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Content-Length: 307
+
+{
+  "social" : "KAKAO",
+  "uuid" : "uuid",
+  "deviceToken" : "deviceToken",
+  "email" : "email@emall.com",
+  "profileImage" : "profileImage",
+  "groupId" : 1,
+  "groupAdmissionYear" : 20,
+  "name" : "name",
+  "yelloId" : "yelloId",
+  "gender" : "MALE",
+  "friends" : [ 1 ],
+  "recommendId" : "recommendId"
+}
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 201,
+  "message" : "ํšŒ์› ๊ฐ€์ž…์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "yelloId" : "yelloId",
+    "accessToken" : "serviceAccessToken",
+    "refreshToken" : "serviceRefreshToken"
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/sub-check.html b/src/main/resources/static/docs/sub-check.html new file mode 100644 index 00000000..6b02b3be --- /dev/null +++ b/src/main/resources/static/docs/sub-check.html @@ -0,0 +1,483 @@ + + + + + + + +๊ตฌ๋… ์—ฐ์žฅ ์œ ๋„ ํ•„์š” ์—ฌ๋ถ€ ํ™•์ธํ•˜๊ธฐ + + + + + +
+
+

๊ตฌ๋… ์—ฐ์žฅ ์œ ๋„ ํ•„์š” ์—ฌ๋ถ€ ํ™•์ธํ•˜๊ธฐ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/purchase/subscribe HTTP/1.1
+Authorization: Bearer your-access-token
+
+
+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์œ ์ € ๊ตฌ๋… ์—ฐ์žฅ ์œ ๋„ ํ•„์š” ์—ฌ๋ถ€ ํ™•์ธ ์กฐํšŒ์— ์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค.",
+  "data" : {
+    "subscribe" : "NORMAL",
+    "isSubscribeNeeded" : false
+  }
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/validate-yelloid.html b/src/main/resources/static/docs/validate-yelloid.html new file mode 100644 index 00000000..89a3508a --- /dev/null +++ b/src/main/resources/static/docs/validate-yelloid.html @@ -0,0 +1,500 @@ + + + + + + + +์˜๋กœ ์•„์ด๋”” ์ค‘๋ณต ํ™•์ธ + + + + + +
+
+

์˜๋กœ ์•„์ด๋”” ์ค‘๋ณต ํ™•์ธ

+
+
+

์š”์ฒญ

+
+
+
GET /api/v1/auth/valid?yelloId=yelloId+here HTTP/1.1
+
+
+
+
+

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ

+ ++++ + + + + + + + + + + + + +
ParameterDescription

yelloId

์ค‘๋ณต ์ฒดํฌํ•  yelloId

+
+
+

์‘๋‹ต

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "status" : 200,
+  "message" : "์˜๋กœ ์•„์ด๋”” ์ค‘๋ณต ์—ฌ๋ถ€ ์กฐํšŒ์— ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.",
+  "data" : false
+}
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/test/java/com/yello/server/ServerApplicationTests.java b/src/test/java/com/yello/server/ServerApplicationTests.java deleted file mode 100644 index 0e120911..00000000 --- a/src/test/java/com/yello/server/ServerApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.yello.server; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class ServerApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/src/test/java/com/yello/server/small/domain/authorization/FakeAuthManager.java b/src/test/java/com/yello/server/domain/authorization/FakeAuthManager.java similarity index 96% rename from src/test/java/com/yello/server/small/domain/authorization/FakeAuthManager.java rename to src/test/java/com/yello/server/domain/authorization/FakeAuthManager.java index b7e82fea..c23cb568 100644 --- a/src/test/java/com/yello/server/small/domain/authorization/FakeAuthManager.java +++ b/src/test/java/com/yello/server/domain/authorization/FakeAuthManager.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.authorization; +package com.yello.server.domain.authorization; import static com.yello.server.global.common.ErrorCode.NOT_SIGNIN_USER_EXCEPTION; import static com.yello.server.global.common.ErrorCode.UUID_CONFLICT_USER_EXCEPTION; @@ -76,7 +76,7 @@ public void validateSignupRequest(SignUpRequest signUpRequest) { throw new UserConflictException(UUID_CONFLICT_USER_EXCEPTION); }); - userRepository.findByYelloId(signUpRequest.yelloId()) + userRepository.findByYelloIdNotFiltered(signUpRequest.yelloId()) .ifPresent(action -> { throw new UserConflictException(YELLOID_CONFLICT_USER_EXCEPTION); }); @@ -86,7 +86,7 @@ public void validateSignupRequest(SignUpRequest signUpRequest) { public Boolean renewUserData(User user) { final Long userId = user.getId(); - if (user.getDeletedAt()!=null) { + if (user.getDeletedAt() != null) { user.renew(); friendRepository.findAllByUserIdNotFiltered(userId) diff --git a/src/test/java/com/yello/server/small/domain/authorization/FakeConnectionManager.java b/src/test/java/com/yello/server/domain/authorization/FakeConnectionManager.java similarity index 87% rename from src/test/java/com/yello/server/small/domain/authorization/FakeConnectionManager.java rename to src/test/java/com/yello/server/domain/authorization/FakeConnectionManager.java index cdf97787..7a3e3ec2 100644 --- a/src/test/java/com/yello/server/small/domain/authorization/FakeConnectionManager.java +++ b/src/test/java/com/yello/server/domain/authorization/FakeConnectionManager.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.authorization; +package com.yello.server.domain.authorization; import com.yello.server.domain.authorization.dto.kakao.KakaoTokenInfo; import com.yello.server.global.common.manager.ConnectionManager; diff --git a/src/test/java/com/yello/server/domain/authorization/medium/AuthControllerTest.java b/src/test/java/com/yello/server/domain/authorization/medium/AuthControllerTest.java new file mode 100644 index 00000000..15536c6c --- /dev/null +++ b/src/test/java/com/yello/server/domain/authorization/medium/AuthControllerTest.java @@ -0,0 +1,295 @@ +package com.yello.server.domain.authorization.medium; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yello.server.domain.authorization.controller.AuthController; +import com.yello.server.domain.authorization.dto.ServiceTokenVO; +import com.yello.server.domain.authorization.dto.request.OAuthRequest; +import com.yello.server.domain.authorization.dto.request.OnBoardingFriendRequest; +import com.yello.server.domain.authorization.dto.request.SignUpRequest; +import com.yello.server.domain.authorization.dto.response.DepartmentSearchResponse; +import com.yello.server.domain.authorization.dto.response.GroupNameSearchResponse; +import com.yello.server.domain.authorization.dto.response.OAuthResponse; +import com.yello.server.domain.authorization.dto.response.OnBoardingFriendResponse; +import com.yello.server.domain.authorization.dto.response.SignUpResponse; +import com.yello.server.domain.authorization.filter.JwtExceptionFilter; +import com.yello.server.domain.authorization.filter.JwtFilter; +import com.yello.server.domain.authorization.service.AuthService; +import com.yello.server.domain.user.entity.Gender; +import com.yello.server.domain.user.entity.Social; +import com.yello.server.domain.user.entity.User; +import com.yello.server.global.exception.ControllerExceptionAdvice; +import com.yello.server.util.TestDataEntityUtil; +import com.yello.server.util.TestDataUtil; +import com.yello.server.util.WithAccessTokenUser; +import java.util.Arrays; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +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.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.data.domain.Pageable; +import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.operation.preprocess.Preprocessors; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@AutoConfigureRestDocs +@WebMvcTest( + controllers = AuthController.class, + excludeFilters = { + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtExceptionFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ControllerExceptionAdvice.class) + }) +@WithAccessTokenUser +@DisplayNameGeneration(ReplaceUnderscores.class) +@DisplayName("Auth ์ปจํŠธ๋กค๋Ÿฌ์—์„œ") +class AuthControllerTest { + + final String[] excludeRequestHeaders = {"X-CSRF-TOKEN", "Host"}; + final String[] excludeResponseHeaders = {"X-Content-Type-Options", "X-XSS-Protection", "Cache-Control", "Pragma", + "Expires", "X-Frame-Options", "Content-Length"}; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private AuthService authService; + + private TestDataUtil testDataUtil = new TestDataEntityUtil(); + private User user; + private User target; + + @BeforeEach + void init() { + user = testDataUtil.generateUser(1L, 1L); + target = testDataUtil.generateUser(2L, 1L); + } + + @Test + void ์†Œ์…œ_๋กœ๊ทธ์ธ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final OAuthRequest oAuthRequest = OAuthRequest.builder() + .accessToken("accessToken") + .deviceToken("deviceToken") + .social("social") + .build(); + + final ServiceTokenVO serviceTokenVO = ServiceTokenVO.of( + "serviceAccessToken", + "serviceRefreshToken" + ); + + final OAuthResponse oAuthResponse = OAuthResponse.of(false, serviceTokenVO); + + given(authService.oauthLogin(oAuthRequest)) + .willReturn(oAuthResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/auth/oauth") + .with(csrf().asHeader()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(oAuthRequest))) + .andDo(print()) + .andDo(document("api/v1/auth/oauthLogin", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ์˜๋กœ_์•„์ด๋””_์ค‘๋ณต_ํ™•์ธ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + given(authService.isYelloIdDuplicated(anyString())) + .willReturn(false); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/auth/valid") + .param("yelloId", "yelloId here")) + .andDo(print()) + .andDo(document("api/v1/auth/getYelloIdValidation", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + requestParameters(parameterWithName("yelloId").description("์ค‘๋ณต ์ฒดํฌํ•  yelloId"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ํšŒ์›_๊ฐ€์ž…์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final SignUpRequest signUpRequest = SignUpRequest.builder() + .social(Social.KAKAO) + .uuid("uuid") + .deviceToken("deviceToken") + .email("email@emall.com") + .profileImage("profileImage") + .groupId(1L) + .groupAdmissionYear(20) + .name("name") + .yelloId("yelloId") + .gender(Gender.MALE) + .friends(Arrays.asList(1L)) + .recommendId("recommendId") + .build(); + + final ServiceTokenVO serviceTokenVO = ServiceTokenVO.of( + "serviceAccessToken", + "serviceRefreshToken" + ); + + final SignUpResponse signUpResponse = SignUpResponse.of("yelloId", serviceTokenVO); + + given(authService.signUp(signUpRequest)) + .willReturn(signUpResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/auth/signup") + .with(csrf().asHeader()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(signUpRequest))) + .andDo(print()) + .andDo(document("api/v1/auth/postSignUp", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ๊ฐ€์ž…ํ•œ_์นœ๊ตฌ_๋ถˆ๋Ÿฌ์˜ค๊ธฐ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final OnBoardingFriendRequest onBoardingFriendRequest = OnBoardingFriendRequest.builder() + .friendKakaoId(Arrays.asList("friendKakaoId")) + .build(); + + final OnBoardingFriendResponse onBoardingFriendResponse = OnBoardingFriendResponse.of(0, Arrays.asList(user)); + + given(authService.findOnBoardingFriends(any(OnBoardingFriendRequest.class), any(Pageable.class))) + .willReturn(onBoardingFriendResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/auth/friend") + .with(csrf().asHeader()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(onBoardingFriendRequest)) + .param("page", "0")) + .andDo(print()) + .andDo(document("api/v1/auth/findOnBoardingFriends", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + requestParameters(parameterWithName("page").description("ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ๋Œ€ํ•™๊ต_์ด๋ฆ„_๊ฒ€์ƒ‰์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final GroupNameSearchResponse groupNameSearchResponse = GroupNameSearchResponse.of( + 0, + Arrays.asList("groupName") + ); + + given(authService.findSchoolsByKeyword(anyString(), any(Pageable.class))) + .willReturn(groupNameSearchResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/auth/school") + .param("page", "0") + .param("keyword", "keyword here") + ) + .andDo(print()) + .andDo(document("api/v1/auth/findSchoolsByKeyword", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + requestParameters( + parameterWithName("page").description("ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ"), + parameterWithName("keyword").description("๊ฒ€์ƒ‰ํ•  ์ฟผ๋ฆฌ"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ํ•™๊ณผ_์ด๋ฆ„_๊ฒ€์ƒ‰์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final DepartmentSearchResponse departmentSearchResponse = DepartmentSearchResponse.of( + 0, + Arrays.asList(testDataUtil.generateSchool(1L)) + ); + + given(authService.findDepartmentsByKeyword(anyString(), anyString(), any(Pageable.class))) + .willReturn(departmentSearchResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/auth/school/department") + .param("page", "0") + .param("school", "school name here") + .param("keyword", "keyword here") + ) + .andDo(print()) + .andDo(document("api/v1/auth/findDepartmentsByKeyword", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + requestParameters( + parameterWithName("page").description("ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ"), + parameterWithName("school").description("ํ•™๊ต ์ด๋ฆ„"), + parameterWithName("keyword").description("๊ฒ€์ƒ‰ํ•  ์ฟผ๋ฆฌ"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ํ† ํฐ_์žฌ๋ฐœ๊ธ‰์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final ServiceTokenVO serviceTokenVO = ServiceTokenVO.of( + "new accessToken", + "new refreshToken" + ); + + given(authService.reIssueToken(any(ServiceTokenVO.class))) + .willReturn(serviceTokenVO); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/auth/token/issue") + .with(csrf().asHeader()) + .header("X-ACCESS-AUTH", "Bearer your-access-token") + .header("X-REFRESH-AUTH", "Bearer your-refresh-token") + ) + .andDo(print()) + .andDo(document("api/v1/auth/reIssueToken", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } +} diff --git a/src/test/java/com/yello/server/small/domain/authorization/AuthManagerTest.java b/src/test/java/com/yello/server/domain/authorization/small/AuthManagerTest.java similarity index 85% rename from src/test/java/com/yello/server/small/domain/authorization/AuthManagerTest.java rename to src/test/java/com/yello/server/domain/authorization/small/AuthManagerTest.java index 7844df19..c8ac935c 100644 --- a/src/test/java/com/yello/server/small/domain/authorization/AuthManagerTest.java +++ b/src/test/java/com/yello/server/domain/authorization/small/AuthManagerTest.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.authorization; +package com.yello.server.domain.authorization.small; import static com.yello.server.global.common.ErrorCode.NOT_SIGNIN_USER_EXCEPTION; import static org.assertj.core.api.Assertions.assertThat; @@ -10,24 +10,29 @@ import com.yello.server.domain.authorization.service.AuthManagerImpl; import com.yello.server.domain.authorization.service.TokenJwtProvider; import com.yello.server.domain.authorization.service.TokenProvider; +import com.yello.server.domain.cooldown.FakeCooldownRepository; import com.yello.server.domain.cooldown.repository.CooldownRepository; +import com.yello.server.domain.friend.FakeFriendRepository; import com.yello.server.domain.friend.repository.FriendRepository; +import com.yello.server.domain.question.FakeQuestionRepository; import com.yello.server.domain.question.repository.QuestionRepository; +import com.yello.server.domain.user.FakeUserRepository; import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.repository.UserRepository; +import com.yello.server.domain.vote.FakeVoteRepository; import com.yello.server.domain.vote.repository.VoteRepository; +import com.yello.server.infrastructure.redis.FakeTokenRepository; import com.yello.server.infrastructure.redis.repository.TokenRepository; -import com.yello.server.small.domain.cooldown.FakeCooldownRepository; -import com.yello.server.small.domain.friend.FakeFriendRepository; -import com.yello.server.small.domain.question.FakeQuestionRepository; -import com.yello.server.small.domain.user.FakeUserRepository; -import com.yello.server.small.domain.vote.FakeVoteRepository; -import com.yello.server.small.global.redis.FakeTokenRepository; -import com.yello.server.util.TestDataUtil; +import com.yello.server.util.TestDataRepositoryUtil; import java.util.Base64; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; +@DisplayName("AuthManager ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) public class AuthManagerTest { private final String secretKey = Base64.getEncoder().encodeToString( @@ -40,7 +45,7 @@ public class AuthManagerTest { private final QuestionRepository questionRepository = new FakeQuestionRepository(); private final VoteRepository voteRepository = new FakeVoteRepository(); - private final TestDataUtil testDataUtil = new TestDataUtil( + private final TestDataRepositoryUtil testDataUtil = new TestDataRepositoryUtil( userRepository, voteRepository, questionRepository, diff --git a/src/test/java/com/yello/server/small/domain/authorization/AuthServiceTest.java b/src/test/java/com/yello/server/domain/authorization/small/AuthServiceTest.java similarity index 91% rename from src/test/java/com/yello/server/small/domain/authorization/AuthServiceTest.java rename to src/test/java/com/yello/server/domain/authorization/small/AuthServiceTest.java index cfc01289..e2425595 100644 --- a/src/test/java/com/yello/server/small/domain/authorization/AuthServiceTest.java +++ b/src/test/java/com/yello/server/domain/authorization/small/AuthServiceTest.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.authorization; +package com.yello.server.domain.authorization.small; import static com.yello.server.global.common.ErrorCode.GROUPID_NOT_FOUND_GROUP_EXCEPTION; import static com.yello.server.global.common.ErrorCode.UUID_CONFLICT_USER_EXCEPTION; @@ -7,6 +7,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.yello.server.domain.authorization.FakeAuthManager; +import com.yello.server.domain.authorization.FakeConnectionManager; import com.yello.server.domain.authorization.dto.request.OnBoardingFriendRequest; import com.yello.server.domain.authorization.dto.request.SignUpRequest; import com.yello.server.domain.authorization.dto.response.OnBoardingFriend; @@ -17,50 +19,55 @@ import com.yello.server.domain.authorization.service.AuthService; import com.yello.server.domain.authorization.service.TokenJwtProvider; import com.yello.server.domain.authorization.service.TokenProvider; +import com.yello.server.domain.cooldown.FakeCooldownRepository; import com.yello.server.domain.cooldown.entity.Cooldown; import com.yello.server.domain.cooldown.repository.CooldownRepository; +import com.yello.server.domain.friend.FakeFriendManager; +import com.yello.server.domain.friend.FakeFriendRepository; import com.yello.server.domain.friend.repository.FriendRepository; import com.yello.server.domain.friend.service.FriendManager; +import com.yello.server.domain.group.FakeSchoolRepository; import com.yello.server.domain.group.exception.GroupNotFoundException; import com.yello.server.domain.group.repository.SchoolRepository; +import com.yello.server.domain.question.FakeQuestionRepository; import com.yello.server.domain.question.repository.QuestionRepository; +import com.yello.server.domain.user.FakeUserManager; +import com.yello.server.domain.user.FakeUserRepository; import com.yello.server.domain.user.entity.Gender; import com.yello.server.domain.user.entity.Social; import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.exception.UserConflictException; import com.yello.server.domain.user.repository.UserRepository; import com.yello.server.domain.user.service.UserManager; +import com.yello.server.domain.vote.FakeVoteManager; +import com.yello.server.domain.vote.FakeVoteRepository; import com.yello.server.domain.vote.repository.VoteRepository; import com.yello.server.domain.vote.service.VoteManager; import com.yello.server.global.common.factory.PaginationFactory; import com.yello.server.global.common.manager.ConnectionManager; +import com.yello.server.infrastructure.firebase.FakeFcmManger; import com.yello.server.infrastructure.firebase.manager.FCMManager; import com.yello.server.infrastructure.firebase.service.NotificationFcmService; import com.yello.server.infrastructure.firebase.service.NotificationService; +import com.yello.server.infrastructure.rabbitmq.FakeMessageQueueRepository; import com.yello.server.infrastructure.rabbitmq.repository.MessageQueueRepository; +import com.yello.server.infrastructure.redis.FakeTokenRepository; import com.yello.server.infrastructure.redis.repository.TokenRepository; -import com.yello.server.small.domain.cooldown.FakeCooldownRepository; -import com.yello.server.small.domain.friend.FakeFriendManager; -import com.yello.server.small.domain.friend.FakeFriendRepository; -import com.yello.server.small.domain.group.FakeSchoolRepository; -import com.yello.server.small.domain.question.FakeQuestionRepository; -import com.yello.server.small.domain.user.FakeUserManager; -import com.yello.server.small.domain.user.FakeUserRepository; -import com.yello.server.small.domain.vote.FakeVoteManager; -import com.yello.server.small.domain.vote.FakeVoteRepository; -import com.yello.server.small.global.firebase.FakeFcmManger; -import com.yello.server.small.global.rabbitmq.FakeMessageQueueRepository; -import com.yello.server.small.global.redis.FakeTokenRepository; -import com.yello.server.util.TestDataUtil; +import com.yello.server.util.TestDataRepositoryUtil; import java.util.ArrayList; import java.util.Base64; import java.util.List; import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Pageable; +@DisplayName("AuthService ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) public class AuthServiceTest { private final String secretKey = Base64.getEncoder().encodeToString( @@ -75,7 +82,7 @@ public class AuthServiceTest { private final VoteRepository voteRepository = new FakeVoteRepository(); private final MessageQueueRepository messageQueueRepository = new FakeMessageQueueRepository(); - private final TestDataUtil testDataUtil = new TestDataUtil( + private final TestDataRepositoryUtil testDataUtil = new TestDataRepositoryUtil( userRepository, voteRepository, questionRepository, diff --git a/src/test/java/com/yello/server/small/domain/cooldown/FakeCooldownRepository.java b/src/test/java/com/yello/server/domain/cooldown/FakeCooldownRepository.java similarity index 96% rename from src/test/java/com/yello/server/small/domain/cooldown/FakeCooldownRepository.java rename to src/test/java/com/yello/server/domain/cooldown/FakeCooldownRepository.java index 2060341e..24d62ca9 100644 --- a/src/test/java/com/yello/server/small/domain/cooldown/FakeCooldownRepository.java +++ b/src/test/java/com/yello/server/domain/cooldown/FakeCooldownRepository.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.cooldown; +package com.yello.server.domain.cooldown; import com.yello.server.domain.cooldown.entity.Cooldown; import com.yello.server.domain.cooldown.repository.CooldownRepository; diff --git a/src/test/java/com/yello/server/small/domain/friend/FakeFriendManager.java b/src/test/java/com/yello/server/domain/friend/FakeFriendManager.java similarity index 95% rename from src/test/java/com/yello/server/small/domain/friend/FakeFriendManager.java rename to src/test/java/com/yello/server/domain/friend/FakeFriendManager.java index dada4dd2..912532e8 100644 --- a/src/test/java/com/yello/server/small/domain/friend/FakeFriendManager.java +++ b/src/test/java/com/yello/server/domain/friend/FakeFriendManager.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.friend; +package com.yello.server.domain.friend; import com.yello.server.domain.friend.service.FriendManager; import com.yello.server.domain.user.entity.User; diff --git a/src/test/java/com/yello/server/small/domain/friend/FakeFriendRepository.java b/src/test/java/com/yello/server/domain/friend/FakeFriendRepository.java similarity index 89% rename from src/test/java/com/yello/server/small/domain/friend/FakeFriendRepository.java rename to src/test/java/com/yello/server/domain/friend/FakeFriendRepository.java index dfac562b..ec14dd32 100644 --- a/src/test/java/com/yello/server/small/domain/friend/FakeFriendRepository.java +++ b/src/test/java/com/yello/server/domain/friend/FakeFriendRepository.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.friend; +package com.yello.server.domain.friend; import static com.yello.server.global.common.ErrorCode.NOT_FOUND_FRIEND_EXCEPTION; @@ -19,12 +19,12 @@ public class FakeFriendRepository implements FriendRepository { @Override public Friend save(Friend friend) { - if (friend.getId() != null && friend.getId() > id) { + if (friend.getId()!=null && friend.getId() > id) { id = friend.getId(); } Friend newFriend = Friend.builder() - .id(friend.getId() == null ? ++id : friend.getId()) + .id(friend.getId()==null ? ++id : friend.getId()) .user(friend.getUser()) .target(friend.getTarget()) .deletedAt(null) @@ -43,7 +43,7 @@ public void delete(Friend friend) { public Integer countAllByUserId(Long userId) { return data.stream() .filter( - friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt() == null) + friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt()==null) .toList() .size(); } @@ -53,7 +53,7 @@ public Optional findByUserAndTarget(Long userId, Long targetId) { return data.stream() .filter(friend -> friend.getUser().getId().equals(userId) && friend.getTarget().getId() .equals(targetId) - && friend.getDeletedAt() == null) + && friend.getDeletedAt()==null) .findFirst(); } @@ -70,7 +70,7 @@ public Friend getByUserAndTarget(Long userId, Long targetId) { return data.stream() .filter(friend -> friend.getUser().getId().equals(userId) && friend.getTarget().getId().equals(targetId) - && friend.getDeletedAt() == null) + && friend.getDeletedAt()==null) .findFirst() .orElseThrow(() -> new FriendNotFoundException(NOT_FOUND_FRIEND_EXCEPTION)); } @@ -80,14 +80,14 @@ public boolean existsByUserAndTarget(Long userId, Long targetId) { return data.stream() .anyMatch(friend -> friend.getUser().getId().equals(userId) && friend.getTarget().getId().equals(targetId) - && friend.getDeletedAt() == null); + && friend.getDeletedAt()==null); } @Override public Page findAllFriendsByUserId(Pageable pageable, Long userId) { final List friends = data.stream() .filter( - friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt() == null) + friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt()==null) .toList(); final int start = (int) pageable.getOffset(); @@ -99,7 +99,7 @@ public Page findAllFriendsByUserId(Pageable pageable, Long userId) { public List findAllByUserId(Long userId) { return data.stream() .filter( - friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt() == null) + friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt()==null) .toList(); } @@ -108,7 +108,7 @@ public List findAllByTargetId(Long targetId) { return data.stream() .filter( friend -> friend.getTarget().getId().equals(targetId) - && friend.getDeletedAt() == null) + && friend.getDeletedAt()==null) .toList(); } diff --git a/src/test/java/com/yello/server/domain/friend/medium/FriendControllerTest.java b/src/test/java/com/yello/server/domain/friend/medium/FriendControllerTest.java new file mode 100644 index 00000000..998f0c75 --- /dev/null +++ b/src/test/java/com/yello/server/domain/friend/medium/FriendControllerTest.java @@ -0,0 +1,267 @@ +package com.yello.server.domain.friend.medium; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doNothing; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yello.server.domain.authorization.filter.JwtExceptionFilter; +import com.yello.server.domain.authorization.filter.JwtFilter; +import com.yello.server.domain.friend.controller.FriendController; +import com.yello.server.domain.friend.dto.request.KakaoRecommendRequest; +import com.yello.server.domain.friend.dto.response.FriendResponse; +import com.yello.server.domain.friend.dto.response.FriendShuffleResponse; +import com.yello.server.domain.friend.dto.response.FriendsResponse; +import com.yello.server.domain.friend.dto.response.RecommendFriendResponse; +import com.yello.server.domain.friend.dto.response.SearchFriendResponse; +import com.yello.server.domain.friend.dto.response.SearchFriendVO; +import com.yello.server.domain.friend.entity.Friend; +import com.yello.server.domain.friend.service.FriendService; +import com.yello.server.domain.user.dto.response.UserResponse; +import com.yello.server.domain.user.entity.User; +import com.yello.server.global.exception.ControllerExceptionAdvice; +import com.yello.server.infrastructure.firebase.service.NotificationService; +import com.yello.server.util.TestDataEntityUtil; +import com.yello.server.util.TestDataUtil; +import com.yello.server.util.WithAccessTokenUser; +import java.util.Arrays; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +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.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.operation.preprocess.Preprocessors; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@WebMvcTest( + controllers = FriendController.class, + excludeFilters = { + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtExceptionFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ControllerExceptionAdvice.class) + }) +@AutoConfigureRestDocs +@WithAccessTokenUser +@DisplayName("FriendController ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) +class FriendControllerTest { + + final String[] excludeRequestHeaders = {"X-CSRF-TOKEN", "Host"}; + final String[] excludeResponseHeaders = {"X-Content-Type-Options", "X-XSS-Protection", "Cache-Control", "Pragma", + "Expires", "X-Frame-Options", "Content-Length"}; + + @Autowired + protected ObjectMapper objectMapper; + + @Autowired + protected MockMvc mockMvc; + + @MockBean + private FriendService friendService; + + @MockBean + private NotificationService notificationService; + + private TestDataUtil testDataUtil = new TestDataEntityUtil(); + private User user; + private User target; + + @BeforeEach + void init() { + user = testDataUtil.generateUser(1L, 1L); + target = testDataUtil.generateUser(2L, 1L); + } + + @Test + void ์นœ๊ตฌ_์ถ”๊ฐ€์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + given(friendService.addFriend(anyLong(), anyLong())) + .willReturn(null); + + doNothing() + .when(notificationService) + .sendFriendNotification(any(Friend.class)); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/friend/{targetId}", 1) + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token")) + .andDo(print()) + .andDo(document("api/v1/friend/addFriend", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + pathParameters(parameterWithName("targetId").description("์นœ๊ตฌ ์‹ ์ฒญํ•  ์ƒ๋Œ€ ์œ ์ €์˜ ์•„์ด๋”” ๊ฐ’"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ๋‚ด_์นœ๊ตฌ_์ „์ฒด_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final UserResponse userResponse = UserResponse.of(user, 0, 0); + final FriendsResponse friendsResponse = FriendsResponse.of(0L, Arrays.asList(userResponse)); + + given(friendService.findAllFriends(any(Pageable.class), anyLong())) + .willReturn(friendsResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/friend") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .param("page", "0")) + .andDo(print()) + .andDo(document("api/v1/friend/findAllFriend", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + requestParameters(parameterWithName("page").description("ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ์นœ๊ตฌ_ํˆฌํ‘œ_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Friend friend = testDataUtil.generateFriend(user, target); + final FriendShuffleResponse friendShuffleResponse = FriendShuffleResponse.of(friend); + + given(friendService.findShuffledFriend(anyLong())) + .willReturn(Arrays.asList(friendShuffleResponse)); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/friend/shuffle") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token")) + .andDo(print()) + .andDo(document("api/v1/friend/findShuffledFriend", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ๊ทธ๋ฃน_์ถ”์ฒœ_์นœ๊ตฌ_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final FriendResponse friendResponse = FriendResponse.of(user); + final RecommendFriendResponse recommendFriendResponse = RecommendFriendResponse.of(0, + Arrays.asList(friendResponse)); + + given(friendService.findAllRecommendSchoolFriends(any(Pageable.class), anyLong())) + .willReturn(recommendFriendResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/friend/recommend/school") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .param("page", "0")) + .andDo(print()) + .andDo(document("api/v1/friend/findAllRecommendSchoolFriends", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + requestParameters(parameterWithName("page").description("ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ์นด์นด์˜ค_์ถ”์ฒœ_์นœ๊ตฌ_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final KakaoRecommendRequest kakaoRecommendRequest = KakaoRecommendRequest.builder() + .friendKakaoId(new String[]{"testKakaoId"}) + .build(); + final FriendResponse friendResponse = FriendResponse.of(user); + final RecommendFriendResponse recommendFriendResponse = RecommendFriendResponse.of(0, + Arrays.asList(friendResponse)); + + given(friendService.findAllRecommendKakaoFriends(any(Pageable.class), anyLong(), eq(kakaoRecommendRequest))) + .willReturn(recommendFriendResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/friend/recommend/kakao") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(kakaoRecommendRequest)) + .param("page", "0")) + .andDo(print()) + .andDo(document("api/v1/friend/findAllRecommendKakaoFriends", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + requestParameters(parameterWithName("page").description("ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ์นœ๊ตฌ_์‚ญ์ œ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + doNothing() + .when(friendService) + .deleteFriend(anyLong(), anyLong()); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.delete("/api/v1/friend/{targetId}", 1) + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + ) + .andDo(print()) + .andDo(document("api/v1/friend/deleteFriend", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + pathParameters(parameterWithName("targetId").description("์‚ญ์ œํ•  ์ƒ๋Œ€ ์œ ์ €์˜ ์•„์ด๋”” ๊ฐ’"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ์นœ๊ตฌ_๊ฒ€์ƒ‰์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final SearchFriendVO searchFriendVO = SearchFriendVO.of(user, false); + final SearchFriendResponse searchFriendResponse = SearchFriendResponse.of(0, Arrays.asList(searchFriendVO)); + + given(friendService.searchFriend(anyLong(), any(Pageable.class), anyString())) + .willReturn(searchFriendResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/friend/search") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .param("page", "0") + .param("keyword", "keyword here") + ) + .andDo(print()) + .andDo(document("api/v1/friend/searchFriend", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + requestParameters( + parameterWithName("page").description("ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ"), + parameterWithName("keyword").description("๊ฒ€์ƒ‰ํ•  ์ฟผ๋ฆฌ"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } +} diff --git a/src/test/java/com/yello/server/small/domain/friend/FriendManagerTest.java b/src/test/java/com/yello/server/domain/friend/small/FriendManagerTest.java similarity index 87% rename from src/test/java/com/yello/server/small/domain/friend/FriendManagerTest.java rename to src/test/java/com/yello/server/domain/friend/small/FriendManagerTest.java index 92d2b971..c6ee375c 100644 --- a/src/test/java/com/yello/server/small/domain/friend/FriendManagerTest.java +++ b/src/test/java/com/yello/server/domain/friend/small/FriendManagerTest.java @@ -1,20 +1,25 @@ -package com.yello.server.small.domain.friend; +package com.yello.server.domain.friend.small; import static org.assertj.core.api.Assertions.assertThat; import com.yello.server.domain.friend.service.FriendManager; import com.yello.server.domain.friend.service.FriendManagerImpl; import com.yello.server.domain.group.entity.School; +import com.yello.server.domain.user.FakeUserRepository; import com.yello.server.domain.user.entity.Gender; import com.yello.server.domain.user.entity.Social; import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.repository.UserRepository; -import com.yello.server.small.domain.user.FakeUserRepository; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; +@DisplayName("FriendManager ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) public class FriendManagerTest { private final UserRepository userRepository = new FakeUserRepository(); diff --git a/src/test/java/com/yello/server/small/domain/friend/FriendServiceTest.java b/src/test/java/com/yello/server/domain/friend/small/FriendServiceTest.java similarity index 93% rename from src/test/java/com/yello/server/small/domain/friend/FriendServiceTest.java rename to src/test/java/com/yello/server/domain/friend/small/FriendServiceTest.java index d5ed5251..3378e964 100644 --- a/src/test/java/com/yello/server/small/domain/friend/FriendServiceTest.java +++ b/src/test/java/com/yello/server/domain/friend/small/FriendServiceTest.java @@ -1,10 +1,11 @@ -package com.yello.server.small.domain.friend; +package com.yello.server.domain.friend.small; import static com.yello.server.global.common.factory.PaginationFactory.createPageable; import static com.yello.server.global.common.factory.PaginationFactory.createPageableLimitTen; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.yello.server.domain.friend.FakeFriendRepository; import com.yello.server.domain.friend.dto.request.KakaoRecommendRequest; import com.yello.server.domain.friend.dto.response.FriendShuffleResponse; import com.yello.server.domain.friend.dto.response.FriendsResponse; @@ -15,29 +16,33 @@ import com.yello.server.domain.friend.exception.FriendNotFoundException; import com.yello.server.domain.friend.repository.FriendRepository; import com.yello.server.domain.friend.service.FriendService; +import com.yello.server.domain.question.FakeQuestionRepository; import com.yello.server.domain.question.repository.QuestionRepository; +import com.yello.server.domain.user.FakeUserRepository; import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.exception.UserNotFoundException; import com.yello.server.domain.user.repository.UserRepository; +import com.yello.server.domain.vote.FakeVoteRepository; import com.yello.server.domain.vote.repository.VoteRepository; -import com.yello.server.small.domain.question.FakeQuestionRepository; -import com.yello.server.small.domain.user.FakeUserRepository; -import com.yello.server.small.domain.vote.FakeVoteRepository; -import com.yello.server.util.TestDataUtil; +import com.yello.server.util.TestDataRepositoryUtil; import java.util.List; import java.util.Optional; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Pageable; +@DisplayName("FriendService ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) class FriendServiceTest { - private final UserRepository userRepository = new FakeUserRepository(); private final FriendRepository friendRepository = new FakeFriendRepository(); private final VoteRepository voteRepository = new FakeVoteRepository(); private final QuestionRepository questionRepository = new FakeQuestionRepository(); - private final TestDataUtil testDataUtil = new TestDataUtil( + private final TestDataRepositoryUtil testDataUtil = new TestDataRepositoryUtil( userRepository, voteRepository, questionRepository, diff --git a/src/test/java/com/yello/server/small/domain/group/FakeSchoolRepository.java b/src/test/java/com/yello/server/domain/group/FakeSchoolRepository.java similarity index 97% rename from src/test/java/com/yello/server/small/domain/group/FakeSchoolRepository.java rename to src/test/java/com/yello/server/domain/group/FakeSchoolRepository.java index e4cb1c71..d1c3cbbc 100644 --- a/src/test/java/com/yello/server/small/domain/group/FakeSchoolRepository.java +++ b/src/test/java/com/yello/server/domain/group/FakeSchoolRepository.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.group; +package com.yello.server.domain.group; import static com.yello.server.global.common.ErrorCode.GROUPID_NOT_FOUND_GROUP_EXCEPTION; diff --git a/src/test/java/com/yello/server/small/domain/keyword/FakeKeywordRepository.java b/src/test/java/com/yello/server/domain/keyword/FakeKeywordRepository.java similarity index 94% rename from src/test/java/com/yello/server/small/domain/keyword/FakeKeywordRepository.java rename to src/test/java/com/yello/server/domain/keyword/FakeKeywordRepository.java index 26cc4a49..a9c3640b 100644 --- a/src/test/java/com/yello/server/small/domain/keyword/FakeKeywordRepository.java +++ b/src/test/java/com/yello/server/domain/keyword/FakeKeywordRepository.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.keyword; +package com.yello.server.domain.keyword; import com.yello.server.domain.keyword.entity.Keyword; import com.yello.server.domain.keyword.repository.KeywordRepository; diff --git a/src/test/java/com/yello/server/domain/pay/medium/PayControllerTest.java b/src/test/java/com/yello/server/domain/pay/medium/PayControllerTest.java new file mode 100644 index 00000000..bdbb1b15 --- /dev/null +++ b/src/test/java/com/yello/server/domain/pay/medium/PayControllerTest.java @@ -0,0 +1,89 @@ +package com.yello.server.domain.pay.medium; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yello.server.domain.authorization.filter.JwtExceptionFilter; +import com.yello.server.domain.authorization.filter.JwtFilter; +import com.yello.server.domain.pay.controller.PayController; +import com.yello.server.domain.pay.dto.request.PayCountRequest; +import com.yello.server.domain.pay.service.PayService; +import com.yello.server.global.exception.ControllerExceptionAdvice; +import com.yello.server.util.WithAccessTokenUser; +import org.junit.jupiter.api.DisplayName; +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.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.operation.preprocess.Preprocessors; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@AutoConfigureRestDocs +@WebMvcTest( + controllers = PayController.class, + excludeFilters = { + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtExceptionFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ControllerExceptionAdvice.class) + }) +@WithAccessTokenUser +@DisplayNameGeneration(ReplaceUnderscores.class) +@DisplayName("Pay ์ปจํŠธ๋กค๋Ÿฌ์—์„œ") +class PayControllerTest { + + final String[] excludeRequestHeaders = {"X-CSRF-TOKEN", "Host"}; + final String[] excludeResponseHeaders = {"X-Content-Type-Options", "X-XSS-Protection", "Cache-Control", "Pragma", + "Expires", "X-Frame-Options", "Content-Length"}; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private PayService payService; + + @Test + void ๊ฒฐ์ œ_์ „ํ™˜์œจ_์ฒดํฌ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final PayCountRequest request = PayCountRequest.builder() + .index(1) + .build(); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/pay") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andDo(print()) + .andDo(document("api/v1/pay/postPayCount", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + + verify(payService, times(1)) + .postPayCount(anyLong(), anyInt()); + } + +} diff --git a/src/test/java/com/yello/server/small/domain/purchase/FakePurchaseRepository.java b/src/test/java/com/yello/server/domain/purchase/FakePurchaseRepository.java similarity index 92% rename from src/test/java/com/yello/server/small/domain/purchase/FakePurchaseRepository.java rename to src/test/java/com/yello/server/domain/purchase/FakePurchaseRepository.java index 7a571aa3..4fe49ea4 100644 --- a/src/test/java/com/yello/server/small/domain/purchase/FakePurchaseRepository.java +++ b/src/test/java/com/yello/server/domain/purchase/FakePurchaseRepository.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.purchase; +package com.yello.server.domain.purchase; import com.yello.server.domain.purchase.entity.ProductType; import com.yello.server.domain.purchase.entity.Purchase; @@ -18,12 +18,12 @@ public class FakePurchaseRepository implements PurchaseRepository { @Override public Purchase save(Purchase purchase) { - if (purchase.getId() != null && purchase.getId() > id) { + if (purchase.getId()!=null && purchase.getId() > id) { id = purchase.getId(); } final Purchase newPurchase = Purchase.builder() - .id(purchase.getId() == null ? ++id : purchase.getId()) + .id(purchase.getId()==null ? ++id : purchase.getId()) .price(purchase.getPrice()) .user(purchase.getUser()) .gateway(purchase.getGateway()) diff --git a/src/test/java/com/yello/server/domain/purchase/medium/PurchaseControllerTest.java b/src/test/java/com/yello/server/domain/purchase/medium/PurchaseControllerTest.java new file mode 100644 index 00000000..8e7ab3dc --- /dev/null +++ b/src/test/java/com/yello/server/domain/purchase/medium/PurchaseControllerTest.java @@ -0,0 +1,269 @@ +package com.yello.server.domain.purchase.medium; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yello.server.domain.authorization.filter.JwtExceptionFilter; +import com.yello.server.domain.authorization.filter.JwtFilter; +import com.yello.server.domain.purchase.controller.PurchaseController; +import com.yello.server.domain.purchase.dto.apple.AppleTransaction; +import com.yello.server.domain.purchase.dto.request.AppleInAppRefundRequest; +import com.yello.server.domain.purchase.dto.request.GoogleSubscriptionGetRequest; +import com.yello.server.domain.purchase.dto.request.GoogleTicketGetRequest; +import com.yello.server.domain.purchase.dto.response.GoogleSubscriptionGetResponse; +import com.yello.server.domain.purchase.dto.response.GoogleTicketGetResponse; +import com.yello.server.domain.purchase.dto.response.UserSubscribeNeededResponse; +import com.yello.server.domain.purchase.service.PurchaseService; +import com.yello.server.domain.user.entity.User; +import com.yello.server.global.exception.ControllerExceptionAdvice; +import com.yello.server.util.TestDataEntityUtil; +import com.yello.server.util.TestDataUtil; +import com.yello.server.util.WithAccessTokenUser; +import java.time.LocalDateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +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.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.operation.preprocess.Preprocessors; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@AutoConfigureRestDocs +@WebMvcTest( + controllers = PurchaseController.class, + excludeFilters = { + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtExceptionFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ControllerExceptionAdvice.class) + }) +@WithAccessTokenUser +@DisplayNameGeneration(ReplaceUnderscores.class) +@DisplayName("Purchase ์ปจํŠธ๋กค๋Ÿฌ์—์„œ") +class PurchaseControllerTest { + + final String[] excludeRequestHeaders = {"X-CSRF-TOKEN", "Host"}; + final String[] excludeResponseHeaders = {"X-Content-Type-Options", "X-XSS-Protection", "Cache-Control", "Pragma", + "Expires", "X-Frame-Options", "Content-Length"}; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private PurchaseService purchaseService; + + private TestDataUtil testDataUtil = new TestDataEntityUtil(); + private User user; + private User target; + + @BeforeEach + void init() { + user = testDataUtil.generateUser(1L, 1L); + target = testDataUtil.generateUser(2L, 1L); + } + + @Test + void Apple_๊ตฌ๋…_๊ตฌ๋งค_๊ฒ€์ฆ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final AppleTransaction appleTransaction = AppleTransaction.builder() + .transactionId("transactionId") + .productId("productId") + .build(); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/purchase/apple/verify/subscribe") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(appleTransaction))) + .andDo(print()) + .andDo(document("api/v1/purchase/verifyAppleSubscriptionTransaction", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + + verify(purchaseService, times(1)) + .verifyAppleSubscriptionTransaction(anyLong(), any(AppleTransaction.class)); + } + + @Test + void Apple_์—ด๋žŒ๊ถŒ_๊ตฌ๋งค_๊ฒ€์ฆ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final AppleTransaction appleTransaction = AppleTransaction.builder() + .transactionId("transactionId") + .productId("productId") + .build(); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/purchase/apple/verify/ticket") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(appleTransaction))) + .andDo(print()) + .andDo(document("api/v1/purchase/verifyAppleTicketTransaction", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + + verify(purchaseService, times(1)) + .verifyAppleTicketTransaction(anyLong(), any(AppleTransaction.class)); + } + + @Test + void Google_๊ตฌ๋…_๊ตฌ๋งค_๊ฒ€์ฆ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final GoogleSubscriptionGetRequest googleSubscriptionGetRequest = GoogleSubscriptionGetRequest.builder() + .orderId("orderId") + .packageName("packageName") + .productId("productId") + .purchaseTime(1L) + .purchaseState(1) + .purchaseToken("purchaseToken") + .quantity(1) + .autoRenewing(true) + .acknowledged(true) + .build(); + + final GoogleSubscriptionGetResponse response = GoogleSubscriptionGetResponse.of( + "productId"); + + given(purchaseService.verifyGoogleSubscriptionTransaction(anyLong(), any(GoogleSubscriptionGetRequest.class))) + .willReturn(response); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/purchase/google/verify/subscribe") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(googleSubscriptionGetRequest))) + .andDo(print()) + .andDo(document("api/v1/purchase/verifyGoogleSubscriptionTransaction", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void Google_์—ด๋žŒ๊ถŒ_๊ตฌ๋งค_๊ฒ€์ฆ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final GoogleTicketGetRequest googleTicketGetRequest = GoogleTicketGetRequest.builder() + .orderId("orderId") + .packageName("packageName") + .productId("productId") + .purchaseTime(1L) + .purchaseState(1) + .purchaseToken("purchaseToken") + .quantity(1) + .acknowledged(true) + .build(); + + final GoogleTicketGetResponse response = GoogleTicketGetResponse.of( + "productId", + user + ); + + given(purchaseService.verifyGoogleTicketTransaction(anyLong(), any(GoogleTicketGetRequest.class))) + .willReturn(response); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/purchase/google/verify/ticket") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(googleTicketGetRequest))) + .andDo(print()) + .andDo(document("api/v1/purchase/verifyGoogleTicketTransaction", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ๊ตฌ๋…_์—ฐ์žฅ_์œ ๋„_ํ•„์š”_์—ฌ๋ถ€_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final UserSubscribeNeededResponse response = UserSubscribeNeededResponse.of( + user, + false + ); + + given(purchaseService.getUserSubscribe(any(User.class), any(LocalDateTime.class))) + .willReturn(response); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/purchase/subscribe") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token")) + .andDo(print()) + .andDo(document("api/v1/purchase/getUserSubscribeNeeded", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void Apple_ํ™˜๋ถˆ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + doNothing() + .when(purchaseService) + .refundInAppApple(anyLong(), any(AppleInAppRefundRequest.class)); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.delete("/api/v1/purchase/apple/refund") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token")) + .andDo(print()) + .andDo(document("api/v1/purchase/refundInAppApple", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ๊ตฌ๋…_์ƒํƒœ_๋ฐ_๊ตฌ๋…๊ถŒ_๊ฐœ์ˆ˜_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/purchase") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token")) + .andDo(print()) + .andDo(document("api/v1/purchase/getUserPurchaseInfo", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } +} diff --git a/src/test/java/com/yello/server/small/domain/purchase/PurchaseServiceTest.java b/src/test/java/com/yello/server/domain/purchase/small/PurchaseServiceTest.java similarity index 86% rename from src/test/java/com/yello/server/small/domain/purchase/PurchaseServiceTest.java rename to src/test/java/com/yello/server/domain/purchase/small/PurchaseServiceTest.java index 300f645c..bd4dd3e9 100644 --- a/src/test/java/com/yello/server/small/domain/purchase/PurchaseServiceTest.java +++ b/src/test/java/com/yello/server/domain/purchase/small/PurchaseServiceTest.java @@ -1,24 +1,30 @@ -package com.yello.server.small.domain.purchase; +package com.yello.server.domain.purchase.small; import static org.assertj.core.api.Assertions.assertThat; import com.yello.server.domain.group.entity.School; +import com.yello.server.domain.purchase.FakePurchaseRepository; import com.yello.server.domain.purchase.dto.response.UserSubscribeNeededResponse; import com.yello.server.domain.purchase.entity.Gateway; import com.yello.server.domain.purchase.entity.ProductType; import com.yello.server.domain.purchase.entity.Purchase; import com.yello.server.domain.purchase.repository.PurchaseRepository; import com.yello.server.domain.purchase.service.PurchaseService; +import com.yello.server.domain.user.FakeUserRepository; import com.yello.server.domain.user.entity.Gender; import com.yello.server.domain.user.entity.Social; import com.yello.server.domain.user.entity.Subscribe; import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.repository.UserRepository; -import com.yello.server.small.domain.user.FakeUserRepository; import java.time.LocalDateTime; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; +@DisplayName("PurchaseService ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) public class PurchaseServiceTest { private final UserRepository userRepository = new FakeUserRepository(); diff --git a/src/test/java/com/yello/server/small/domain/question/FakeQuestionRepository.java b/src/test/java/com/yello/server/domain/question/FakeQuestionRepository.java similarity index 95% rename from src/test/java/com/yello/server/small/domain/question/FakeQuestionRepository.java rename to src/test/java/com/yello/server/domain/question/FakeQuestionRepository.java index 8a3942c3..da1ab169 100644 --- a/src/test/java/com/yello/server/small/domain/question/FakeQuestionRepository.java +++ b/src/test/java/com/yello/server/domain/question/FakeQuestionRepository.java @@ -1,13 +1,13 @@ -package com.yello.server.small.domain.question; +package com.yello.server.domain.question; import static com.yello.server.global.common.ErrorCode.NOT_FOUND_QUESTION_EXCEPTION; +import com.yello.server.domain.keyword.FakeKeywordRepository; import com.yello.server.domain.keyword.entity.Keyword; import com.yello.server.domain.keyword.repository.KeywordRepository; import com.yello.server.domain.question.entity.Question; import com.yello.server.domain.question.exception.QuestionNotFoundException; import com.yello.server.domain.question.repository.QuestionRepository; -import com.yello.server.small.domain.keyword.FakeKeywordRepository; import java.util.ArrayList; import java.util.List; import java.util.Objects; diff --git a/src/test/java/com/yello/server/small/domain/user/FakeUserManager.java b/src/test/java/com/yello/server/domain/user/FakeUserManager.java similarity index 97% rename from src/test/java/com/yello/server/small/domain/user/FakeUserManager.java rename to src/test/java/com/yello/server/domain/user/FakeUserManager.java index 44d671a0..98786e09 100644 --- a/src/test/java/com/yello/server/small/domain/user/FakeUserManager.java +++ b/src/test/java/com/yello/server/domain/user/FakeUserManager.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.user; +package com.yello.server.domain.user; import com.yello.server.domain.user.entity.Gender; import com.yello.server.domain.user.entity.Social; diff --git a/src/test/java/com/yello/server/small/domain/user/FakeUserRepository.java b/src/test/java/com/yello/server/domain/user/FakeUserRepository.java similarity index 91% rename from src/test/java/com/yello/server/small/domain/user/FakeUserRepository.java rename to src/test/java/com/yello/server/domain/user/FakeUserRepository.java index f9f88b1c..7c130a7c 100644 --- a/src/test/java/com/yello/server/small/domain/user/FakeUserRepository.java +++ b/src/test/java/com/yello/server/domain/user/FakeUserRepository.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.user; +package com.yello.server.domain.user; import static com.yello.server.global.common.ErrorCode.AUTH_UUID_NOT_FOUND_USER_EXCEPTION; import static com.yello.server.global.common.ErrorCode.USERID_NOT_FOUND_USER_EXCEPTION; @@ -18,12 +18,12 @@ public class FakeUserRepository implements UserRepository { @Override public User save(User user) { - if (user.getId()!=null && user.getId() > id) { + if (user.getId() != null && user.getId() > id) { id = user.getId(); } User newUser = User.builder() - .id(user.getId()==null ? ++id : user.getId()) + .id(user.getId() == null ? ++id : user.getId()) .recommendCount(0L) .name(user.getName()) .yelloId(user.getYelloId()) @@ -82,6 +82,14 @@ public boolean existsByUuid(String uuid) { @Override public Optional findByYelloId(String yelloId) { + return data.stream() + .filter(user -> user.getDeletedAt() == null) + .filter(user -> user.getYelloId().equals(yelloId)) + .findFirst(); + } + + @Override + public Optional findByYelloIdNotFiltered(String yelloId) { return data.stream() .filter(user -> user.getYelloId().equals(yelloId)) .findFirst(); diff --git a/src/test/java/com/yello/server/domain/user/medium/UserControllerTest.java b/src/test/java/com/yello/server/domain/user/medium/UserControllerTest.java new file mode 100644 index 00000000..6cda5faf --- /dev/null +++ b/src/test/java/com/yello/server/domain/user/medium/UserControllerTest.java @@ -0,0 +1,174 @@ +package com.yello.server.domain.user.medium; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yello.server.domain.authorization.filter.JwtExceptionFilter; +import com.yello.server.domain.authorization.filter.JwtFilter; +import com.yello.server.domain.user.controller.UserController; +import com.yello.server.domain.user.dto.request.UserDeviceTokenRequest; +import com.yello.server.domain.user.dto.response.UserDetailResponse; +import com.yello.server.domain.user.dto.response.UserResponse; +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.user.service.UserService; +import com.yello.server.global.common.dto.EmptyObject; +import com.yello.server.global.exception.ControllerExceptionAdvice; +import com.yello.server.util.WithAccessTokenUser; +import org.junit.jupiter.api.DisplayName; +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.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.operation.preprocess.Preprocessors; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@AutoConfigureRestDocs +@WebMvcTest( + controllers = UserController.class, + excludeFilters = { + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtExceptionFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ControllerExceptionAdvice.class) + }) +@WithAccessTokenUser +@DisplayNameGeneration(ReplaceUnderscores.class) +@DisplayName("User ์ปจํŠธ๋กค๋Ÿฌ์—์„œ") +class UserControllerTest { + + final String[] excludeRequestHeaders = {"X-CSRF-TOKEN", "Host"}; + final String[] excludeResponseHeaders = {"X-Content-Type-Options", "X-XSS-Protection", "Cache-Control", "Pragma", + "Expires", "X-Frame-Options", "Content-Length"}; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private UserService userService; + + @Test + void ๋‚ด_์ •๋ณด_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final UserDetailResponse userDetailResponse = UserDetailResponse.builder() + .userId(1L) + .name("test") + .group("group") + .profileImageUrl("profile") + .yelloId("yelloId") + .yelloCount(0) + .friendCount(0) + .point(200) + .build(); + + given(userService.findMyProfile(anyLong())) + .willReturn(userDetailResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/user") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + ) + .andDo(print()) + .andDo(document("api/v1/user/findUser", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ๋‹ค๋ฅธ_์œ ์ €_์ •๋ณด_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Long userId = 2L; + final UserResponse userResponse = UserResponse.builder() + .userId(userId) + .name("test") + .group("group") + .profileImageUrl("profile") + .yelloId("yelloId") + .yelloCount(0) + .friendCount(0) + .build(); + + given(userService.findUserById(anyLong())) + .willReturn(userResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/user/{userId}", userId) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + ) + .andDo(print()) + .andDo(document("api/v1/user/findUserById", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + pathParameters(parameterWithName("userId").description("์œ ์ € ์•„์ด๋”” ๊ฐ’"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ๋””๋ฐ”์ด์Šค_ํ† ํฐ_์ˆ˜์ •์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final EmptyObject emptyObject = EmptyObject.builder().build(); + final UserDeviceTokenRequest userDeviceTokenRequest = UserDeviceTokenRequest.builder() + .deviceToken("testDeviceToken") + .build(); + + given(userService.updateUserDeviceToken(any(User.class), eq(userDeviceTokenRequest))) + .willReturn(emptyObject); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.put("/api/v1/user/device") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(userDeviceTokenRequest))) + .andDo(print()) + .andDo(document("api/v1/user/updateUserDeviceToken", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ์œ ์ €_ํƒˆํ‡ด์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.delete("/api/v1/user") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + ) + .andDo(print()) + .andDo(document("api/v1/user/deleteUser", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + +} diff --git a/src/test/java/com/yello/server/small/domain/user/UserManagerTest.java b/src/test/java/com/yello/server/domain/user/small/UserManagerTest.java similarity index 90% rename from src/test/java/com/yello/server/small/domain/user/UserManagerTest.java rename to src/test/java/com/yello/server/domain/user/small/UserManagerTest.java index 399be9f5..34dc4a15 100644 --- a/src/test/java/com/yello/server/small/domain/user/UserManagerTest.java +++ b/src/test/java/com/yello/server/domain/user/small/UserManagerTest.java @@ -1,8 +1,9 @@ -package com.yello.server.small.domain.user; +package com.yello.server.domain.user.small; import static org.assertj.core.api.Assertions.assertThat; import com.yello.server.domain.group.entity.School; +import com.yello.server.domain.user.FakeUserRepository; import com.yello.server.domain.user.entity.Gender; import com.yello.server.domain.user.entity.Social; import com.yello.server.domain.user.entity.User; @@ -10,8 +11,13 @@ import com.yello.server.domain.user.service.UserManager; import com.yello.server.domain.user.service.UserManagerImpl; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; +@DisplayName("UserManager ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) public class UserManagerTest { private final static String OFFICIAL_NAME = "์˜๋กœํŒ€"; diff --git a/src/test/java/com/yello/server/domain/user/small/UserRepositoryTest.java b/src/test/java/com/yello/server/domain/user/small/UserRepositoryTest.java new file mode 100644 index 00000000..98f544d4 --- /dev/null +++ b/src/test/java/com/yello/server/domain/user/small/UserRepositoryTest.java @@ -0,0 +1,146 @@ +package com.yello.server.domain.user.small; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; + +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.user.repository.UserJpaRepository; +import com.yello.server.domain.user.repository.UserRepositoryImpl; +import com.yello.server.util.TestDataEntityUtil; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +@DisplayName("UserRepository ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) +public class UserRepositoryTest { + + + private final TestDataEntityUtil testDataEntityUtil = new TestDataEntityUtil(); + + @Mock + private UserJpaRepository userJpaRepository; + + @InjectMocks + private UserRepositoryImpl userRepository; + + @BeforeEach + public void init() { + MockitoAnnotations.initMocks(this); + } + + @Test + void save์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + final User user = testDataEntityUtil.generateUser(1L, 1L); + + // when + given(userRepository.save(any(User.class))) + .willReturn(user); + + User newUser = userRepository.save(user); + + // then + assertThat(newUser.getId()).isEqualTo(user.getId()); + } + + @Test + void findById์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void getById์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void findByUuid์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void getByUuid์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void existsByUuid์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void findByYelloId์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void getByYelloId์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void findByDeviceToken์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void findAllByGroupId์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void findAllByGroupContainingName์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void findAllByOtherGroupContainingName์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void findAllByGroupContainingYelloId์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } + + @Test + void findAllByOtherGroupContainingYelloId์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + } +} diff --git a/src/test/java/com/yello/server/small/domain/user/UserServiceTest.java b/src/test/java/com/yello/server/domain/user/small/UserServiceTest.java similarity index 81% rename from src/test/java/com/yello/server/small/domain/user/UserServiceTest.java rename to src/test/java/com/yello/server/domain/user/small/UserServiceTest.java index ba57057f..b8f0a90a 100644 --- a/src/test/java/com/yello/server/small/domain/user/UserServiceTest.java +++ b/src/test/java/com/yello/server/domain/user/small/UserServiceTest.java @@ -1,29 +1,35 @@ -package com.yello.server.small.domain.user; +package com.yello.server.domain.user.small; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.yello.server.domain.cooldown.FakeCooldownRepository; import com.yello.server.domain.cooldown.repository.CooldownRepository; +import com.yello.server.domain.friend.FakeFriendRepository; import com.yello.server.domain.friend.repository.FriendRepository; +import com.yello.server.domain.question.FakeQuestionRepository; import com.yello.server.domain.question.repository.QuestionRepository; +import com.yello.server.domain.user.FakeUserRepository; import com.yello.server.domain.user.dto.response.UserDetailResponse; import com.yello.server.domain.user.dto.response.UserResponse; import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.exception.UserNotFoundException; import com.yello.server.domain.user.repository.UserRepository; import com.yello.server.domain.user.service.UserService; +import com.yello.server.domain.vote.FakeVoteRepository; import com.yello.server.domain.vote.repository.VoteRepository; +import com.yello.server.infrastructure.redis.FakeTokenRepository; import com.yello.server.infrastructure.redis.repository.TokenRepository; -import com.yello.server.small.domain.cooldown.FakeCooldownRepository; -import com.yello.server.small.domain.friend.FakeFriendRepository; -import com.yello.server.small.domain.question.FakeQuestionRepository; -import com.yello.server.small.domain.vote.FakeVoteRepository; -import com.yello.server.small.global.redis.FakeTokenRepository; -import com.yello.server.util.TestDataUtil; +import com.yello.server.util.TestDataRepositoryUtil; import java.time.LocalDateTime; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; +@DisplayName("UserService ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) class UserServiceTest { private final UserRepository userRepository = new FakeUserRepository(); @@ -32,7 +38,7 @@ class UserServiceTest { private final CooldownRepository cooldownRepository = new FakeCooldownRepository(); private final TokenRepository tokenRepository = new FakeTokenRepository(); private final QuestionRepository questionRepository = new FakeQuestionRepository(); - private final TestDataUtil testDataUtil = new TestDataUtil( + private final TestDataRepositoryUtil testDataUtil = new TestDataRepositoryUtil( userRepository, voteRepository, questionRepository, diff --git a/src/test/java/com/yello/server/domain/user/small/UserTest.java b/src/test/java/com/yello/server/domain/user/small/UserTest.java new file mode 100644 index 00000000..e58eeff1 --- /dev/null +++ b/src/test/java/com/yello/server/domain/user/small/UserTest.java @@ -0,0 +1,146 @@ +package com.yello.server.domain.user.small; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.yello.server.domain.user.entity.Subscribe; +import com.yello.server.domain.user.entity.User; +import com.yello.server.util.TestDataEntityUtil; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; + +@DisplayName("User ์—”ํ‹ฐํ‹ฐ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) +public class UserTest { + + private final TestDataEntityUtil testDataEntityUtil = new TestDataEntityUtil(); + + private User user; + private User deletedUser; + + @BeforeEach + void init() { + user = testDataEntityUtil.generateUser(1L, 1L); + deletedUser = testDataEntityUtil.generateDeletedUser(2L, 1L); + } + + @Test + void ์‚ญ์ œ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + assertThat(user.getDeletedAt()).isNull(); + + // when + user.delete(); + + // then + assertThat(user.getDeletedAt()).isNotNull(); + assertThat(user.getPoint()).isZero(); + assertThat(user.getDeviceToken()).isNull(); + } + + @Test + void ์žฌ๊ฐ€์ž…์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + assertThat(deletedUser.getDeletedAt()).isNotNull(); + assertThat(deletedUser.getPoint()).isZero(); + assertThat(deletedUser.getDeviceToken()).isNull(); + + // when + deletedUser.renew(); + + // then + assertThat(deletedUser.getDeletedAt()).isNull(); + assertThat(deletedUser.getPoint()).isZero(); + } + + @Test + void ๊ทธ๋ฃน๋ช…_๊ฐ€์ ธ์˜ค๊ธฐ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + assertThat(user.groupString()).isEqualTo("ํ…Œ์ŠคํŠธ ๋Œ€ํ•™๊ต 1 ํ…Œ์ŠคํŠธ ํ•™๊ณผ 1 20ํ•™๋ฒˆ"); + } + + @Test + void ์ถ”์ฒœ_์นด์šดํŠธ_์ฆ๊ฐ€์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + assertThat(user.getRecommendCount()).isZero(); + + // when + user.increaseRecommendCount(); + + // then + assertThat(user.getRecommendCount()).isEqualTo(1); + } + + @Test + void ํฌ์ธํŠธ_์ฆ๊ฐ€์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + assertThat(user.getPoint()).isEqualTo(200); + + // when + user.increaseRecommendPoint(); + + // then + assertThat(user.getPoint()).isEqualTo(300); + } + + @Test + void ํฌ์ธํŠธ_๊ฐ์†Œ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + assertThat(user.getPoint()).isEqualTo(200); + + // when + user.minusPoint(100); + + // then + assertThat(user.getPoint()).isEqualTo(100); + } + + @Test + void ๋””๋ฐ”์ด์Šค_ํ† ํฐ_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + // when + // then + assertThat(user.getDeviceToken()).isEqualTo("deviceToken#1"); + } + + @Test + void ๋””๋ฐ”์ด์Šค_ํ† ํฐ_์ˆ˜์ •์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + assertThat(user.getDeviceToken()).isEqualTo("deviceToken#1"); + + // when + user.setDeviceToken("newDeviceToken"); + + // then + assertThat(user.getDeviceToken()).isEqualTo("newDeviceToken"); + } + + @Test + void ๊ตฌ๋…_์—ฌ๋ถ€_์ˆ˜์ •์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + assertThat(user.getSubscribe()).isEqualTo(Subscribe.NORMAL); + + // when + user.setSubscribe(Subscribe.ACTIVE); + + // then + assertThat(user.getSubscribe()).isEqualTo(Subscribe.ACTIVE); + } + + @Test + void ํ‹ฐ์ผ“_์ˆ˜๋Ÿ‰_์ˆ˜์ •์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + assertThat(user.getTicketCount()).isZero(); + + // when + user.addTicketCount(10); + + // then + assertThat(user.getTicketCount()).isEqualTo(10); + } + +} diff --git a/src/test/java/com/yello/server/small/domain/vote/FakeVoteManager.java b/src/test/java/com/yello/server/domain/vote/FakeVoteManager.java similarity index 95% rename from src/test/java/com/yello/server/small/domain/vote/FakeVoteManager.java rename to src/test/java/com/yello/server/domain/vote/FakeVoteManager.java index f3729f3a..deadc264 100644 --- a/src/test/java/com/yello/server/small/domain/vote/FakeVoteManager.java +++ b/src/test/java/com/yello/server/domain/vote/FakeVoteManager.java @@ -1,9 +1,9 @@ -package com.yello.server.small.domain.vote; +package com.yello.server.domain.vote; -import static com.yello.server.domain.vote.common.WeightedRandomFactory.randomPoint; import static com.yello.server.global.common.ErrorCode.DUPLICATE_VOTE_EXCEPTION; import static com.yello.server.global.common.ErrorCode.INVALID_VOTE_EXCEPTION; import static com.yello.server.global.common.ErrorCode.LACK_POINT_EXCEPTION; +import static com.yello.server.global.common.factory.WeightedRandomFactory.randomPoint; import static com.yello.server.global.common.util.ConstantUtil.KEYWORD_HINT_POINT; import static com.yello.server.global.common.util.ConstantUtil.NAME_HINT_DEFAULT; import static com.yello.server.global.common.util.ConstantUtil.NAME_HINT_POINT; @@ -31,7 +31,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; import java.util.stream.IntStream; public class FakeVoteManager implements VoteManager { @@ -115,7 +115,8 @@ public int useNameHint(User sender, Vote vote) { throw new VoteNotFoundException(INVALID_VOTE_EXCEPTION); } - int randomIndex = (int) (Math.random() * 2); + final ThreadLocalRandom random = ThreadLocalRandom.current(); + int randomIndex = random.nextInt(2); vote.checkNameIndexOf(randomIndex); sender.minusPoint(NAME_HINT_POINT); return randomIndex; @@ -185,7 +186,7 @@ private List getShuffledKeywords(Question question) { } private Vote createFirstVote(User sender, User receiver, Question question) { - Random random = new Random(); + final ThreadLocalRandom random = ThreadLocalRandom.current(); final String answer = "๋„ ๊ธฐ๋‹ค๋ ธ์–ด"; return Vote.builder() diff --git a/src/test/java/com/yello/server/small/domain/vote/FakeVoteRepository.java b/src/test/java/com/yello/server/domain/vote/FakeVoteRepository.java similarity index 99% rename from src/test/java/com/yello/server/small/domain/vote/FakeVoteRepository.java rename to src/test/java/com/yello/server/domain/vote/FakeVoteRepository.java index ec33f7f4..15ea84ed 100644 --- a/src/test/java/com/yello/server/small/domain/vote/FakeVoteRepository.java +++ b/src/test/java/com/yello/server/domain/vote/FakeVoteRepository.java @@ -1,4 +1,4 @@ -package com.yello.server.small.domain.vote; +package com.yello.server.domain.vote; import static com.yello.server.global.common.ErrorCode.NOT_FOUND_VOTE_EXCEPTION; diff --git a/src/test/java/com/yello/server/domain/vote/medium/VoteControllerTest.java b/src/test/java/com/yello/server/domain/vote/medium/VoteControllerTest.java new file mode 100644 index 00000000..da193725 --- /dev/null +++ b/src/test/java/com/yello/server/domain/vote/medium/VoteControllerTest.java @@ -0,0 +1,368 @@ +package com.yello.server.domain.vote.medium; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doNothing; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yello.server.domain.authorization.filter.JwtExceptionFilter; +import com.yello.server.domain.authorization.filter.JwtFilter; +import com.yello.server.domain.cooldown.entity.Cooldown; +import com.yello.server.domain.friend.dto.response.FriendShuffleResponse; +import com.yello.server.domain.friend.entity.Friend; +import com.yello.server.domain.keyword.dto.response.KeywordCheckResponse; +import com.yello.server.domain.question.dto.response.QuestionForVoteResponse; +import com.yello.server.domain.question.dto.response.QuestionVO; +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.vote.controller.VoteController; +import com.yello.server.domain.vote.dto.request.CreateVoteRequest; +import com.yello.server.domain.vote.dto.request.VoteAnswer; +import com.yello.server.domain.vote.dto.response.RevealFullNameResponse; +import com.yello.server.domain.vote.dto.response.RevealNameResponse; +import com.yello.server.domain.vote.dto.response.VoteAvailableResponse; +import com.yello.server.domain.vote.dto.response.VoteCountVO; +import com.yello.server.domain.vote.dto.response.VoteCreateResponse; +import com.yello.server.domain.vote.dto.response.VoteCreateVO; +import com.yello.server.domain.vote.dto.response.VoteDetailResponse; +import com.yello.server.domain.vote.dto.response.VoteFriendResponse; +import com.yello.server.domain.vote.dto.response.VoteFriendVO; +import com.yello.server.domain.vote.dto.response.VoteListResponse; +import com.yello.server.domain.vote.dto.response.VoteResponse; +import com.yello.server.domain.vote.dto.response.VoteUnreadCountResponse; +import com.yello.server.domain.vote.entity.Vote; +import com.yello.server.domain.vote.service.VoteService; +import com.yello.server.global.exception.ControllerExceptionAdvice; +import com.yello.server.infrastructure.firebase.service.NotificationService; +import com.yello.server.util.TestDataEntityUtil; +import com.yello.server.util.TestDataUtil; +import com.yello.server.util.WithAccessTokenUser; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +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.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.operation.preprocess.Preprocessors; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@AutoConfigureRestDocs +@WebMvcTest( + controllers = VoteController.class, + excludeFilters = { + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = JwtExceptionFilter.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ControllerExceptionAdvice.class) + }) +@WithAccessTokenUser +@DisplayNameGeneration(ReplaceUnderscores.class) +@DisplayName("Vote ์ปจํŠธ๋กค๋Ÿฌ์—์„œ") +class VoteControllerTest { + + final String[] excludeRequestHeaders = {"X-CSRF-TOKEN", "Host"}; + final String[] excludeResponseHeaders = {"X-Content-Type-Options", "X-XSS-Protection", "Cache-Control", "Pragma", + "Expires", "X-Frame-Options", "Content-Length"}; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private VoteService voteService; + + @MockBean + private NotificationService notificationService; + + private TestDataUtil testDataUtil = new TestDataEntityUtil(); + private User user; + private User target; + + @BeforeEach + void init() { + user = testDataUtil.generateUser(1L, 1L); + target = testDataUtil.generateUser(2L, 1L); + } + + @Test + void ๋‚ด_ํˆฌํ‘œ_์ „์ฒด_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Vote vote = testDataUtil.generateVote(1L, user, target, testDataUtil.generateQuestion(1L)); + final VoteResponse voteResponse = VoteResponse.of(vote); + final VoteCountVO voteCountVO = VoteCountVO.of(1, 0, 0, 0, 0); + final VoteListResponse voteListResponse = VoteListResponse.of(voteCountVO, Arrays.asList(voteResponse), user); + + given(voteService.findAllVotes(anyLong(), any(Pageable.class))) + .willReturn(voteListResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/vote") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .param("page", "0")) + .andDo(print()) + .andDo(document("api/v1/vote/findAllMyVotes", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + requestParameters(parameterWithName("page").description("ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ์ฝ์ง€_์•Š์€_์ชฝ์ง€_๊ฐœ์ˆ˜_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final VoteUnreadCountResponse voteUnreadCountResponse = VoteUnreadCountResponse.of(1); + + given(voteService.getUnreadVoteCount(anyLong())) + .willReturn(voteUnreadCountResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/vote/count") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + ) + .andDo(print()) + .andDo(document("api/v1/vote/getUnreadVoteCount", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ์นœ๊ตฌ_ํˆฌํ‘œ_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Vote vote = testDataUtil.generateVote(1L, user, target, testDataUtil.generateQuestion(1L)); + final VoteFriendVO voteFriendVO = VoteFriendVO.of(vote); + final VoteFriendResponse voteFriendResponse = VoteFriendResponse.of(1, Arrays.asList(voteFriendVO)); + + given(voteService.findAllFriendVotes(anyLong(), any(Pageable.class))) + .willReturn(voteFriendResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/vote/friend") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .param("page", "0")) + .andDo(print()) + .andDo(document("api/v1/vote/findAllFriendVotes", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + requestParameters(parameterWithName("page").description("ํŽ˜์ด์ง€๋„ค์ด์…˜ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ํˆฌํ‘œ_์ƒ์„ธ_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Vote vote = testDataUtil.generateVote(1L, user, target, testDataUtil.generateQuestion(1L)); + final VoteDetailResponse voteDetailResponse = VoteDetailResponse.of(vote, user); + + given(voteService.findVoteById(anyLong(), anyLong())) + .willReturn(voteDetailResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/vote/{voteId}", 1) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + ) + .andDo(print()) + .andDo(document("api/v1/vote/findVoteById", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + pathParameters(parameterWithName("voteId").description("ํˆฌํ‘œ ์•„์ด๋”” ๊ฐ’"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ํ‚ค์›Œ๋“œ_ํ™•์ธ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Vote vote = testDataUtil.generateVote(1L, user, target, testDataUtil.generateQuestion(1L)); + final KeywordCheckResponse keywordCheckResponse = KeywordCheckResponse.of(vote); + + given(voteService.checkKeyword(anyLong(), anyLong())) + .willReturn(keywordCheckResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.patch("/api/v1/vote/{voteId}/keyword", 1) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .with(csrf().asHeader()) + ) + .andDo(print()) + .andDo(document("api/v1/vote/checkKeyword", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + pathParameters(parameterWithName("voteId").description("ํˆฌํ‘œ ์•„์ด๋”” ๊ฐ’"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ํˆฌํ‘œ_8๊ฐœ_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Friend friend = testDataUtil.generateFriend(user, target); + final List friendShuffleResponses = Arrays.asList(FriendShuffleResponse.of(friend)); + final List keywordList = Arrays.asList("A", "B", "C", "D"); + final QuestionVO questionVO = QuestionVO.of(testDataUtil.generateQuestion(1L)); + final QuestionForVoteResponse questionForVoteResponse = QuestionForVoteResponse.builder() + .question(questionVO) + .friendList(friendShuffleResponses) + .keywordList(keywordList) + .questionPoint(10) + .subscribe("normal | active") + .build(); + + given(voteService.findVoteQuestionList(anyLong())) + .willReturn(Arrays.asList(questionForVoteResponse)); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/vote/question") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + ) + .andDo(print()) + .andDo(document("api/v1/vote/findVoteQuestions", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ํˆฌํ‘œ_๊ฐ€๋Šฅ_์—ฌ๋ถ€_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Cooldown cooldown = Cooldown.of(user, UUID.randomUUID().toString(), LocalDateTime.now()); + final VoteAvailableResponse voteAvailableResponse = VoteAvailableResponse.of(user, cooldown); + + given(voteService.checkVoteAvailable(anyLong())) + .willReturn(voteAvailableResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/vote/available") + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + ) + .andDo(print()) + .andDo(document("api/v1/vote/checkVoteAvailable", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ํˆฌํ‘œ_์ƒ์„ฑ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Vote vote = testDataUtil.generateVote(1L, user, target, testDataUtil.generateQuestion(1L)); + final VoteCreateVO voteCreateVO = VoteCreateVO.of(10, Arrays.asList(vote)); + final VoteCreateResponse voteCreateResponse = VoteCreateResponse.of(10); + final VoteAnswer voteAnswer = VoteAnswer.builder() + .friendId(2L) + .questionId(1L) + .keywordName("ํ‚ค์›Œ๋“œ") + .colorIndex(0) + .build(); + + final CreateVoteRequest createVoteRequest = CreateVoteRequest.builder() + .voteAnswerList(Arrays.asList(voteAnswer)) + .totalPoint(10) + .build(); + + given(voteService.createVote(anyLong(), eq(createVoteRequest))) + .willReturn(voteCreateVO); + + doNothing() + .when(notificationService) + .sendYelloNotification(any()); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/vote") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(createVoteRequest))) + .andDo(print()) + .andDo(document("api/v1/vote/createVote", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ํˆฌํ‘œ_์ด๋ฆ„_๋ถ€๋ถ„_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Long voteId = 1L; + final RevealNameResponse revealNameResponse = RevealNameResponse.of(user, 0); + + given(voteService.revealNameHint(anyLong(), anyLong())) + .willReturn(revealNameResponse); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.patch("/api/v1/vote/{voteId}/name", voteId) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .with(csrf().asHeader()) + ) + .andDo(print()) + .andDo(document("api/v1/vote/revealNameHint", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + pathParameters(parameterWithName("voteId").description("ํˆฌํ‘œ ์•„์ด๋”” ๊ฐ’"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + void ํˆฌํ‘œ_์ด๋ฆ„_์ „์ฒด_์กฐํšŒ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() throws Exception { + // given + final Long voteId = 1L; + final RevealFullNameResponse response = RevealFullNameResponse.of(user); + + given(voteService.revealFullName(anyLong(), anyLong())) + .willReturn(response); + + // when + // then + mockMvc.perform(RestDocumentationRequestBuilders.patch("/api/v1/vote/{voteId}/fullname", voteId) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .with(csrf().asHeader()) + ) + .andDo(print()) + .andDo(document("api/v1/vote/revealFullName", + Preprocessors.preprocessRequest(prettyPrint(), removeHeaders(excludeRequestHeaders)), + Preprocessors.preprocessResponse(prettyPrint(), removeHeaders(excludeResponseHeaders)), + pathParameters(parameterWithName("voteId").description("ํˆฌํ‘œ ์•„์ด๋”” ๊ฐ’"))) + ) + .andExpect(MockMvcResultMatchers.status().isOk()); + } +} diff --git a/src/test/java/com/yello/server/small/domain/vote/VoteManagerTest.java b/src/test/java/com/yello/server/domain/vote/small/VoteManagerTest.java similarity index 83% rename from src/test/java/com/yello/server/small/domain/vote/VoteManagerTest.java rename to src/test/java/com/yello/server/domain/vote/small/VoteManagerTest.java index f9cc2a07..9ce22a44 100644 --- a/src/test/java/com/yello/server/small/domain/vote/VoteManagerTest.java +++ b/src/test/java/com/yello/server/domain/vote/small/VoteManagerTest.java @@ -1,36 +1,42 @@ -package com.yello.server.small.domain.vote; +package com.yello.server.domain.vote.small; import static com.yello.server.global.common.factory.PaginationFactory.createPageable; import static org.assertj.core.api.Assertions.assertThat; +import com.yello.server.domain.friend.FakeFriendRepository; import com.yello.server.domain.friend.repository.FriendRepository; +import com.yello.server.domain.question.FakeQuestionRepository; import com.yello.server.domain.question.entity.Question; import com.yello.server.domain.question.repository.QuestionRepository; +import com.yello.server.domain.user.FakeUserManager; +import com.yello.server.domain.user.FakeUserRepository; import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.repository.UserRepository; import com.yello.server.domain.user.service.UserManager; +import com.yello.server.domain.vote.FakeVoteRepository; import com.yello.server.domain.vote.entity.Vote; import com.yello.server.domain.vote.repository.VoteRepository; import com.yello.server.domain.vote.service.VoteManager; import com.yello.server.domain.vote.service.VoteManagerImpl; -import com.yello.server.small.domain.friend.FakeFriendRepository; -import com.yello.server.small.domain.question.FakeQuestionRepository; -import com.yello.server.small.domain.user.FakeUserManager; -import com.yello.server.small.domain.user.FakeUserRepository; -import com.yello.server.util.TestDataUtil; +import com.yello.server.util.TestDataRepositoryUtil; import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Pageable; +@DisplayName("VoteManager ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) public class VoteManagerTest { private final UserRepository userRepository = new FakeUserRepository(); private final FriendRepository friendRepository = new FakeFriendRepository(); private final VoteRepository voteRepository = new FakeVoteRepository(); private final QuestionRepository questionRepository = new FakeQuestionRepository(); - private final TestDataUtil testDataUtil = new TestDataUtil( + private final TestDataRepositoryUtil testDataUtil = new TestDataRepositoryUtil( userRepository, voteRepository, questionRepository, diff --git a/src/test/java/com/yello/server/small/domain/vote/VoteServiceTest.java b/src/test/java/com/yello/server/domain/vote/small/VoteServiceTest.java similarity index 89% rename from src/test/java/com/yello/server/small/domain/vote/VoteServiceTest.java rename to src/test/java/com/yello/server/domain/vote/small/VoteServiceTest.java index d0848d95..25b4c23b 100644 --- a/src/test/java/com/yello/server/small/domain/vote/VoteServiceTest.java +++ b/src/test/java/com/yello/server/domain/vote/small/VoteServiceTest.java @@ -1,18 +1,26 @@ -package com.yello.server.small.domain.vote; +package com.yello.server.domain.vote.small; import static com.yello.server.global.common.factory.PaginationFactory.createPageable; import static org.assertj.core.api.Assertions.assertThat; +import com.yello.server.domain.cooldown.FakeCooldownRepository; import com.yello.server.domain.cooldown.repository.CooldownRepository; +import com.yello.server.domain.friend.FakeFriendRepository; import com.yello.server.domain.friend.repository.FriendRepository; +import com.yello.server.domain.keyword.FakeKeywordRepository; import com.yello.server.domain.keyword.dto.response.KeywordCheckResponse; import com.yello.server.domain.keyword.repository.KeywordRepository; +import com.yello.server.domain.question.FakeQuestionRepository; import com.yello.server.domain.question.dto.response.QuestionForVoteResponse; import com.yello.server.domain.question.entity.Question; import com.yello.server.domain.question.repository.QuestionRepository; +import com.yello.server.domain.user.FakeUserManager; +import com.yello.server.domain.user.FakeUserRepository; import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.repository.UserRepository; import com.yello.server.domain.user.service.UserManager; +import com.yello.server.domain.vote.FakeVoteManager; +import com.yello.server.domain.vote.FakeVoteRepository; import com.yello.server.domain.vote.dto.request.CreateVoteRequest; import com.yello.server.domain.vote.dto.request.VoteAnswer; import com.yello.server.domain.vote.dto.response.RevealNameResponse; @@ -26,23 +34,22 @@ import com.yello.server.domain.vote.repository.VoteRepository; import com.yello.server.domain.vote.service.VoteManager; import com.yello.server.domain.vote.service.VoteService; +import com.yello.server.infrastructure.rabbitmq.FakeMessageQueueRepository; +import com.yello.server.infrastructure.rabbitmq.FakeProducerService; import com.yello.server.infrastructure.rabbitmq.service.ProducerService; -import com.yello.server.small.domain.cooldown.FakeCooldownRepository; -import com.yello.server.small.domain.friend.FakeFriendRepository; -import com.yello.server.small.domain.keyword.FakeKeywordRepository; -import com.yello.server.small.domain.question.FakeQuestionRepository; -import com.yello.server.small.domain.user.FakeUserManager; -import com.yello.server.small.domain.user.FakeUserRepository; -import com.yello.server.small.global.rabbitmq.FakeMessageQueueRepository; -import com.yello.server.small.global.rabbitmq.FakeProducerService; -import com.yello.server.util.TestDataUtil; +import com.yello.server.util.TestDataRepositoryUtil; import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Pageable; +@DisplayName("VoteService ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) public class VoteServiceTest { private final UserRepository userRepository = new FakeUserRepository(); @@ -61,7 +68,7 @@ public class VoteServiceTest { userManager ); - private final TestDataUtil testDataUtil = new TestDataUtil( + private final TestDataRepositoryUtil testDataUtil = new TestDataRepositoryUtil( userRepository, voteRepository, questionRepository, diff --git a/src/test/java/com/yello/server/global/common/factory/ListFactoryTest.java b/src/test/java/com/yello/server/global/common/factory/ListFactoryTest.java new file mode 100644 index 00000000..db5768f0 --- /dev/null +++ b/src/test/java/com/yello/server/global/common/factory/ListFactoryTest.java @@ -0,0 +1,38 @@ +package com.yello.server.global.common.factory; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; + +@DisplayName("ListFactory ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) +public class ListFactoryTest { + + @Test + void null์ด_์—†๋Š”_๋ฆฌ์ŠคํŠธ_๋ณ€ํ™˜์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + List> optionalList = new ArrayList<>(); + optionalList.add(Optional.of(1)); + optionalList.add(Optional.empty()); + optionalList.add(Optional.of(3)); + optionalList.add(Optional.empty()); + optionalList.add(Optional.of(5)); + + // when + List result = ListFactory.toNonNullableList(optionalList); + + // then + assertThat(result).hasSize(3); + assertThat(result.get(0)).isEqualTo(1); + assertThat(result.get(1)).isEqualTo(3); + assertThat(result.get(2)).isEqualTo(5); + } + + +} diff --git a/src/test/java/com/yello/server/global/common/factory/PaginationFactoryTest.java b/src/test/java/com/yello/server/global/common/factory/PaginationFactoryTest.java new file mode 100644 index 00000000..7fbaaabd --- /dev/null +++ b/src/test/java/com/yello/server/global/common/factory/PaginationFactoryTest.java @@ -0,0 +1,89 @@ +package com.yello.server.global.common.factory; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort.Direction; + +@DisplayName("PaginationFactory ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) +public class PaginationFactoryTest { + + private final int PAGE_LIMIT = 100; + private final int PAGE_LIMIT_TEN = 10; + + @Test + void Pageable_๊ฐ์ฒด_์ƒ์„ฑ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + final Integer page = 1; + + // when + final Pageable pageable = PaginationFactory.createPageable(page); + + // then + assertThat(pageable.getPageNumber()).isEqualTo(page); + assertThat(pageable.getPageSize()).isEqualTo(PAGE_LIMIT); + } + + @Test + void ์ด๋ฆ„์œผ๋กœ_์ •๋ ฌ๋œ_Pageable_๊ฐ์ฒด_์ƒ์„ฑ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + final Integer page = 1; + + // when + final Pageable pageable = PaginationFactory.createPageableByNameSort(page); + + // then + assertThat(pageable.getPageNumber()).isEqualTo(page); + assertThat(pageable.getPageSize()).isEqualTo(PAGE_LIMIT); + assertThat(pageable.getSort().getOrderFor("name").getDirection()).isEqualTo(Direction.ASC); + } + + @Test + void Page_Size_10_๊ณ ์ •_Pageable_๊ฐ์ฒด_์ƒ์„ฑ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + final Integer page = 1; + + // when + final Pageable pageable = PaginationFactory.createPageable(page); + + // then + assertThat(pageable.getPageNumber()).isEqualTo(page); + assertThat(pageable.getPageSize()).isEqualTo(PAGE_LIMIT); + } + + @Test + void Page_๊ฐ์ฒด_์ƒ์„ฑ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + final Integer page = 1; + final Pageable pageable = PageRequest.of(page, PAGE_LIMIT_TEN); + List dataList = new ArrayList<>(); + for (int i = 1; i <= 20; i++) { + dataList.add(i); + } + + // when + Page resultPage = PaginationFactory.getPage(dataList, pageable); + + // then + assertThat(pageable.getPageNumber()).isEqualTo(page); + assertThat(pageable.getPageSize()).isEqualTo(PAGE_LIMIT_TEN); + + assertThat(resultPage.getTotalElements()).isEqualTo(20); + assertThat(resultPage.getSize()).isEqualTo(PAGE_LIMIT_TEN); + assertThat(resultPage.getTotalPages()).isEqualTo(2); + + List content = resultPage.getContent(); + assertThat(content).hasSize(10); + assertThat(content.get(0)).isEqualTo(11); + assertThat(content.get(9)).isEqualTo(20); + } +} diff --git a/src/test/java/com/yello/server/global/common/factory/TimeFactoryTest.java b/src/test/java/com/yello/server/global/common/factory/TimeFactoryTest.java new file mode 100644 index 00000000..b19d2aa0 --- /dev/null +++ b/src/test/java/com/yello/server/global/common/factory/TimeFactoryTest.java @@ -0,0 +1,42 @@ +package com.yello.server.global.common.factory; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Duration; +import java.time.LocalDateTime; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; + +@DisplayName("TimeFactory ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) +public class TimeFactoryTest { + + @Test + void ์‹œ๊ฐ„์„_๋ฌธ์ž์—ด_ํ˜•์‹์œผ๋กœ_ํฌ๋งทํŒ…์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + final LocalDateTime localDateTime = LocalDateTime.of(2023, 1, 1, 14, 0, 0); + + final LocalDateTime currentDateTime = LocalDateTime.now(); + Duration duration = Duration.between(localDateTime, currentDateTime); + long seconds = duration.getSeconds(); + String expect = ""; + + if (seconds < 60) { + expect = seconds + "์ดˆ ์ „"; + } else if ((seconds /= 60) < 60) { + expect = seconds + "๋ถ„ ์ „"; + } else if ((seconds /= 60) < 24) { + expect = (seconds) + "์‹œ๊ฐ„ ์ „"; + } + + expect = (seconds / 24) + "์ผ ์ „"; + + // when + String result = TimeFactory.toFormattedString(localDateTime); + + // then + assertThat(result).isEqualTo(expect); + } +} \ No newline at end of file diff --git a/src/test/java/com/yello/server/global/common/factory/WeightedRandomFactoryTest.java b/src/test/java/com/yello/server/global/common/factory/WeightedRandomFactoryTest.java new file mode 100644 index 00000000..0ec41b0e --- /dev/null +++ b/src/test/java/com/yello/server/global/common/factory/WeightedRandomFactoryTest.java @@ -0,0 +1,27 @@ +package com.yello.server.global.common.factory; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.ThreadLocalRandom; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; + +@DisplayName("WeightedRandomFactory ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) +public class WeightedRandomFactoryTest { + + @Test + void ๊ฐ€์ค‘์น˜_๋žœ๋ค๊ฐ’_์ƒ์„ฑ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + final ThreadLocalRandom random = ThreadLocalRandom.current(); + + // when + Integer result = WeightedRandomFactory.randomPoint(); + + // then + assertThat(result).isBetween(5, 25); + assertThat(random.nextDouble()).isBetween(0.0, 1.0); + } +} \ No newline at end of file diff --git a/src/test/java/com/yello/server/small/global/firebase/FakeFcmManger.java b/src/test/java/com/yello/server/infrastructure/firebase/FakeFcmManger.java similarity index 94% rename from src/test/java/com/yello/server/small/global/firebase/FakeFcmManger.java rename to src/test/java/com/yello/server/infrastructure/firebase/FakeFcmManger.java index 3efcae87..aa42ffd6 100644 --- a/src/test/java/com/yello/server/small/global/firebase/FakeFcmManger.java +++ b/src/test/java/com/yello/server/infrastructure/firebase/FakeFcmManger.java @@ -1,12 +1,12 @@ -package com.yello.server.small.global.firebase; +package com.yello.server.infrastructure.firebase; import com.google.firebase.messaging.ApnsConfig; import com.google.firebase.messaging.Aps; import com.google.firebase.messaging.Message; +import com.yello.server.domain.vote.FakeVoteRepository; import com.yello.server.domain.vote.repository.VoteRepository; import com.yello.server.infrastructure.firebase.dto.request.NotificationMessage; import com.yello.server.infrastructure.firebase.manager.FCMManager; -import com.yello.server.small.domain.vote.FakeVoteRepository; public class FakeFcmManger implements FCMManager { diff --git a/src/test/java/com/yello/server/small/global/firebase/NotificationFcmServiceTest.java b/src/test/java/com/yello/server/infrastructure/firebase/NotificationFcmServiceTest.java similarity index 91% rename from src/test/java/com/yello/server/small/global/firebase/NotificationFcmServiceTest.java rename to src/test/java/com/yello/server/infrastructure/firebase/NotificationFcmServiceTest.java index f14921bb..b11f2a90 100644 --- a/src/test/java/com/yello/server/small/global/firebase/NotificationFcmServiceTest.java +++ b/src/test/java/com/yello/server/infrastructure/firebase/NotificationFcmServiceTest.java @@ -1,10 +1,11 @@ -package com.yello.server.small.global.firebase; +package com.yello.server.infrastructure.firebase; import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.yello.server.domain.friend.entity.Friend; import com.yello.server.domain.group.entity.School; import com.yello.server.domain.question.entity.Question; +import com.yello.server.domain.user.FakeUserRepository; import com.yello.server.domain.user.entity.Gender; import com.yello.server.domain.user.entity.Social; import com.yello.server.domain.user.entity.User; @@ -14,13 +15,17 @@ import com.yello.server.infrastructure.firebase.manager.FCMManager; import com.yello.server.infrastructure.firebase.service.NotificationFcmService; import com.yello.server.infrastructure.firebase.service.NotificationService; +import com.yello.server.infrastructure.redis.FakeTokenRepository; import com.yello.server.infrastructure.redis.repository.TokenRepository; -import com.yello.server.small.domain.user.FakeUserRepository; -import com.yello.server.small.global.redis.FakeTokenRepository; import java.time.LocalDateTime; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; +@DisplayName("NotificationFcmService ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) class NotificationFcmServiceTest { private final UserRepository userRepository = new FakeUserRepository(); diff --git a/src/test/java/com/yello/server/infrastructure/firebase/small/FcmManagerTest.java b/src/test/java/com/yello/server/infrastructure/firebase/small/FcmManagerTest.java new file mode 100644 index 00000000..0ba548a7 --- /dev/null +++ b/src/test/java/com/yello/server/infrastructure/firebase/small/FcmManagerTest.java @@ -0,0 +1,76 @@ +package com.yello.server.infrastructure.firebase.small; + +import com.yello.server.domain.friend.FakeFriendRepository; +import com.yello.server.domain.friend.repository.FriendRepository; +import com.yello.server.domain.question.FakeQuestionRepository; +import com.yello.server.domain.question.entity.Question; +import com.yello.server.domain.question.repository.QuestionRepository; +import com.yello.server.domain.user.FakeUserRepository; +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.user.repository.UserRepository; +import com.yello.server.domain.vote.FakeVoteRepository; +import com.yello.server.domain.vote.repository.VoteRepository; +import com.yello.server.infrastructure.firebase.dto.request.NotificationMessage; +import com.yello.server.infrastructure.firebase.manager.FCMManager; +import com.yello.server.infrastructure.firebase.manager.FCMManagerImpl; +import com.yello.server.util.TestDataRepositoryUtil; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; + +@DisplayName("FcmManager ์—์„œ") +@DisplayNameGeneration(ReplaceUnderscores.class) +public class FcmManagerTest { + + private final UserRepository userRepository = new FakeUserRepository(); + private final VoteRepository voteRepository = new FakeVoteRepository(); + private final QuestionRepository questionRepository = new FakeQuestionRepository(); + private final FriendRepository friendRepository = new FakeFriendRepository(); + + private final TestDataRepositoryUtil testDataUtil = new TestDataRepositoryUtil( + userRepository, + voteRepository, + questionRepository, + friendRepository + ); + + private FCMManager fcmManager; + + @BeforeEach + void init() { + this.fcmManager = FCMManagerImpl.builder() + .voteRepository(voteRepository) + .build(); + + User user = testDataUtil.generateUser(1L, 1L); + User target = testDataUtil.generateUser(2L, 1L); + Question question = testDataUtil.generateQuestion(1L); + testDataUtil.generateVote(1L, user, target, question); + } + + @Test + void path๋ฅผ_์ œ์™ธํ•œ_๋ฉ”์„ธ์ง€_๊ฐ์ฒด_์ƒ์„ฑ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + final String testDeviceToken = "testDeviceToken"; + final NotificationMessage notificationMessage = NotificationMessage.toVoteAvailableNotificationContent(); + + // when + // then + fcmManager.createMessage(testDeviceToken, notificationMessage); + } + + @Test + void path๋ฅผ_ํฌํ•จํ•œ_๋ฉ”์„ธ์ง€_๊ฐ์ฒด_์ƒ์„ฑ์—_์„ฑ๊ณตํ•ฉ๋‹ˆ๋‹ค() { + // given + final String path = "/api/v1/vote/1"; + final String testDeviceToken = "deviceToken#2"; + final NotificationMessage notificationMessage = NotificationMessage.toVoteAvailableNotificationContent(); + + // when + // then + fcmManager.createMessage(testDeviceToken, notificationMessage, path); + } + +} diff --git a/src/test/java/com/yello/server/small/global/rabbitmq/FakeMessageQueueRepository.java b/src/test/java/com/yello/server/infrastructure/rabbitmq/FakeMessageQueueRepository.java similarity index 88% rename from src/test/java/com/yello/server/small/global/rabbitmq/FakeMessageQueueRepository.java rename to src/test/java/com/yello/server/infrastructure/rabbitmq/FakeMessageQueueRepository.java index 66c85685..67521f3a 100644 --- a/src/test/java/com/yello/server/small/global/rabbitmq/FakeMessageQueueRepository.java +++ b/src/test/java/com/yello/server/infrastructure/rabbitmq/FakeMessageQueueRepository.java @@ -1,4 +1,4 @@ -package com.yello.server.small.global.rabbitmq; +package com.yello.server.infrastructure.rabbitmq; import com.yello.server.infrastructure.rabbitmq.repository.MessageQueueRepository; import org.springframework.amqp.core.MessagePostProcessor; diff --git a/src/test/java/com/yello/server/small/global/rabbitmq/FakeProducerService.java b/src/test/java/com/yello/server/infrastructure/rabbitmq/FakeProducerService.java similarity index 92% rename from src/test/java/com/yello/server/small/global/rabbitmq/FakeProducerService.java rename to src/test/java/com/yello/server/infrastructure/rabbitmq/FakeProducerService.java index 0458d0d6..eea2c34d 100644 --- a/src/test/java/com/yello/server/small/global/rabbitmq/FakeProducerService.java +++ b/src/test/java/com/yello/server/infrastructure/rabbitmq/FakeProducerService.java @@ -1,4 +1,4 @@ -package com.yello.server.small.global.rabbitmq; +package com.yello.server.infrastructure.rabbitmq; import com.yello.server.domain.cooldown.entity.Cooldown; import com.yello.server.infrastructure.rabbitmq.repository.MessageQueueRepository; diff --git a/src/test/java/com/yello/server/small/global/redis/FakeTokenRepository.java b/src/test/java/com/yello/server/infrastructure/redis/FakeTokenRepository.java similarity index 91% rename from src/test/java/com/yello/server/small/global/redis/FakeTokenRepository.java rename to src/test/java/com/yello/server/infrastructure/redis/FakeTokenRepository.java index 483b1e7a..bc2133a0 100644 --- a/src/test/java/com/yello/server/small/global/redis/FakeTokenRepository.java +++ b/src/test/java/com/yello/server/infrastructure/redis/FakeTokenRepository.java @@ -1,4 +1,4 @@ -package com.yello.server.small.global.redis; +package com.yello.server.infrastructure.redis; import com.yello.server.domain.authorization.dto.ServiceTokenVO; import com.yello.server.infrastructure.redis.repository.TokenRepository; diff --git a/src/test/java/com/yello/server/util/TestDataEntityUtil.java b/src/test/java/com/yello/server/util/TestDataEntityUtil.java new file mode 100644 index 00000000..d0275790 --- /dev/null +++ b/src/test/java/com/yello/server/util/TestDataEntityUtil.java @@ -0,0 +1,109 @@ +package com.yello.server.util; + +import com.yello.server.domain.friend.entity.Friend; +import com.yello.server.domain.group.entity.School; +import com.yello.server.domain.question.entity.Question; +import com.yello.server.domain.user.entity.Gender; +import com.yello.server.domain.user.entity.Social; +import com.yello.server.domain.user.entity.Subscribe; +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.vote.entity.Vote; +import java.time.LocalDateTime; + +public class TestDataEntityUtil implements TestDataUtil { + + @Override + public User generateUser(long index, long schoolIndex) { + School school = School.builder() + .id(schoolIndex) + .schoolName("ํ…Œ์ŠคํŠธ ๋Œ€ํ•™๊ต %d".formatted(index)) + .departmentName("ํ…Œ์ŠคํŠธ ํ•™๊ณผ %d".formatted(index)) + .build(); + + return User.builder() + .id((index)) + .recommendCount(0L) + .name("name%d".formatted(index)) + .yelloId("yelloId%d".formatted(index)) + .gender(Gender.MALE) + .point(200) + .social(Social.KAKAO) + .profileImage("test image") + .uuid("%d".formatted(index)) + .deletedAt(null) + .group(school) + .groupAdmissionYear(20) + .deviceToken("deviceToken#%d".formatted(index)) + .subscribe(Subscribe.NORMAL) + .ticketCount(0) + .email("test%d@test.com".formatted(index)) + .build(); + } + + @Override + public User generateDeletedUser(long index, long schoolIndex) { + School school = School.builder() + .id(schoolIndex) + .schoolName("ํ…Œ์ŠคํŠธ ๋Œ€ํ•™๊ต %d".formatted(index)) + .departmentName("ํ…Œ์ŠคํŠธ ํ•™๊ณผ %d".formatted(index)) + .build(); + + return User.builder() + .id(index) + .recommendCount(0L) + .name("name%d".formatted(index)) + .yelloId("yelloId%d".formatted(index)) + .gender(Gender.MALE) + .point(0) + .social(Social.KAKAO) + .profileImage("test image") + .uuid("%d".formatted(index)) + .deletedAt(LocalDateTime.now()) + .group(school) + .groupAdmissionYear(20) + .deviceToken(null) + .subscribe(Subscribe.NORMAL) + .ticketCount(0) + .email("test%d@test.com".formatted(index)) + .build(); + } + + @Override + public Friend generateFriend(User user, User target) { + return Friend.createFriend(user, target); + } + + @Override + public Vote generateVote(long index, User sender, User receiver, Question question) { + return Vote.builder() + .id(index) + .colorIndex(0) + .answer("test") + .isRead(false) + .nameHint(-1) + .isAnswerRevealed(false) + .sender(sender) + .receiver(receiver) + .question(question) + .createdAt(LocalDateTime.now()) + .build(); + } + + @Override + public Question generateQuestion(long index) { + return Question.builder() + .id(index) + .nameHead("๋‚˜๋Š”").nameFoot("์™€") + .keywordHead("๋ฉ‹์ง„").keywordFoot("์—์„œ ๋†€๊ณ ์‹ถ์–ด") + .build(); + } + + @Override + public School generateSchool(long index) { + return School.builder() + .id(index) + .schoolName("ํ…Œ์ŠคํŠธ ๋Œ€ํ•™๊ต %d".formatted(index)) + .departmentName("ํ…Œ์ŠคํŠธ ํ•™๊ณผ %d".formatted(index)) + .build(); + } +} diff --git a/src/test/java/com/yello/server/util/TestDataRepositoryUtil.java b/src/test/java/com/yello/server/util/TestDataRepositoryUtil.java new file mode 100644 index 00000000..a36c6873 --- /dev/null +++ b/src/test/java/com/yello/server/util/TestDataRepositoryUtil.java @@ -0,0 +1,124 @@ +package com.yello.server.util; + +import com.yello.server.domain.friend.entity.Friend; +import com.yello.server.domain.friend.repository.FriendRepository; +import com.yello.server.domain.group.entity.School; +import com.yello.server.domain.question.entity.Question; +import com.yello.server.domain.question.repository.QuestionRepository; +import com.yello.server.domain.user.entity.Gender; +import com.yello.server.domain.user.entity.Social; +import com.yello.server.domain.user.entity.Subscribe; +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.user.repository.UserRepository; +import com.yello.server.domain.vote.entity.Vote; +import com.yello.server.domain.vote.repository.VoteRepository; +import java.time.LocalDateTime; + +public class TestDataRepositoryUtil implements TestDataUtil { + + private final UserRepository userRepository; + private final VoteRepository voteRepository; + private final QuestionRepository questionRepository; + private final FriendRepository friendRepository; + + public TestDataRepositoryUtil(UserRepository userRepository, VoteRepository voteRepository, + QuestionRepository questionRepository, + FriendRepository friendRepository) { + this.userRepository = userRepository; + this.voteRepository = voteRepository; + this.questionRepository = questionRepository; + this.friendRepository = friendRepository; + } + + @Override + public User generateUser(long index, long schoolIndex) { + School school = generateSchool(schoolIndex); + + return userRepository.save(User.builder() + .id((index)) + .recommendCount(0L) + .name("name%d".formatted(index)) + .yelloId("yelloId%d".formatted(index)) + .gender(Gender.MALE) + .point(200) + .social(Social.KAKAO) + .profileImage("test image") + .uuid("%d".formatted(index)) + .deletedAt(null) + .group(school) + .groupAdmissionYear(20) + .deviceToken("deviceToken#%d".formatted(index)) + .subscribe(Subscribe.NORMAL) + .ticketCount(0) + .email("test%d@test.com".formatted(index)) + .build()); + } + + @Override + public User generateDeletedUser(long index, long schoolIndex) { + School school = generateSchool(schoolIndex); + + return userRepository.save(User.builder() + .id(index) + .recommendCount(0L) + .name("name%d".formatted(index)) + .yelloId("yelloId%d".formatted(index)) + .gender(Gender.MALE) + .point(0) + .social(Social.KAKAO) + .profileImage("test image") + .uuid("%d".formatted(index)) + .deletedAt(LocalDateTime.now()) + .group(school) + .groupAdmissionYear(20) + .deviceToken(null) + .subscribe(Subscribe.NORMAL) + .ticketCount(0) + .email("test%d@test.com".formatted(index)) + .build()); + } + + @Override + public Friend generateFriend(User user, User target) { + return friendRepository.save(Friend.createFriend(user, target)); + } + + @Override + public Vote generateVote(long index, User sender, User receiver, Question question) { + return voteRepository.save( + Vote.builder() + .id(index) + .colorIndex(0) + .answer("test") + .isRead(false) + .nameHint(-1) + .isAnswerRevealed(false) + .sender(sender) + .receiver(receiver) + .question(question) + .createdAt(LocalDateTime.now()) + .build() + ); + } + + @Override + public Question generateQuestion(long index) { + return questionRepository.save( + Question.builder() + .id(index) + .nameHead("๋‚˜๋Š”").nameFoot("์™€") + .keywordHead("๋ฉ‹์ง„").keywordFoot("์—์„œ ๋†€๊ณ ์‹ถ์–ด") + .build() + ); + } + + @Override + public School generateSchool(long index) { + return School.builder() + .id(index) + .schoolName("ํ…Œ์ŠคํŠธ ๋Œ€ํ•™๊ต %d".formatted(index)) + .departmentName("ํ…Œ์ŠคํŠธ ํ•™๊ณผ %d".formatted(index)) + .build(); + } + +} diff --git a/src/test/java/com/yello/server/util/TestDataUtil.java b/src/test/java/com/yello/server/util/TestDataUtil.java index 583edfff..0c7ca96c 100644 --- a/src/test/java/com/yello/server/util/TestDataUtil.java +++ b/src/test/java/com/yello/server/util/TestDataUtil.java @@ -1,118 +1,23 @@ package com.yello.server.util; import com.yello.server.domain.friend.entity.Friend; -import com.yello.server.domain.friend.repository.FriendRepository; import com.yello.server.domain.group.entity.School; import com.yello.server.domain.question.entity.Question; -import com.yello.server.domain.question.repository.QuestionRepository; -import com.yello.server.domain.user.entity.Gender; -import com.yello.server.domain.user.entity.Social; -import com.yello.server.domain.user.entity.Subscribe; import com.yello.server.domain.user.entity.User; -import com.yello.server.domain.user.repository.UserRepository; import com.yello.server.domain.vote.entity.Vote; -import com.yello.server.domain.vote.repository.VoteRepository; -import java.time.LocalDateTime; -public class TestDataUtil { +public interface TestDataUtil { - private final UserRepository userRepository; - private final VoteRepository voteRepository; - private final QuestionRepository questionRepository; - private final FriendRepository friendRepository; + User generateUser(long index, long schoolIndex); - public TestDataUtil(UserRepository userRepository, VoteRepository voteRepository, - QuestionRepository questionRepository, - FriendRepository friendRepository) { - this.userRepository = userRepository; - this.voteRepository = voteRepository; - this.questionRepository = questionRepository; - this.friendRepository = friendRepository; - } + User generateDeletedUser(long index, long schoolIndex); - public User generateUser(long index, long schoolIndex) { - School school = generateSchool(schoolIndex); + Friend generateFriend(User user, User target); - return userRepository.save(User.builder() - .id((index)) - .recommendCount(0L) - .name("name%d".formatted(index)) - .yelloId("yelloId%d".formatted(index)) - .gender(Gender.MALE) - .point(200) - .social(Social.KAKAO) - .profileImage("test image") - .uuid("%d".formatted(index)) - .deletedAt(null) - .group(school) - .groupAdmissionYear(20) - .deviceToken("deviceToken#%d".formatted(index)) - .subscribe(Subscribe.NORMAL) - .ticketCount(0) - .email("test%d@test.com".formatted(index)) - .build()); - } + Vote generateVote(long index, User sender, User receiver, Question question); - public User generateDeletedUser(long index, long schoolIndex) { - School school = generateSchool(schoolIndex); - - return userRepository.save(User.builder() - .id(index) - .recommendCount(0L) - .name("name%d".formatted(index)) - .yelloId("yelloId%d".formatted(index)) - .gender(Gender.MALE) - .point(0) - .social(Social.KAKAO) - .profileImage("test image") - .uuid("%d".formatted(index)) - .deletedAt(LocalDateTime.now()) - .group(school) - .groupAdmissionYear(20) - .deviceToken(null) - .subscribe(Subscribe.NORMAL) - .ticketCount(0) - .email("test%d@test.com".formatted(index)) - .build()); - } - - public void generateFriend(User user, User target) { - friendRepository.save(Friend.createFriend(user, target)); - } - - public Vote generateVote(long index, User sender, User receiver, Question question) { - return voteRepository.save( - Vote.builder() - .id(index) - .colorIndex(0) - .answer("test") - .isRead(false) - .nameHint(-1) - .isAnswerRevealed(false) - .sender(sender) - .receiver(receiver) - .question(question) - .createdAt(LocalDateTime.now()) - .build() - ); - } - - public Question generateQuestion(long index) { - return questionRepository.save( - Question.builder() - .id(index) - .nameHead("๋‚˜๋Š”").nameFoot("์™€") - .keywordHead("๋ฉ‹์ง„").keywordFoot("์—์„œ ๋†€๊ณ ์‹ถ์–ด") - .build() - ); - } - - public School generateSchool(long index) { - return School.builder() - .id(index) - .schoolName("ํ…Œ์ŠคํŠธ ๋Œ€ํ•™๊ต %d".formatted(index)) - .departmentName("ํ…Œ์ŠคํŠธ ํ•™๊ณผ %d".formatted(index)) - .build(); - } + Question generateQuestion(long index); + School generateSchool(long index); } + diff --git a/src/test/java/com/yello/server/util/WithAccessTokenUser.java b/src/test/java/com/yello/server/util/WithAccessTokenUser.java new file mode 100644 index 00000000..c430e8e7 --- /dev/null +++ b/src/test/java/com/yello/server/util/WithAccessTokenUser.java @@ -0,0 +1,11 @@ +package com.yello.server.util; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import org.springframework.security.test.context.support.WithSecurityContext; + +@Retention(RetentionPolicy.RUNTIME) +@WithSecurityContext(factory = WithAccessTokenUserSecurityFactory.class) +public @interface WithAccessTokenUser { + +} diff --git a/src/test/java/com/yello/server/util/WithAccessTokenUserSecurityFactory.java b/src/test/java/com/yello/server/util/WithAccessTokenUserSecurityFactory.java new file mode 100644 index 00000000..d242458e --- /dev/null +++ b/src/test/java/com/yello/server/util/WithAccessTokenUserSecurityFactory.java @@ -0,0 +1,56 @@ +package com.yello.server.util; + +import com.yello.server.domain.group.entity.School; +import com.yello.server.domain.user.entity.Gender; +import com.yello.server.domain.user.entity.Social; +import com.yello.server.domain.user.entity.Subscribe; +import com.yello.server.domain.user.entity.User; +import java.util.List; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.test.context.support.WithSecurityContextFactory; + +public class WithAccessTokenUserSecurityFactory implements WithSecurityContextFactory { + + @Override + public SecurityContext createSecurityContext(WithAccessTokenUser annotation) { + SecurityContext context = SecurityContextHolder.createEmptyContext(); + + School school = School.builder() + .schoolName("school") + .departmentName("department") + .build(); + + User user = User.builder() + .id(1L) + .recommendCount(0L) + .name("name") + .yelloId("yelloId") + .gender(Gender.MALE) + .point(200) + .social(Social.KAKAO) + .profileImage("profileImage") + .uuid("uuid") + .deletedAt(null) + .group(school) + .deviceToken("deviceToken") + .subscribe(Subscribe.NORMAL) + .ticketCount(0) + .groupAdmissionYear(20) + .email("test@test.com") + .build(); + + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + user.getYelloId(), + null, + List.of(new SimpleGrantedAuthority("USER")) + ); + + authentication.setDetails(user); + + context.setAuthentication(authentication); + return context; + } +}