diff --git a/src/docs/asciidoc/create-event-history.adoc b/src/docs/asciidoc/create-event-history.adoc index 00ccbcca..90bd2dcc 100644 --- a/src/docs/asciidoc/create-event-history.adoc +++ b/src/docs/asciidoc/create-event-history.adoc @@ -1,10 +1,9 @@ :reproducible: -== 공지 조회 +== 이벤트 참여 === 요청 include::{snippets}/api/v1/event/join/1/http-request.adoc[] -include::{snippets}/api/v1/event/join/2/http-request.adoc[] === 응답 @@ -12,7 +11,7 @@ include::{snippets}/api/v1/event/join/1/http-response.adoc[] === 주의 -- "tag": "LUNCH_EVENT" | "ADMOB" +- "tag": "LUNCH_EVENT" === NOTE diff --git a/src/docs/asciidoc/find-event.adoc b/src/docs/asciidoc/find-event.adoc index 4dbb06a8..4b486a4a 100644 --- a/src/docs/asciidoc/find-event.adoc +++ b/src/docs/asciidoc/find-event.adoc @@ -1,5 +1,5 @@ :reproducible: -== 공지 조회 +== 이벤트 조회 === 요청 @@ -17,7 +17,7 @@ include::{snippets}/api/v1/event/3/http-response.adoc[] - data: *Response*[] - *Response* -- tag : "LUNCH_EVENT" | "ADMOB" +- tag : "LUNCH_EVENT" * LUNCH_EVENT에 해당하는 *Response*가 없으면 Render 해주지 말아주세요 - startDate : "2024-01-01T00:00:00+09:00" - endDate : "2024-12-31T00:00:00+09:00" diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 24ffc13a..eb3d84b5 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -110,8 +110,10 @@ === Event API -* 🆕 link:find-event.html[공지 조회, 2024-02-06] +* 🆕 link:find-event.html[이벤트 조회, 2024-02-06] * 🆕 link:create-event-history.html[이벤트 참여, 2024-02-07] -* 🆕 link:reward-event.html[이벤트 보상, 2024-02-07] \ No newline at end of file +* 🆕 link:reward-event.html[이벤트 보상, 2024-02-07] + +* 🆕 link:reward-admob.html[광고보고 보상 얻기, 2024-02-11] \ No newline at end of file diff --git a/src/docs/asciidoc/reward-admob.adoc b/src/docs/asciidoc/reward-admob.adoc new file mode 100644 index 00000000..5ebed6ac --- /dev/null +++ b/src/docs/asciidoc/reward-admob.adoc @@ -0,0 +1,35 @@ +:reproducible: +== 이벤트 참여 + +=== 요청 + +include::{snippets}/api/v1/admob/reward/http-request.adoc[] + +=== request body + +- "rewardType": String -> "ADMOB_POINT" | "ADMOB_MULTIPLE_POINT" +* ADMOB_POINT : 광고 보고 10 포인트 +* ADMOB_MULTIPLE_POINT : 광고 보고 포인트 2배 이벤트 + +- "randomType" : String -> "FIXED" | "ADMOB_RANDOM" +* FIXED : 고정값 (현재 이것만 사용) +* ADMOB_RANDOM : 랜덤값 (추후 랜덤으로 바뀔 것 고려) +- "uuid" : String -> UUID4 형식만 적용 +- "rewardNumber" : Integer -> 포인트인 경우 10, 투표 포인트 2배 이벤트인 경우 현재 투표 후 받은 포인트 보내줘야함 + +=== 응답 + +include::{snippets}/api/v1/admob/reward/http-response.adoc[] + +=== NOTE + +- Header에 무작위한 UUID4 값을 넣어주세요 +* 예시) IdempotencyKey: 0397b5f3-ecdc-47d6-b5d7-2b1afcf00e87 +- 주의사항 +* 같은 멱등성키를 2번 요청하면, 400번 에러. +- ADMOB +* ADMOB 서버에 SSV(ServerSideVerification) Options의 customData에 입력한 것과 동일한 멱등성 키를 넘겨주세요. + +=== CHANGELOG + +- 2024.02.11 릴리즈 \ No newline at end of file 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 a7bc2921..c2083b41 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 @@ -48,6 +48,7 @@ protected void doFilterInternal( || requestPath.startsWith("/api/v1/admin/login") || requestPath.startsWith("/v2/apple/notifications") || requestPath.startsWith("/v2/google/notifications") + || requestPath.startsWith("/api/v1/admob/verify") || (requestPath.startsWith("/api/v1/auth") && !requestPath.startsWith("/api/v1/auth/token/issue"))) { 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 7e7015de..76fa1f3a 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 @@ -41,7 +41,8 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse || requestPath.startsWith("/api/v1/admin/login") || requestPath.startsWith("/api/v1/auth") || requestPath.startsWith("/v2/apple/notifications") - || requestPath.startsWith("/v2/google/notifications")) { + || requestPath.startsWith("/v2/google/notifications") + || requestPath.startsWith("/api/v1/admob/verify")) { filterChain.doFilter(request, response); return; } diff --git a/src/main/java/com/yello/server/domain/event/controller/EventController.java b/src/main/java/com/yello/server/domain/event/controller/EventController.java index e6a10776..9e86a223 100644 --- a/src/main/java/com/yello/server/domain/event/controller/EventController.java +++ b/src/main/java/com/yello/server/domain/event/controller/EventController.java @@ -27,6 +27,8 @@ import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.val; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -66,7 +68,7 @@ public BaseResponse rewardEvent(@AccessTokenUser User user, } @GetMapping("/v1/admob/verify") - public BaseResponse verifyAdmob(HttpServletRequest request) { + public ResponseEntity verifyAdmob(HttpServletRequest request) { URI uri; try { uri = @@ -76,7 +78,8 @@ public BaseResponse verifyAdmob(HttpServletRequest request) { throw new EventBadRequestException(ADMOB_URI_BAD_REQUEST_EXCEPTION); } eventService.verifyAdmobReward(uri, request); - return BaseResponse.success(VERIFY_ADMOB_SSV_SUCCESS); + + return new ResponseEntity<>(HttpStatus.OK); } @PostMapping("/v1/admob/reward") diff --git a/src/main/java/com/yello/server/domain/event/dto/request/AdmobSsvRequest.java b/src/main/java/com/yello/server/domain/event/dto/request/AdmobSsvRequest.java index eccfe07a..3db850f8 100644 --- a/src/main/java/com/yello/server/domain/event/dto/request/AdmobSsvRequest.java +++ b/src/main/java/com/yello/server/domain/event/dto/request/AdmobSsvRequest.java @@ -33,7 +33,7 @@ public static AdmobSsvRequest of(Map parameters ) { .orElse(0); return AdmobSsvRequest.builder() - .customData(getParameter.apply("customData")) + .customData(getParameter.apply("custom_data")) .signature(getParameter.apply("signature")) .keyId(keyId) .transactionId(getParameter.apply("transaction_id")) diff --git a/src/main/java/com/yello/server/domain/event/entity/EventInstanceReward.java b/src/main/java/com/yello/server/domain/event/entity/EventInstanceReward.java index 73b77619..d707371a 100644 --- a/src/main/java/com/yello/server/domain/event/entity/EventInstanceReward.java +++ b/src/main/java/com/yello/server/domain/event/entity/EventInstanceReward.java @@ -50,7 +50,7 @@ public static EventInstanceReward of(EventInstance eventInstance, EventReward ev .eventInstance(eventInstance) .rewardTag(eventReward.getTag()) .rewardValue(eventReward.getMinRewardValue()) - .rewardTitle(eventReward.getRewardTitle()) + .rewardTitle(String.format(eventReward.getRewardTitle(), eventReward.getMinRewardValue())) .rewardImage(eventReward.getRewardImage()) .build(); } diff --git a/src/main/java/com/yello/server/domain/event/repository/EventRepository.java b/src/main/java/com/yello/server/domain/event/repository/EventRepository.java index 5acbd26a..18177b61 100644 --- a/src/main/java/com/yello/server/domain/event/repository/EventRepository.java +++ b/src/main/java/com/yello/server/domain/event/repository/EventRepository.java @@ -43,5 +43,6 @@ public interface EventRepository { Optional findInstanceByEventHistory(EventHistory eventHistory); EventReward findRewardByTag(String rewardTag); + EventRewardMapping findRewardMappingByEventRewardId(Long eventRewardId); } diff --git a/src/main/java/com/yello/server/domain/event/repository/EventRepositoryImpl.java b/src/main/java/com/yello/server/domain/event/repository/EventRepositoryImpl.java index de72099a..af3c2d6e 100644 --- a/src/main/java/com/yello/server/domain/event/repository/EventRepositoryImpl.java +++ b/src/main/java/com/yello/server/domain/event/repository/EventRepositoryImpl.java @@ -117,6 +117,6 @@ public EventReward findRewardByTag(String rewardTag) { public EventRewardMapping findRewardMappingByEventRewardId(Long eventRewardId) { return Optional.ofNullable(jpaQueryFactory.selectFrom(eventRewardMapping) .where(eventRewardMapping.eventReward.id.eq(eventRewardId)) - .fetchOne()).orElseThrow(() -> new EventNotFoundException(NOT_FOUND_EVENT_REWARD_EXCEPTION)); + .fetchFirst()).orElseThrow(() -> new EventNotFoundException(NOT_FOUND_EVENT_REWARD_EXCEPTION)); } } diff --git a/src/main/java/com/yello/server/domain/event/service/EventService.java b/src/main/java/com/yello/server/domain/event/service/EventService.java index acc6e4d6..a9da86f5 100644 --- a/src/main/java/com/yello/server/domain/event/service/EventService.java +++ b/src/main/java/com/yello/server/domain/event/service/EventService.java @@ -239,6 +239,7 @@ public void verifyAdmobReward(URI uri, HttpServletRequest request) { RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD) .build(); verifier.verify(uri.toString()); + System.out.println(" verify 성공 !!!!!!"); // 2. google이 넘겨준 query 정보 가져오기 AdmobSsvRequest admobRequest = AdmobSsvRequest.of(request.getParameterMap()); diff --git a/src/main/resources/static/docs/user-data-get.html b/src/main/resources/static/docs/user-data-get.html index 1640ec7e..1a5fddac 100644 --- a/src/main/resources/static/docs/user-data-get.html +++ b/src/main/resources/static/docs/user-data-get.html @@ -483,24 +483,6 @@

응답

} -
-
-
HTTP/1.1 200 OK
-Vary: Origin
-Vary: Access-Control-Request-Method
-Vary: Access-Control-Request-Headers
-Content-Type: application/json
-
-{
-  "status" : 200,
-  "message" : "유저 데이터 조회에 성공하였습니다.",
-  "data" : {
-    "tag" : "account-updated-at",
-    "value" : "true|null|2024-01-31"
-  }
-}
-
-

필드 타입

@@ -523,9 +505,6 @@

응답

  • 예시) "false|2024-01-31|2024-01-31"

  • -
  • -

    "updated_at": "YYYY-mm-dd" | null

    -
  • @@ -553,9 +532,6 @@

    CHANGELOG

    • -

      2024.02.10 응답 케이스 추가

      -
    • -
    • 2024.01.30 릴리즈

    • diff --git a/src/test/java/com/yello/server/domain/event/medium/EventControllerTest.java b/src/test/java/com/yello/server/domain/event/medium/EventControllerTest.java index 03ba72f0..63bfe80e 100644 --- a/src/test/java/com/yello/server/domain/event/medium/EventControllerTest.java +++ b/src/test/java/com/yello/server/domain/event/medium/EventControllerTest.java @@ -18,6 +18,7 @@ import com.yello.server.domain.authorization.filter.JwtExceptionFilter; import com.yello.server.domain.authorization.filter.JwtFilter; import com.yello.server.domain.event.controller.EventController; +import com.yello.server.domain.event.dto.request.AdmobRewardRequest; import com.yello.server.domain.event.dto.request.EventJoinRequest; import com.yello.server.domain.event.dto.response.EventResponse; import com.yello.server.domain.event.dto.response.EventRewardResponse; @@ -37,6 +38,7 @@ import java.time.ZonedDateTime; 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; @@ -70,13 +72,13 @@ @DisplayName("Event 컨트롤러에서") class EventControllerTest { - final OperationPreprocessor[] excludeRequestHeaders = new OperationPreprocessor[]{ + final OperationPreprocessor[] excludeRequestHeaders = new OperationPreprocessor[] { prettyPrint(), modifyHeaders().remove("X-CSRF-TOKEN"), modifyHeaders().remove(HttpHeaders.HOST) }; - final OperationPreprocessor[] excludeResponseHeaders = new OperationPreprocessor[]{ + final OperationPreprocessor[] excludeResponseHeaders = new OperationPreprocessor[] { prettyPrint(), modifyHeaders().remove("X-Content-Type-Options"), modifyHeaders().remove("X-XSS-Protection"), @@ -101,6 +103,11 @@ class EventControllerTest { /** * TODO Event* TestUtil 작성 및 연결 필요 */ + @BeforeEach + void init() { + + } + @Test void 이벤트_전체_조회에_성공합니다1() throws Exception { final EventReward ticket = EventReward.builder() @@ -140,7 +147,8 @@ class EventControllerTest { .build(); final EventRandom eventRandom2 = EventRandom.builder() .randomTag("RANDOM") - .probabilityPointList("[{\"x\": 0, \"y\": 0},{ \"x\": 0.8, \"y\": 0.55 }, { \"x\": 1, \"y\": 1 }]") + .probabilityPointList( + "[{\"x\": 0, \"y\": 0},{ \"x\": 0.8, \"y\": 0.55 }, { \"x\": 1, \"y\": 1 }]") .build(); final List rewardList1 = List.of( @@ -251,7 +259,8 @@ class EventControllerTest { .build(); final EventRandom eventRandom2 = EventRandom.builder() .randomTag("RANDOM") - .probabilityPointList("[{\"x\": 0, \"y\": 0},{ \"x\": 0.8, \"y\": 0.55 }, { \"x\": 1, \"y\": 1 }]") + .probabilityPointList( + "[{\"x\": 0, \"y\": 0},{ \"x\": 0.8, \"y\": 0.55 }, { \"x\": 1, \"y\": 1 }]") .build(); final List rewardList2 = List.of( @@ -518,4 +527,43 @@ class EventControllerTest { )) .andExpect(MockMvcResultMatchers.status().isOk()); } + + @Test + void 광고_후_보상에_성공합니다() throws Exception { + + final String idempotencyKey = "87552f7c-9b62-4b12-b567-1bd062b09288"; + + final AdmobRewardRequest request = AdmobRewardRequest.builder() + .rewardType("ADMOB_POINT") + .randomType("FIXED") + .uuid(idempotencyKey) + .rewardNumber(10) + .build(); + + final EventRewardResponse response = EventRewardResponse.builder() + .rewardTag("ADMOB_POINT") + .rewardValue(10L) + .rewardTitle(String.format("%s 포인트를 얻었어요!", 10L)) + .rewardImage("https://storage.googleapis.com/yelloworld/image/ticket-reward.svg") + .build(); + + given(eventService.rewardAdmob(anyLong(), eq(request))) + .willReturn(response); + // when + + // then + mockMvc.perform( + RestDocumentationRequestBuilders.post("/api/v1/admob/reward") + .with(csrf().asHeader()) + .header(HttpHeaders.AUTHORIZATION, "Bearer your-access-token") + .header(ConstantUtil.IdempotencyKeyHeader, idempotencyKey) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andDo(print()) + .andDo(document("api/v1/admob/reward", + Preprocessors.preprocessRequest(excludeRequestHeaders), + Preprocessors.preprocessResponse(excludeResponseHeaders) + )) + .andExpect(MockMvcResultMatchers.status().isOk()); + } }