diff --git a/.gitignore b/.gitignore index 29c585e5..8ac8c49c 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,6 @@ monitoring/prometheus/volume monitoring/grafana src/main/resources/application-local.yml + +### QueryDSL ### +src/main/generated/ diff --git a/build.gradle b/build.gradle index 267afcb6..67629786 100644 --- a/build.gradle +++ b/build.gradle @@ -6,11 +6,10 @@ buildscript { plugins { id 'java' - id 'org.springframework.boot' version '2.7.4' - id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id 'org.springframework.boot' version '3.2.2' + id 'io.spring.dependency-management' version '1.1.4' id "org.asciidoctor.jvm.convert" version "3.3.2" id 'jacoco' - id "com.ewerk.gradle.plugins.querydsl" version "1.0.10" } group = 'com.yello' @@ -39,13 +38,16 @@ repositories { } dependencies { + // Properties Migrator + runtimeOnly "org.springframework.boot:spring-boot-properties-migrator" + implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' // Repositories implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.amqp:spring-rabbit:2.3.12' + implementation 'org.springframework.amqp:spring-rabbit:3.1.1' runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j:8.0.31' @@ -85,7 +87,7 @@ dependencies { asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' testImplementation 'org.springframework.security:spring-security-test' - testImplementation 'org.mockito:mockito-inline' + testImplementation 'org.mockito:mockito-inline:5.2.0' // jwt decode implementation 'org.bouncycastle:bcprov-jdk15on:1.69' @@ -97,9 +99,12 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-aop' // querydsl - implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" - implementation "com.querydsl:querydsl-apt:${queryDslVersion}" implementation "com.querydsl:querydsl-core:${queryDslVersion}" + annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta" + implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" + implementation "jakarta.annotation:jakarta.annotation-api" + implementation "com.querydsl:querydsl-codegen:${queryDslVersion}" } asciidoctor { @@ -142,21 +147,6 @@ jacocoTestReport { // finalizedBy 'jacocoTestCoverageVerification' } -// QueryDsl -def querydslDir = "$buildDir/generated/querydsl" - -querydsl { - jpa = true - querydslSourcesDir = querydslDir -} -sourceSets { - main.java.srcDir querydslDir -} - -compileQuerydsl { - options.annotationProcessorPath = configurations.querydsl -} - //jacocoTestCoverageVerification { // violationRules { // rule { diff --git a/src/docs/asciidoc/find-event.adoc b/src/docs/asciidoc/find-event.adoc new file mode 100644 index 00000000..93f646ec --- /dev/null +++ b/src/docs/asciidoc/find-event.adoc @@ -0,0 +1,37 @@ +:reproducible: +== 공지 조회 + +=== 요청 + +include::{snippets}/api/v1/event/1/http-request.adoc[] + +=== 응답 + +include::{snippets}/api/v1/event/1/http-response.adoc[] + +include::{snippets}/api/v1/event/2/http-response.adoc[] + +include::{snippets}/api/v1/event/3/http-response.adoc[] + +=== 주의 + +- data: *Response*[] +- *Response* +- tag : "LUNCH_EVENT" | "ADMOB" +* LUNCH_EVENT에 해당하는 *Response*가 없으면 Render 해주지 말아주세요 +- startDate : "2024-01-01T00:00:00+09:00" +- endDate : "2024-12-31T00:00:00+09:00" +- title : "점심 시간 깜짝 선물!" +- subTitle : "평일 12-14시 최대 1회까지 참여 가능" +- animationList : [{...json1...}, {...json2...}] +- eventReward: *EventReward* | null +* 해당 필드가 **null**일 시, 이벤트 보여주지 않도록 해주세요. + +=== NOTE + +- *!* LUNCH_EVENT에 해당하는 Response가 없거나, LUNCH_EVENT Response의 eventReward가 null이면, 메인화면 접속시, 이벤트 화면을 띄워주지마세요. +- 이벤트 참여 요청, 이벤트 보상 반환 API 문서 작성중.. + +=== CHANGELOG + +- 2024.02.06 릴리즈 \ No newline at end of file diff --git a/src/docs/asciidoc/find-friend-votes-v2.adoc b/src/docs/asciidoc/find-friend-votes-v2.adoc index a201d4e7..c5694126 100644 --- a/src/docs/asciidoc/find-friend-votes-v2.adoc +++ b/src/docs/asciidoc/find-friend-votes-v2.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v2/vote/friend/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v2/vote/friend/request-parameters.adoc[] +include::{snippets}/api/v2/vote/friend/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/find-friend-votes.adoc b/src/docs/asciidoc/find-friend-votes.adoc index 28379cfd..f964a24b 100644 --- a/src/docs/asciidoc/find-friend-votes.adoc +++ b/src/docs/asciidoc/find-friend-votes.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/vote/findAllFriendVotes/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v1/vote/findAllFriendVotes/request-parameters.adoc[] +include::{snippets}/api/v1/vote/findAllFriendVotes/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/find-friends.adoc b/src/docs/asciidoc/find-friends.adoc index c37ac0d7..6e442a68 100644 --- a/src/docs/asciidoc/find-friends.adoc +++ b/src/docs/asciidoc/find-friends.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/friend/findAllFriend/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v1/friend/findAllFriend/request-parameters.adoc[] +include::{snippets}/api/v1/friend/findAllFriend/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/find-group-friends.adoc b/src/docs/asciidoc/find-group-friends.adoc index 03d9ddce..d7d17e51 100644 --- a/src/docs/asciidoc/find-group-friends.adoc +++ b/src/docs/asciidoc/find-group-friends.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/friend/findAllRecommendSchoolFriends/http-request.ado === 요청 파라미터 -include::{snippets}/api/v1/friend/findAllRecommendSchoolFriends/request-parameters.adoc[] +include::{snippets}/api/v1/friend/findAllRecommendSchoolFriends/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/find-kakao-friends.adoc b/src/docs/asciidoc/find-kakao-friends.adoc index 21130236..d253f5d3 100644 --- a/src/docs/asciidoc/find-kakao-friends.adoc +++ b/src/docs/asciidoc/find-kakao-friends.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/friend/findAllRecommendKakaoFriends/http-request.adoc === 요청 파라미터 -include::{snippets}/api/v1/friend/findAllRecommendKakaoFriends/request-parameters.adoc[] +include::{snippets}/api/v1/friend/findAllRecommendKakaoFriends/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/find-onboarding-friends.adoc b/src/docs/asciidoc/find-onboarding-friends.adoc index 3a8c9a8d..92a41136 100644 --- a/src/docs/asciidoc/find-onboarding-friends.adoc +++ b/src/docs/asciidoc/find-onboarding-friends.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/auth/findOnBoardingFriends/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v1/auth/findOnBoardingFriends/request-parameters.adoc[] +include::{snippets}/api/v1/auth/findOnBoardingFriends/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/find-votes.adoc b/src/docs/asciidoc/find-votes.adoc index 3026b251..be1cfc2e 100644 --- a/src/docs/asciidoc/find-votes.adoc +++ b/src/docs/asciidoc/find-votes.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/vote/findAllMyVotes/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v1/vote/findAllMyVotes/request-parameters.adoc[] +include::{snippets}/api/v1/vote/findAllMyVotes/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 41ca7251..d2d6d8f3 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -57,7 +57,7 @@ * link:find-friend-votes.html[친구 투표 전체 조회하기, 2024-01-09] -* ⬆️ link:find-friend-votes-v2.html[친구 투표 전체 조회하기 v2, 2024-01-30] +* 🆕 link:find-friend-votes-v2.html[친구 투표 전체 조회하기 v2, 2024-01-30] * link:get-unread-vote.html[읽지 않은 쪽지 개수 조회하기] @@ -106,4 +106,8 @@ === Notice API -* 🆕 link:find-notice.html[공지 조회, 2024-01-29] \ No newline at end of file +* 🆕 link:find-notice.html[공지 조회, 2024-01-29] + +=== Event API + +* 🆕 link:find-event.html[공지 조회, 2024-02-06] \ No newline at end of file diff --git a/src/docs/asciidoc/reissue-token.adoc b/src/docs/asciidoc/reissue-token.adoc index 2ce80986..6c9edfb3 100644 --- a/src/docs/asciidoc/reissue-token.adoc +++ b/src/docs/asciidoc/reissue-token.adoc @@ -1,8 +1,6 @@ :reproducible: == 토큰 재발급 -operation::api/v1/auth/reIssueToken[snippets='http-request,http-response'] - === 요청 include::{snippets}/api/v1/auth/reIssueToken/http-request.adoc[] diff --git a/src/docs/asciidoc/search-department.adoc b/src/docs/asciidoc/search-department.adoc index 670573f6..5b5864af 100644 --- a/src/docs/asciidoc/search-department.adoc +++ b/src/docs/asciidoc/search-department.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/auth/findAllUnivDepartmentName/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v1/auth/findAllUnivDepartmentName/request-parameters.adoc[] +include::{snippets}/api/v1/auth/findAllUnivDepartmentName/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/search-friend.adoc b/src/docs/asciidoc/search-friend.adoc index 3db6e3ee..e23dce32 100644 --- a/src/docs/asciidoc/search-friend.adoc +++ b/src/docs/asciidoc/search-friend.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/friend/searchFriend/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v1/friend/searchFriend/request-parameters.adoc[] +include::{snippets}/api/v1/friend/searchFriend/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/search-high-class.adoc b/src/docs/asciidoc/search-high-class.adoc index 6f0ce4b4..56bcf491 100644 --- a/src/docs/asciidoc/search-high-class.adoc +++ b/src/docs/asciidoc/search-high-class.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/auth/findGroupIdByName/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v1/auth/findGroupIdByName/request-parameters.adoc[] +include::{snippets}/api/v1/auth/findGroupIdByName/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/search-high-name.adoc b/src/docs/asciidoc/search-high-name.adoc index f82fb744..56d3356f 100644 --- a/src/docs/asciidoc/search-high-name.adoc +++ b/src/docs/asciidoc/search-high-name.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/auth/findAllHighSchoolName/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v1/auth/findAllHighSchoolName/request-parameters.adoc[] +include::{snippets}/api/v1/auth/findAllHighSchoolName/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/search-school.adoc b/src/docs/asciidoc/search-school.adoc index 80452fa7..ae12d1b8 100644 --- a/src/docs/asciidoc/search-school.adoc +++ b/src/docs/asciidoc/search-school.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/auth/findAllUnivName/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v1/auth/findAllUnivName/request-parameters.adoc[] +include::{snippets}/api/v1/auth/findAllUnivName/query-parameters.adoc[] === 응답 diff --git a/src/docs/asciidoc/validate-yelloid.adoc b/src/docs/asciidoc/validate-yelloid.adoc index 572c7d30..0de66e04 100644 --- a/src/docs/asciidoc/validate-yelloid.adoc +++ b/src/docs/asciidoc/validate-yelloid.adoc @@ -7,7 +7,7 @@ include::{snippets}/api/v1/auth/getYelloIdValidation/http-request.adoc[] === 요청 파라미터 -include::{snippets}/api/v1/auth/getYelloIdValidation/request-parameters.adoc[] +include::{snippets}/api/v1/auth/getYelloIdValidation/query-parameters.adoc[] === 응답 diff --git a/src/main/java/com/yello/server/domain/admin/controller/AdminController.java b/src/main/java/com/yello/server/domain/admin/controller/AdminController.java index 51bc57c2..631f5899 100644 --- a/src/main/java/com/yello/server/domain/admin/controller/AdminController.java +++ b/src/main/java/com/yello/server/domain/admin/controller/AdminController.java @@ -6,7 +6,12 @@ import static com.yello.server.global.common.SuccessCode.DELETE_COOLDOWN_ADMIN_SUCCESS; import static com.yello.server.global.common.SuccessCode.DELETE_QUESTION_ADMIN_SUCCESS; import static com.yello.server.global.common.SuccessCode.DELETE_USER_ADMIN_SUCCESS; +import static com.yello.server.global.common.SuccessCode.EVENT_CREATE_ADMIN_SUCCESS; +import static com.yello.server.global.common.SuccessCode.EVENT_REWARD_CREATE_ADMIN_SUCCESS; import static com.yello.server.global.common.SuccessCode.LOGIN_USER_ADMIN_SUCCESS; +import static com.yello.server.global.common.SuccessCode.NOTICE_CREATE_ADMIN_SUCCESS; +import static com.yello.server.global.common.SuccessCode.NOTICE_READ_ADMIN_SUCCESS; +import static com.yello.server.global.common.SuccessCode.NOTICE_UPDATE_DETAIL_ADMIN_SUCCESS; import static com.yello.server.global.common.SuccessCode.READ_COOLDOWN_ADMIN_SUCCESS; import static com.yello.server.global.common.SuccessCode.READ_QUESTION_ADMIN_SUCCESS; import static com.yello.server.global.common.SuccessCode.READ_QUESTION_DETAIL_ADMIN_SUCCESS; @@ -17,7 +22,11 @@ import static com.yello.server.global.common.factory.PaginationFactory.createPageableByNameSortDescLimitTen; import static com.yello.server.global.common.factory.PaginationFactory.createPageableLimitTen; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.yello.server.domain.admin.dto.request.AdminEventCreateRequest; +import com.yello.server.domain.admin.dto.request.AdminEventRewardCreateRequest; import com.yello.server.domain.admin.dto.request.AdminLoginRequest; +import com.yello.server.domain.admin.dto.request.AdminNoticeCreateRequest; import com.yello.server.domain.admin.dto.request.AdminQuestionVoteRequest; import com.yello.server.domain.admin.dto.request.AdminUserDetailRequest; import com.yello.server.domain.admin.dto.response.AdminConfigurationResponse; @@ -30,12 +39,14 @@ import com.yello.server.domain.admin.dto.response.AdminUserResponse; import com.yello.server.domain.admin.entity.AdminConfigurationType; import com.yello.server.domain.admin.service.AdminService; +import com.yello.server.domain.notice.entity.Notice; import com.yello.server.domain.user.entity.User; 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 com.yello.server.infrastructure.firebase.dto.request.NotificationCustomMessage; import com.yello.server.infrastructure.firebase.service.NotificationService; +import java.util.List; import javax.annotation.Nullable; import lombok.RequiredArgsConstructor; import lombok.val; @@ -168,4 +179,38 @@ public BaseResponse postConfigurations( return BaseResponse.success(CONFIGURATION_UPDATE_ADMIN_SUCCESS, data); } + + @GetMapping("/notice") + public BaseResponse> getNotices(@AccessTokenUser User user) { + val data = adminService.getNotices(user.getId()); + return BaseResponse.success(NOTICE_READ_ADMIN_SUCCESS, data); + } + + @PostMapping("/notice") + public BaseResponse createNotice(@AccessTokenUser User user, + @RequestBody AdminNoticeCreateRequest request) { + val data = adminService.createNotice(user.getId(), request); + return BaseResponse.success(NOTICE_CREATE_ADMIN_SUCCESS, data); + } + + @PostMapping("/notice/{id}") + public BaseResponse updateNotice(@AccessTokenUser User user, @PathVariable("id") Long noticeId, + @RequestBody AdminNoticeCreateRequest request) { + val data = adminService.updateNotice(user.getId(), noticeId, request); + return BaseResponse.success(NOTICE_UPDATE_DETAIL_ADMIN_SUCCESS, data); + } + + @PostMapping("/event") + public BaseResponse createEvent(@AccessTokenUser User user, + @RequestBody AdminEventCreateRequest request) throws JsonProcessingException { + val data = adminService.createEvent(user.getId(), request); + return BaseResponse.success(EVENT_CREATE_ADMIN_SUCCESS, data); + } + + @PostMapping("/event/reward") + public BaseResponse createEventReward(@AccessTokenUser User user, + @RequestBody AdminEventRewardCreateRequest request) { + val data = adminService.createEventReward(user.getId(), request); + return BaseResponse.success(EVENT_REWARD_CREATE_ADMIN_SUCCESS, data); + } } diff --git a/src/main/java/com/yello/server/domain/admin/dto/request/AdminEventCreateRequest.java b/src/main/java/com/yello/server/domain/admin/dto/request/AdminEventCreateRequest.java new file mode 100644 index 00000000..058ae120 --- /dev/null +++ b/src/main/java/com/yello/server/domain/admin/dto/request/AdminEventCreateRequest.java @@ -0,0 +1,34 @@ +package com.yello.server.domain.admin.dto.request; + +import com.yello.server.domain.event.entity.EventRewardRandomType; +import com.yello.server.domain.event.entity.EventType; +import java.time.OffsetTime; +import java.util.List; + +public record AdminEventCreateRequest( + EventType tag, + String startDate, + String endDate, + String title, + String subTitle, + List animationList, + List eventReward +) { + + public record EventRewardVO( + OffsetTime startTime, + OffsetTime endTime, + Long rewardCount, + List eventRewardItem + ) { + + } + + public record EventRewardItemVO( + String tag, + Integer eventRewardProbability, + EventRewardRandomType randomTag + ) { + + } +} diff --git a/src/main/java/com/yello/server/domain/admin/dto/request/AdminEventRewardCreateRequest.java b/src/main/java/com/yello/server/domain/admin/dto/request/AdminEventRewardCreateRequest.java new file mode 100644 index 00000000..46334966 --- /dev/null +++ b/src/main/java/com/yello/server/domain/admin/dto/request/AdminEventRewardCreateRequest.java @@ -0,0 +1,11 @@ +package com.yello.server.domain.admin.dto.request; + +public record AdminEventRewardCreateRequest( + String tag, + Long maxRewardValue, + Long minRewardValue, + String title, + String image +) { + +} diff --git a/src/main/java/com/yello/server/domain/admin/dto/request/AdminNoticeCreateRequest.java b/src/main/java/com/yello/server/domain/admin/dto/request/AdminNoticeCreateRequest.java new file mode 100644 index 00000000..7ba27af0 --- /dev/null +++ b/src/main/java/com/yello/server/domain/admin/dto/request/AdminNoticeCreateRequest.java @@ -0,0 +1,13 @@ +package com.yello.server.domain.admin.dto.request; + +public record AdminNoticeCreateRequest( + String imageUrl, + String redirectUrl, + String startDate, + String endDate, + Boolean isAvailable, + String tag, + String title +) { + +} diff --git a/src/main/java/com/yello/server/domain/admin/dto/request/AdminUserDetailRequest.java b/src/main/java/com/yello/server/domain/admin/dto/request/AdminUserDetailRequest.java index a985c470..ed743ecd 100644 --- a/src/main/java/com/yello/server/domain/admin/dto/request/AdminUserDetailRequest.java +++ b/src/main/java/com/yello/server/domain/admin/dto/request/AdminUserDetailRequest.java @@ -4,7 +4,7 @@ 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 javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; public record AdminUserDetailRequest( @JsonIgnore Long id, diff --git a/src/main/java/com/yello/server/domain/admin/entity/AdminConfiguration.java b/src/main/java/com/yello/server/domain/admin/entity/AdminConfiguration.java index 8eacd32b..a88c093b 100644 --- a/src/main/java/com/yello/server/domain/admin/entity/AdminConfiguration.java +++ b/src/main/java/com/yello/server/domain/admin/entity/AdminConfiguration.java @@ -1,11 +1,11 @@ package com.yello.server.domain.admin.entity; -import javax.persistence.Column; -import javax.persistence.Convert; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/src/main/java/com/yello/server/domain/admin/entity/AdminConfigurationTypeConverter.java b/src/main/java/com/yello/server/domain/admin/entity/AdminConfigurationTypeConverter.java index 413c65fa..5ff6c3a5 100644 --- a/src/main/java/com/yello/server/domain/admin/entity/AdminConfigurationTypeConverter.java +++ b/src/main/java/com/yello/server/domain/admin/entity/AdminConfigurationTypeConverter.java @@ -1,7 +1,7 @@ package com.yello.server.domain.admin.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter diff --git a/src/main/java/com/yello/server/domain/admin/entity/UserAdmin.java b/src/main/java/com/yello/server/domain/admin/entity/UserAdmin.java index 5119d364..c1f9b3e6 100644 --- a/src/main/java/com/yello/server/domain/admin/entity/UserAdmin.java +++ b/src/main/java/com/yello/server/domain/admin/entity/UserAdmin.java @@ -2,17 +2,20 @@ import com.yello.server.domain.user.entity.User; import com.yello.server.global.common.dto.AuditingTimeEntity; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; @Getter @Entity @@ -24,7 +27,8 @@ public class UserAdmin extends AuditingTimeEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(fetch = FetchType.LAZY) + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "userId") + @OnDelete(action = OnDeleteAction.CASCADE) private User user; } diff --git a/src/main/java/com/yello/server/domain/admin/repository/AdminRepository.java b/src/main/java/com/yello/server/domain/admin/repository/AdminRepository.java new file mode 100644 index 00000000..758b6e05 --- /dev/null +++ b/src/main/java/com/yello/server/domain/admin/repository/AdminRepository.java @@ -0,0 +1,23 @@ +package com.yello.server.domain.admin.repository; + +import com.yello.server.domain.event.entity.Event; +import com.yello.server.domain.event.entity.EventReward; +import com.yello.server.domain.event.entity.EventRewardMapping; +import com.yello.server.domain.event.entity.EventTime; + +public interface AdminRepository { + + Event save(Event newEvent); + + EventTime save(EventTime newEventTime); + + EventReward save(EventReward newEventReward); + + EventRewardMapping save(EventRewardMapping newEventRewardMapping); + + Event getById(Long eventId); + + EventTime getEventTimeById(Long eventTimeId); + + EventReward getByTag(String tag); +} diff --git a/src/main/java/com/yello/server/domain/admin/repository/AdminRepositoryImpl.java b/src/main/java/com/yello/server/domain/admin/repository/AdminRepositoryImpl.java new file mode 100644 index 00000000..e5b404b2 --- /dev/null +++ b/src/main/java/com/yello/server/domain/admin/repository/AdminRepositoryImpl.java @@ -0,0 +1,77 @@ +package com.yello.server.domain.admin.repository; + +import static com.yello.server.domain.event.entity.QEvent.event; +import static com.yello.server.domain.event.entity.QEventTime.eventTime; +import static com.yello.server.global.common.ErrorCode.EVENT_NOT_FOUND_EXCEPTION; +import static com.yello.server.global.common.ErrorCode.EVENT_REWARD_NOT_FOUND_EXCEPTION; +import static com.yello.server.global.common.ErrorCode.EVENT_TIME_NOT_FOUND_EXCEPTION; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import com.yello.server.domain.admin.exception.UserAdminNotFoundException; +import com.yello.server.domain.event.entity.Event; +import com.yello.server.domain.event.entity.EventReward; +import com.yello.server.domain.event.entity.EventRewardMapping; +import com.yello.server.domain.event.entity.EventTime; +import com.yello.server.domain.event.repository.EventJpaRepository; +import com.yello.server.domain.event.repository.EventRewardJpaRepository; +import com.yello.server.domain.event.repository.EventRewardMappingJpaRepository; +import com.yello.server.domain.event.repository.EventTimeJpaRepository; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class AdminRepositoryImpl implements AdminRepository { + + private final EventJpaRepository eventJpaRepository; + private final EventRewardJpaRepository eventRewardJpaRepository; + private final EventRewardMappingJpaRepository eventRewardMappingJpaRepository; + private final EventTimeJpaRepository eventTimeJpaRepository; + private final JPAQueryFactory jpaQueryFactory; + + @Override + public Event save(Event newEvent) { + return eventJpaRepository.save(newEvent); + } + + @Override + public EventTime save(EventTime newEventTime) { + return eventTimeJpaRepository.save(newEventTime); + } + + @Override + public EventReward save(EventReward newEventReward) { + return eventRewardJpaRepository.save(newEventReward); + } + + @Override + public EventRewardMapping save(EventRewardMapping newEventRewardMapping) { + return eventRewardMappingJpaRepository.save(newEventRewardMapping); + } + + @Override + public Event getById(Long eventId) { + return Optional.ofNullable(jpaQueryFactory.selectFrom(event) + .where(event.id.eq(eventId)) + .fetchFirst()) + .orElseThrow(() -> new UserAdminNotFoundException(EVENT_NOT_FOUND_EXCEPTION)); + } + + @Override + public EventTime getEventTimeById(Long eventTimeId) { + return Optional.ofNullable(jpaQueryFactory.selectFrom(eventTime) + .where(eventTime.id.eq(eventTimeId)) + .fetchFirst()) + .orElseThrow(() -> new UserAdminNotFoundException(EVENT_TIME_NOT_FOUND_EXCEPTION)); + } + + /** + * findByEnum을 QueryDSL을 이용하여 조회시 오류가 발생하여 JPA로 구현한다. + */ + @Override + public EventReward getByTag(String tag) { + return eventRewardJpaRepository.findByTag(tag) + .orElseThrow(() -> new UserAdminNotFoundException(EVENT_REWARD_NOT_FOUND_EXCEPTION)); + } +} diff --git a/src/main/java/com/yello/server/domain/admin/service/AdminService.java b/src/main/java/com/yello/server/domain/admin/service/AdminService.java index 5c90b776..a0965c8e 100644 --- a/src/main/java/com/yello/server/domain/admin/service/AdminService.java +++ b/src/main/java/com/yello/server/domain/admin/service/AdminService.java @@ -3,12 +3,20 @@ import static com.yello.server.domain.admin.entity.AdminConfigurationType.ADMIN_SITE_PASSWORD; import static com.yello.server.global.common.ErrorCode.ADMIN_CONFIGURATION_NOT_FOUND_EXCEPTION; import static com.yello.server.global.common.ErrorCode.DEVICE_TOKEN_CONFLICT_USER_EXCEPTION; +import static com.yello.server.global.common.ErrorCode.PROBABILITY_BAD_REQUEST_EXCEPTION; import static com.yello.server.global.common.ErrorCode.USER_ADMIN_BAD_REQUEST_EXCEPTION; import static com.yello.server.global.common.ErrorCode.USER_ADMIN_NOT_FOUND_EXCEPTION; import static com.yello.server.global.common.ErrorCode.UUID_CONFLICT_USER_EXCEPTION; import static com.yello.server.global.common.ErrorCode.YELLOID_CONFLICT_USER_EXCEPTION; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yello.server.domain.admin.dto.request.AdminEventCreateRequest; +import com.yello.server.domain.admin.dto.request.AdminEventCreateRequest.EventRewardItemVO; +import com.yello.server.domain.admin.dto.request.AdminEventCreateRequest.EventRewardVO; +import com.yello.server.domain.admin.dto.request.AdminEventRewardCreateRequest; import com.yello.server.domain.admin.dto.request.AdminLoginRequest; +import com.yello.server.domain.admin.dto.request.AdminNoticeCreateRequest; import com.yello.server.domain.admin.dto.request.AdminQuestionVoteRequest; import com.yello.server.domain.admin.dto.request.AdminUserDetailRequest; import com.yello.server.domain.admin.dto.response.AdminConfigurationResponse; @@ -27,10 +35,18 @@ import com.yello.server.domain.admin.exception.UserAdminBadRequestException; import com.yello.server.domain.admin.exception.UserAdminNotFoundException; import com.yello.server.domain.admin.repository.AdminConfigurationRepository; +import com.yello.server.domain.admin.repository.AdminRepository; import com.yello.server.domain.admin.repository.UserAdminRepository; import com.yello.server.domain.authorization.service.AuthManager; import com.yello.server.domain.cooldown.entity.Cooldown; import com.yello.server.domain.cooldown.repository.CooldownRepository; +import com.yello.server.domain.event.entity.Event; +import com.yello.server.domain.event.entity.EventReward; +import com.yello.server.domain.event.entity.EventRewardMapping; +import com.yello.server.domain.event.entity.EventTime; +import com.yello.server.domain.notice.entity.Notice; +import com.yello.server.domain.notice.entity.NoticeType; +import com.yello.server.domain.notice.repository.NoticeRepository; import com.yello.server.domain.question.entity.Question; import com.yello.server.domain.question.repository.QuestionRepository; import com.yello.server.domain.user.entity.Gender; @@ -41,6 +57,8 @@ import com.yello.server.domain.vote.entity.Vote; import com.yello.server.domain.vote.repository.VoteRepository; import com.yello.server.global.common.dto.EmptyObject; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -56,8 +74,11 @@ public class AdminService { private final AdminConfigurationRepository adminConfigurationRepository; + private final AdminRepository adminRepository; private final AuthManager authManager; private final CooldownRepository cooldownRepository; + private final NoticeRepository noticeRepository; + private final ObjectMapper objectMapper; private final QuestionRepository questionRepository; private final UserAdminRepository userAdminRepository; private final UserManager userManager; @@ -321,4 +342,135 @@ public EmptyObject updateConfigurations(Long adminId, AdminConfigurationType tag return EmptyObject.builder().build(); } + + public List getNotices(Long adminId) { + // exception + final User admin = userRepository.getById(adminId); + userAdminRepository.getByUser(admin); + + final List noticeList = noticeRepository.findAll(); + + return noticeList; + } + + @Transactional + public EmptyObject createNotice(Long adminId, AdminNoticeCreateRequest request) { + // exception + final User admin = userRepository.getById(adminId); + userAdminRepository.getByUser(admin); + + ZonedDateTime startDate = ZonedDateTime.parse(request.startDate(), DateTimeFormatter.ISO_OFFSET_DATE_TIME); + ZonedDateTime endDate = ZonedDateTime.parse(request.endDate(), DateTimeFormatter.ISO_OFFSET_DATE_TIME); + final NoticeType tag = NoticeType.fromCode(request.tag()); + + final Notice notice = Notice.builder() + .imageUrl(request.imageUrl()) + .redirectUrl(request.redirectUrl()) + .startDate(startDate) + .endDate(endDate) + .isAvailable(true) + .tag(tag) + .title(request.title()) + .build(); + + noticeRepository.save(notice); + + return EmptyObject.builder().build(); + } + + @Transactional + public EmptyObject updateNotice(Long adminId, Long noticeId, AdminNoticeCreateRequest request) { + // exception + final User admin = userRepository.getById(adminId); + userAdminRepository.getByUser(admin); + final Notice notice = noticeRepository.getById(noticeId); + + ZonedDateTime startDate = ZonedDateTime.parse(request.startDate(), DateTimeFormatter.ISO_OFFSET_DATE_TIME); + ZonedDateTime endDate = ZonedDateTime.parse(request.endDate(), DateTimeFormatter.ISO_OFFSET_DATE_TIME); + final NoticeType tag = NoticeType.fromCode(request.tag()); + + noticeRepository.update(Notice.builder() + .id(notice.getId()) + .imageUrl(request.imageUrl()) + .redirectUrl(request.redirectUrl()) + .startDate(startDate) + .endDate(endDate) + .isAvailable(request.isAvailable()) + .tag(tag) + .title(request.title()) + .build()); + + return EmptyObject.builder().build(); + } + + @Transactional + public EmptyObject createEvent(Long adminId, AdminEventCreateRequest request) throws JsonProcessingException { + // exception + final User admin = userRepository.getById(adminId); + userAdminRepository.getByUser(admin); + + for (EventRewardVO vo : request.eventReward()) { + int sumOfProbability = 0; + + for (EventRewardItemVO itemVO : vo.eventRewardItem()) { + sumOfProbability += itemVO.eventRewardProbability(); + } + + if (sumOfProbability != 100) { + throw new UserAdminBadRequestException(PROBABILITY_BAD_REQUEST_EXCEPTION); + } + } + + // logic + String animationString = objectMapper.writeValueAsString(request.animationList()); + + final Event newEvent = adminRepository.save(Event.builder() + .tag(request.tag()) + .startDate(ZonedDateTime.parse(request.startDate(), DateTimeFormatter.ISO_OFFSET_DATE_TIME)) + .endDate(ZonedDateTime.parse(request.endDate(), DateTimeFormatter.ISO_OFFSET_DATE_TIME)) + .title(request.title()) + .subTitle(request.subTitle()) + .animation(animationString) + .build()); + + request.eventReward().forEach((eventRewardVO) -> { + final EventTime newEventTime = adminRepository.save(EventTime.builder() + .event(newEvent) + .startTime(eventRewardVO.startTime()) + .endTime(eventRewardVO.endTime()) + .rewardCount(eventRewardVO.rewardCount()) + .build()); + + eventRewardVO.eventRewardItem().forEach(eventRewardItemVO -> { + final EventReward eventReward = adminRepository.getByTag(eventRewardItemVO.tag()); + + adminRepository.save(EventRewardMapping.builder() + .eventTime(newEventTime) + .eventReward(eventReward) + .eventRewardProbability(eventRewardItemVO.eventRewardProbability()) + .randomTag(eventRewardItemVO.randomTag()) + .build()); + }); + }); + + return EmptyObject.builder().build(); + } + + @Transactional + public EmptyObject createEventReward(Long adminId, AdminEventRewardCreateRequest request) { + // exception + final User admin = userRepository.getById(adminId); + userAdminRepository.getByUser(admin); + + // login + adminRepository.save(EventReward.builder() + .tag(request.tag()) + .maxRewardValue(request.maxRewardValue()) + .minRewardValue(request.minRewardValue()) + .title(request.title()) + .image(request.image()) + .build()); + + return EmptyObject.builder().build(); + } } diff --git a/src/main/java/com/yello/server/domain/authorization/configuration/SecurityConfiguration.java b/src/main/java/com/yello/server/domain/authorization/configuration/SecurityConfiguration.java index ad06a64a..14bc887d 100644 --- a/src/main/java/com/yello/server/domain/authorization/configuration/SecurityConfiguration.java +++ b/src/main/java/com/yello/server/domain/authorization/configuration/SecurityConfiguration.java @@ -11,7 +11,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; @@ -20,32 +20,36 @@ @Configuration @EnableWebSecurity @RequiredArgsConstructor -@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) +@EnableMethodSecurity(securedEnabled = true) public class SecurityConfiguration { private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint; - private final UserRepository userRepository; private final TokenProvider tokenProvider; + private final UserRepository userRepository; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { return httpSecurity - .httpBasic().disable() - .csrf().disable() - .cors() - .and() - .authorizeRequests() - .antMatchers("/api/v1/auth/oauth", "/api/v1/auth/signup").permitAll() - .antMatchers("/api/*").authenticated() - .and() - .sessionManagement() - .sessionCreationPolicy(STATELESS) - .and() - .exceptionHandling() - .authenticationEntryPoint(customAuthenticationEntryPoint) - .and() - .addFilterBefore(new JwtFilter(userRepository), - UsernamePasswordAuthenticationFilter.class) + .httpBasic(httpSecurityHttpBasicConfigurer -> { + httpSecurityHttpBasicConfigurer.disable(); + }) + .csrf(httpSecurityCsrfConfigurer -> { + httpSecurityCsrfConfigurer.disable(); + }) + .cors(httpSecurityCorsConfigurer -> { + httpSecurityCorsConfigurer.disable(); + }) + .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> { + authorizationManagerRequestMatcherRegistry + .anyRequest().permitAll(); + }) + .sessionManagement(httpSecuritySessionManagementConfigurer -> { + httpSecuritySessionManagementConfigurer.sessionCreationPolicy(STATELESS); + }) + .exceptionHandling(httpSecurityExceptionHandlingConfigurer -> { + httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint(customAuthenticationEntryPoint); + }) + .addFilterBefore(new JwtFilter(userRepository), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new JwtExceptionFilter(tokenProvider), JwtFilter.class) .addFilterBefore(new ExceptionHandlerFilter(), JwtExceptionFilter.class) .build(); 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 93df7e50..f1d68052 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 @@ -25,8 +25,8 @@ import com.yello.server.global.common.annotation.ServiceToken; import com.yello.server.global.common.dto.BaseResponse; import com.yello.server.infrastructure.slack.annotation.SlackSignUpNotification; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import lombok.val; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/com/yello/server/domain/authorization/dto/request/OnBoardingFriendRequest.java b/src/main/java/com/yello/server/domain/authorization/dto/request/OnBoardingFriendRequest.java index 1c2bfacc..106d6bc2 100644 --- a/src/main/java/com/yello/server/domain/authorization/dto/request/OnBoardingFriendRequest.java +++ b/src/main/java/com/yello/server/domain/authorization/dto/request/OnBoardingFriendRequest.java @@ -1,7 +1,7 @@ package com.yello.server.domain.authorization.dto.request; +import jakarta.validation.constraints.NotNull; import java.util.List; -import javax.validation.constraints.NotNull; import lombok.Builder; @Builder diff --git a/src/main/java/com/yello/server/domain/authorization/dto/request/SignUpRequest.java b/src/main/java/com/yello/server/domain/authorization/dto/request/SignUpRequest.java index e9dbaaa5..a89088f6 100644 --- a/src/main/java/com/yello/server/domain/authorization/dto/request/SignUpRequest.java +++ b/src/main/java/com/yello/server/domain/authorization/dto/request/SignUpRequest.java @@ -2,9 +2,9 @@ import com.yello.server.domain.user.entity.Gender; import com.yello.server.domain.user.entity.Social; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; import java.util.List; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotNull; import lombok.Builder; @Builder diff --git a/src/main/java/com/yello/server/domain/authorization/exception/CustomAuthenticationEntryPoint.java b/src/main/java/com/yello/server/domain/authorization/exception/CustomAuthenticationEntryPoint.java index 1b2c73b0..3261ab46 100644 --- a/src/main/java/com/yello/server/domain/authorization/exception/CustomAuthenticationEntryPoint.java +++ b/src/main/java/com/yello/server/domain/authorization/exception/CustomAuthenticationEntryPoint.java @@ -5,10 +5,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.yello.server.global.common.dto.BaseResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import lombok.extern.log4j.Log4j2; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; 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 6623b08d..a7bc2921 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 @@ -16,11 +16,11 @@ import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.security.SignatureException; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import lombok.val; 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 04ae15c5..7e7015de 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 @@ -2,12 +2,12 @@ import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.repository.UserRepository; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import lombok.val; 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 82bf43bd..cffd8941 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 @@ -38,11 +38,11 @@ import com.yello.server.global.common.manager.ConnectionManager; import com.yello.server.infrastructure.firebase.service.NotificationService; import com.yello.server.infrastructure.rabbitmq.repository.MessageQueueRepository; +import jakarta.validation.constraints.NotNull; import java.time.ZonedDateTime; import java.util.List; import java.util.Objects; import java.util.Optional; -import javax.validation.constraints.NotNull; import lombok.Builder; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; diff --git a/src/main/java/com/yello/server/domain/cooldown/entity/Cooldown.java b/src/main/java/com/yello/server/domain/cooldown/entity/Cooldown.java index 99d87952..6b1a05fc 100644 --- a/src/main/java/com/yello/server/domain/cooldown/entity/Cooldown.java +++ b/src/main/java/com/yello/server/domain/cooldown/entity/Cooldown.java @@ -4,22 +4,24 @@ import static com.yello.server.global.common.util.ConstantUtil.TIMER_TIME; import com.yello.server.domain.user.entity.User; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import java.time.LocalDateTime; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; import org.hibernate.annotations.Where; import org.springframework.data.annotation.CreatedDate; @@ -45,6 +47,7 @@ public class Cooldown { @OneToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = false, name = "userId") + @OnDelete(action = OnDeleteAction.CASCADE) private User user; private String messageId; 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 new file mode 100644 index 00000000..a54ca293 --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/controller/EventController.java @@ -0,0 +1,30 @@ +package com.yello.server.domain.event.controller; + +import static com.yello.server.global.common.SuccessCode.EVENT_NOTICE_SUCCESS; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.yello.server.domain.event.dto.response.EventResponse; +import com.yello.server.domain.event.service.EventService; +import com.yello.server.domain.user.entity.User; +import com.yello.server.global.common.annotation.AccessTokenUser; +import com.yello.server.global.common.dto.BaseResponse; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api") +public class EventController { + + private final EventService eventService; + + @GetMapping("/v1/event") + public BaseResponse> getEvents(@AccessTokenUser User user) throws JsonProcessingException { + val data = eventService.getEvents(user.getId()); + return BaseResponse.success(EVENT_NOTICE_SUCCESS, data); + } +} diff --git a/src/main/java/com/yello/server/domain/event/dto/response/EventResponse.java b/src/main/java/com/yello/server/domain/event/dto/response/EventResponse.java new file mode 100644 index 00000000..f9862dfd --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/dto/response/EventResponse.java @@ -0,0 +1,96 @@ +package com.yello.server.domain.event.dto.response; + +import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yello.server.domain.event.entity.Event; +import com.yello.server.domain.event.entity.EventRewardMapping; +import com.yello.server.domain.event.entity.EventRewardRandomType; +import com.yello.server.domain.event.entity.EventTime; +import com.yello.server.domain.event.entity.EventType; +import jakarta.annotation.Nullable; +import java.time.OffsetTime; +import java.util.List; +import lombok.Builder; + +@Builder +public record EventResponse( + EventType tag, + String startDate, + String endDate, + String title, + String subTitle, + List animationList, + @Nullable EventResponse.EventRewardVO eventReward +) { + + public static EventResponse of(Event event, @Nullable EventTime eventTime, + @Nullable List eventRewardMappingList) + throws JsonProcessingException { + // animation + ObjectMapper objectMapper = new ObjectMapper(); + final List animationList = objectMapper.readValue(event.getAnimation(), + new TypeReference>() { + }); + + EventResponse.EventRewardVO eventRewardVO = eventTime == null || eventRewardMappingList == null ? null + : EventResponse.EventRewardVO.of(eventTime, eventRewardMappingList); + + return EventResponse.builder() + .tag(event.getTag()) + .startDate(event.getStartDate().format(ISO_OFFSET_DATE_TIME)) + .endDate(event.getEndDate().format(ISO_OFFSET_DATE_TIME)) + .title(event.getTitle()) + .subTitle(event.getSubTitle()) + .animationList(animationList) + .eventReward(eventRewardVO) + .build(); + } + + @Builder + public record EventRewardVO( + OffsetTime startTime, + OffsetTime endTime, + Long rewardCount, + List eventRewardItem + ) { + + public static EventRewardVO of(EventTime eventTime, List eventRewardMappingList) { + List eventRewardItemList = eventRewardMappingList.stream() + .map(EventRewardItemVO::of).toList(); + + return EventRewardVO.builder() + .startTime(eventTime.getStartTime()) + .endTime(eventTime.getEndTime()) + .rewardCount(eventTime.getRewardCount()) + .eventRewardItem(eventRewardItemList) + .build(); + } + } + + @Builder + public record EventRewardItemVO( + String tag, + String eventRewardTitle, + String eventRewardImage, + Long maxRewardValue, + Long minRewardValue, + Integer eventRewardProbability, + EventRewardRandomType randomTag + ) { + + public static EventRewardItemVO of(EventRewardMapping eventRewardMapping) { + return EventRewardItemVO.builder() + .tag(eventRewardMapping.getEventReward().getTag()) + .eventRewardTitle(eventRewardMapping.getEventReward().getTitle()) + .eventRewardImage(eventRewardMapping.getEventReward().getImage()) + .maxRewardValue(eventRewardMapping.getEventReward().getMaxRewardValue()) + .minRewardValue(eventRewardMapping.getEventReward().getMinRewardValue()) + .eventRewardProbability(eventRewardMapping.getEventRewardProbability()) + .randomTag(eventRewardMapping.getRandomTag()) + .build(); + } + } +} diff --git a/src/main/java/com/yello/server/domain/event/entity/Event.java b/src/main/java/com/yello/server/domain/event/entity/Event.java new file mode 100644 index 00000000..da002ac8 --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/Event.java @@ -0,0 +1,62 @@ +package com.yello.server.domain.event.entity; + +import com.yello.server.global.common.dto.AuditingTimeEntity; +import com.yello.server.global.common.entity.ZonedDateTimeConverter; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import java.time.ZonedDateTime; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table( + uniqueConstraints = { + @UniqueConstraint( + name = "tag_unique", + columnNames = {"tag"} + ) + } +) +public class Event extends AuditingTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + @Convert(converter = EventTypeConverter.class) + private EventType tag; + + @Column(nullable = false) + @Convert(converter = ZonedDateTimeConverter.class) + private ZonedDateTime startDate; + + @Column(nullable = false) + @Convert(converter = ZonedDateTimeConverter.class) + private ZonedDateTime endDate; + + @Column + private String title; + + @Column + private String subTitle; + + /** + * Lottie를 저장하기 위한 컬럼 [{ ...json1... }, { ...json2... }] + */ + @Column(columnDefinition = "MEDIUMTEXT") + private String animation; +} diff --git a/src/main/java/com/yello/server/domain/event/entity/EventHistory.java b/src/main/java/com/yello/server/domain/event/entity/EventHistory.java new file mode 100644 index 00000000..a48554b3 --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/EventHistory.java @@ -0,0 +1,40 @@ +package com.yello.server.domain.event.entity; + +import com.yello.server.domain.user.entity.User; +import com.yello.server.global.common.dto.AuditingTimeEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.util.UUID; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +@Entity +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class EventHistory extends AuditingTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "userId") + @OnDelete(action = OnDeleteAction.CASCADE) + private User user; + + @Column + private UUID idempotencyKey; +} diff --git a/src/main/java/com/yello/server/domain/event/entity/EventInstance.java b/src/main/java/com/yello/server/domain/event/entity/EventInstance.java new file mode 100644 index 00000000..ced766c9 --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/EventInstance.java @@ -0,0 +1,50 @@ +package com.yello.server.domain.event.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.time.OffsetTime; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +@Getter +@Entity +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class EventInstance { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "eventHistoryId") + @OnDelete(action = OnDeleteAction.CASCADE) + private EventHistory eventHistory; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "eventId") + @OnDelete(action = OnDeleteAction.RESTRICT) + private Event event; + + @Column + private OffsetTime startTime; + + @Column + private OffsetTime endTime; + + @Column + @Builder.Default + private Long remainEventCount = 0L; +} 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 new file mode 100644 index 00000000..d2a11d89 --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/EventInstanceReward.java @@ -0,0 +1,60 @@ +package com.yello.server.domain.event.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +@Getter +@Entity +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class EventInstanceReward { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "eventInstanceId") + @OnDelete(action = OnDeleteAction.CASCADE) + private EventInstance eventInstance; + + @Column(columnDefinition = "int NOT NULL CHECK (event_reward_probability BETWEEN 0 and 100)") + private Integer eventRewardProbability; + + @Column(nullable = false) + private String rewardTag; + + @Column + private String rewardTitle; + + @Column + private String rewardImage; + + @Column(nullable = false) + @Convert(converter = EventRewardRandomTypeConverter.class) + private EventRewardRandomType randomTag; + + @Column(nullable = false) + private Long maxRewardValue; + + @Column(nullable = false) + private Long minRewardValue; + + @Column(nullable = false) + private Long sumRewardValue; +} diff --git a/src/main/java/com/yello/server/domain/event/entity/EventReward.java b/src/main/java/com/yello/server/domain/event/entity/EventReward.java new file mode 100644 index 00000000..40a6adbf --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/EventReward.java @@ -0,0 +1,51 @@ +package com.yello.server.domain.event.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table( + uniqueConstraints = { + @UniqueConstraint( + name = "tag_unique", + columnNames = {"tag"} + ) + } +) +public class EventReward { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private String tag; + + @Column + @Builder.Default + private Long maxRewardValue = 0L; + + @Column + @Builder.Default + private Long minRewardValue = 0L; + + @Column + private String title; + + @Column + private String image; +} diff --git a/src/main/java/com/yello/server/domain/event/entity/EventRewardMapping.java b/src/main/java/com/yello/server/domain/event/entity/EventRewardMapping.java new file mode 100644 index 00000000..d082f40c --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/EventRewardMapping.java @@ -0,0 +1,48 @@ +package com.yello.server.domain.event.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +@Getter +@Entity +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class EventRewardMapping { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "eventTimeId") + @OnDelete(action = OnDeleteAction.RESTRICT) + private EventTime eventTime; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "eventRewardId") + @OnDelete(action = OnDeleteAction.RESTRICT) + private EventReward eventReward; + + @Column(columnDefinition = "int NOT NULL CHECK (event_reward_probability BETWEEN 0 and 100)") + private Integer eventRewardProbability; + + + @Column(nullable = false) + @Convert(converter = EventRewardRandomTypeConverter.class) + private EventRewardRandomType randomTag; +} diff --git a/src/main/java/com/yello/server/domain/event/entity/EventRewardRandomType.java b/src/main/java/com/yello/server/domain/event/entity/EventRewardRandomType.java new file mode 100644 index 00000000..a1250e6a --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/EventRewardRandomType.java @@ -0,0 +1,31 @@ +package com.yello.server.domain.event.entity; + +import static com.yello.server.global.common.ErrorCode.ENUM_BAD_REQUEST_EXCEPTION; + +import com.yello.server.global.exception.EnumIllegalArgumentException; +import java.util.Arrays; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum EventRewardRandomType { + RANDOM("RANDOM"), + FIXED("FIXED"); + + private final String initial; + + public static EventRewardRandomType fromCode(String dbData) { + return Arrays.stream(EventRewardRandomType.values()) + .filter(v -> v.getInitial().equals(dbData)) + .findAny() + .orElseThrow(() -> new EnumIllegalArgumentException(ENUM_BAD_REQUEST_EXCEPTION)); + } + + public static EventRewardRandomType fromName(String name) { + return Arrays.stream(EventRewardRandomType.values()) + .filter(v -> v.name().equals(name)) + .findAny() + .orElseThrow(() -> new EnumIllegalArgumentException(ENUM_BAD_REQUEST_EXCEPTION)); + } +} diff --git a/src/main/java/com/yello/server/domain/event/entity/EventRewardRandomTypeConverter.java b/src/main/java/com/yello/server/domain/event/entity/EventRewardRandomTypeConverter.java new file mode 100644 index 00000000..2f552c02 --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/EventRewardRandomTypeConverter.java @@ -0,0 +1,28 @@ +package com.yello.server.domain.event.entity; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +import lombok.extern.log4j.Log4j2; + +@Converter +@Log4j2 +public class EventRewardRandomTypeConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(EventRewardRandomType type) { + if (type == null) { + return null; + } + return type.name(); + } + + @Override + public EventRewardRandomType convertToEntityAttribute(String dbData) { + if (dbData == null) { + return null; + } + + return EventRewardRandomType.fromName(dbData); + } +} + diff --git a/src/main/java/com/yello/server/domain/event/entity/EventTime.java b/src/main/java/com/yello/server/domain/event/entity/EventTime.java new file mode 100644 index 00000000..7eaf6bd1 --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/EventTime.java @@ -0,0 +1,49 @@ +package com.yello.server.domain.event.entity; + +import com.yello.server.global.common.entity.OffsetTimeConverter; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.time.OffsetTime; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +@Getter +@Entity +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class EventTime { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "eventId") + @OnDelete(action = OnDeleteAction.RESTRICT) + private Event event; + + @Column(columnDefinition = "varchar(30) NOT NULL") + @Convert(converter = OffsetTimeConverter.class) + private OffsetTime startTime; + + @Column(columnDefinition = "varchar(30) NOT NULL") + @Convert(converter = OffsetTimeConverter.class) + private OffsetTime endTime; + + @Column + @Builder.Default + private Long rewardCount = 1L; +} diff --git a/src/main/java/com/yello/server/domain/event/entity/EventType.java b/src/main/java/com/yello/server/domain/event/entity/EventType.java new file mode 100644 index 00000000..2a2d59f9 --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/EventType.java @@ -0,0 +1,31 @@ +package com.yello.server.domain.event.entity; + +import static com.yello.server.global.common.ErrorCode.ENUM_BAD_REQUEST_EXCEPTION; + +import com.yello.server.global.exception.EnumIllegalArgumentException; +import java.util.Arrays; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum EventType { + ADMOB("ADMOB"), + LUNCH_EVENT("LUNCH_EVENT"); + + private final String initial; + + public static EventType fromCode(String dbData) { + return Arrays.stream(EventType.values()) + .filter(v -> v.getInitial().equals(dbData)) + .findAny() + .orElseThrow(() -> new EnumIllegalArgumentException(ENUM_BAD_REQUEST_EXCEPTION)); + } + + public static EventType fromName(String name) { + return Arrays.stream(EventType.values()) + .filter(v -> v.name().equals(name)) + .findAny() + .orElseThrow(() -> new EnumIllegalArgumentException(ENUM_BAD_REQUEST_EXCEPTION)); + } +} diff --git a/src/main/java/com/yello/server/domain/event/entity/EventTypeConverter.java b/src/main/java/com/yello/server/domain/event/entity/EventTypeConverter.java new file mode 100644 index 00000000..33bf2d3d --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/entity/EventTypeConverter.java @@ -0,0 +1,27 @@ +package com.yello.server.domain.event.entity; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +import lombok.extern.log4j.Log4j2; + +@Converter +@Log4j2 +public class EventTypeConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(EventType type) { + if (type == null) { + return null; + } + return type.name(); + } + + @Override + public EventType convertToEntityAttribute(String dbData) { + if (dbData == null) { + return null; + } + + return EventType.fromName(dbData); + } +} diff --git a/src/main/java/com/yello/server/domain/event/exception/EventNotFoundException.java b/src/main/java/com/yello/server/domain/event/exception/EventNotFoundException.java new file mode 100644 index 00000000..62632116 --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/exception/EventNotFoundException.java @@ -0,0 +1,11 @@ +package com.yello.server.domain.event.exception; + +import com.yello.server.global.common.ErrorCode; +import com.yello.server.global.exception.CustomException; + +public class EventNotFoundException extends CustomException { + + public EventNotFoundException(ErrorCode error) { + super(error, "[EventNotFoundException] " + error.getMessage()); + } +} diff --git a/src/main/java/com/yello/server/domain/event/repository/EventJpaRepository.java b/src/main/java/com/yello/server/domain/event/repository/EventJpaRepository.java new file mode 100644 index 00000000..6633a5ae --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/repository/EventJpaRepository.java @@ -0,0 +1,8 @@ +package com.yello.server.domain.event.repository; + +import com.yello.server.domain.event.entity.Event; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface EventJpaRepository extends JpaRepository { + +} 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 new file mode 100644 index 00000000..76f72a0a --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/repository/EventRepository.java @@ -0,0 +1,20 @@ +package com.yello.server.domain.event.repository; + +import com.yello.server.domain.event.entity.Event; +import com.yello.server.domain.event.entity.EventReward; +import com.yello.server.domain.event.entity.EventRewardMapping; +import com.yello.server.domain.event.entity.EventTime; +import java.util.List; + +public interface EventRepository { + + List findAll(); + + List findAllByEventId(Long eventId); + + List findAllByEventTimeId(Long eventTimeId); + + List findRewardAll(); + + EventReward getRewardById(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 new file mode 100644 index 00000000..7b820d4b --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/repository/EventRepositoryImpl.java @@ -0,0 +1,48 @@ +package com.yello.server.domain.event.repository; + +import static com.yello.server.global.common.ErrorCode.EVENT_NOT_FOUND_EXCEPTION; + +import com.yello.server.domain.event.entity.Event; +import com.yello.server.domain.event.entity.EventReward; +import com.yello.server.domain.event.entity.EventRewardMapping; +import com.yello.server.domain.event.entity.EventTime; +import com.yello.server.domain.event.exception.EventNotFoundException; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class EventRepositoryImpl implements EventRepository { + + private final EventJpaRepository eventJpaRepository; + private final EventRewardJpaRepository eventRewardJpaRepository; + private final EventRewardMappingJpaRepository eventRewardMappingJpaRepository; + private final EventTimeJpaRepository eventTimeJpaRepository; + + @Override + public List findAll() { + return eventJpaRepository.findAll(); + } + + @Override + public List findAllByEventId(Long eventId) { + return eventTimeJpaRepository.findAllByEventId(eventId); + } + + @Override + public List findAllByEventTimeId(Long eventTimeId) { + return eventRewardMappingJpaRepository.findAllByEventTimeId(eventTimeId); + } + + @Override + public List findRewardAll() { + return eventRewardJpaRepository.findAll(); + } + + @Override + public EventReward getRewardById(Long eventRewardId) { + return eventRewardJpaRepository.findById(eventRewardId) + .orElseThrow(() -> new EventNotFoundException(EVENT_NOT_FOUND_EXCEPTION)); + } +} diff --git a/src/main/java/com/yello/server/domain/event/repository/EventRewardJpaRepository.java b/src/main/java/com/yello/server/domain/event/repository/EventRewardJpaRepository.java new file mode 100644 index 00000000..15b4a21f --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/repository/EventRewardJpaRepository.java @@ -0,0 +1,13 @@ +package com.yello.server.domain.event.repository; + +import com.yello.server.domain.event.entity.EventReward; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +public interface EventRewardJpaRepository extends JpaRepository { + + @Query("select e from EventReward e where e.tag = ?1") + Optional findByTag(String tag); + +} diff --git a/src/main/java/com/yello/server/domain/event/repository/EventRewardMappingJpaRepository.java b/src/main/java/com/yello/server/domain/event/repository/EventRewardMappingJpaRepository.java new file mode 100644 index 00000000..753f755d --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/repository/EventRewardMappingJpaRepository.java @@ -0,0 +1,13 @@ +package com.yello.server.domain.event.repository; + +import com.yello.server.domain.event.entity.EventRewardMapping; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +public interface EventRewardMappingJpaRepository extends JpaRepository { + + @Query("select e from EventRewardMapping e where e.eventTime.id = ?1") + List findAllByEventTimeId(Long eventTimeId); + +} diff --git a/src/main/java/com/yello/server/domain/event/repository/EventTimeJpaRepository.java b/src/main/java/com/yello/server/domain/event/repository/EventTimeJpaRepository.java new file mode 100644 index 00000000..2d56ee7f --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/repository/EventTimeJpaRepository.java @@ -0,0 +1,13 @@ +package com.yello.server.domain.event.repository; + +import com.yello.server.domain.event.entity.EventTime; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +public interface EventTimeJpaRepository extends JpaRepository { + + @Query("select e from EventTime e where e.event.id = ?1") + List findAllByEventId(Long eventId); + +} 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 new file mode 100644 index 00000000..bbc23de3 --- /dev/null +++ b/src/main/java/com/yello/server/domain/event/service/EventService.java @@ -0,0 +1,58 @@ +package com.yello.server.domain.event.service; + +import static com.yello.server.global.common.util.ConstantUtil.GlobalZoneId; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.yello.server.domain.event.dto.response.EventResponse; +import com.yello.server.domain.event.entity.Event; +import com.yello.server.domain.event.entity.EventRewardMapping; +import com.yello.server.domain.event.entity.EventTime; +import com.yello.server.domain.event.repository.EventRepository; +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.user.repository.UserRepository; +import java.time.OffsetTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class EventService { + + private final EventRepository eventRepository; + private final UserRepository userRepository; + + public List getEvents(Long userId) throws JsonProcessingException { + // exception + final User user = userRepository.getById(userId); + + // logic + ZonedDateTime now = ZonedDateTime.now(GlobalZoneId); + OffsetTime nowTime = now.toOffsetDateTime().toOffsetTime(); + List result = new ArrayList<>(); + + final List eventList = eventRepository.findAll().stream() + .filter(event -> now.isAfter(event.getStartDate()) && now.isBefore(event.getEndDate())) + .toList(); + + for (Event event : eventList) { + final List eventTimeList = eventRepository.findAllByEventId(event.getId()).stream() + .filter( + eventTime -> nowTime.isAfter(eventTime.getStartTime()) && nowTime.isBefore(eventTime.getEndTime()) + ) + .toList(); + + final EventTime eventTime = eventTimeList.isEmpty() ? null : eventTimeList.get(0); + final List eventRewardMappingList = + eventTimeList.isEmpty() ? null : eventRepository.findAllByEventTimeId(eventTime.getId()); + + result.add(EventResponse.of(event, eventTime, eventRewardMappingList)); + } + + return result; + } +} 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 85838714..95d3ddcc 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,8 +18,8 @@ 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 jakarta.validation.Valid; import java.util.List; -import javax.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.val; import org.springframework.web.bind.annotation.DeleteMapping; diff --git a/src/main/java/com/yello/server/domain/friend/entity/Friend.java b/src/main/java/com/yello/server/domain/friend/entity/Friend.java index 51a6b826..75698d95 100644 --- a/src/main/java/com/yello/server/domain/friend/entity/Friend.java +++ b/src/main/java/com/yello/server/domain/friend/entity/Friend.java @@ -2,22 +2,24 @@ import com.yello.server.domain.user.entity.User; import com.yello.server.global.common.dto.AuditingTimeEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import java.time.LocalDateTime; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; import org.hibernate.annotations.Where; @Getter @@ -42,10 +44,12 @@ public class Friend extends AuditingTimeEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = false, name = "user") + @OnDelete(action = OnDeleteAction.CASCADE) private User user; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(nullable = false, name = "target") + @OnDelete(action = OnDeleteAction.CASCADE) private User target; @Column diff --git a/src/main/java/com/yello/server/domain/group/entity/UserGroup.java b/src/main/java/com/yello/server/domain/group/entity/UserGroup.java index e795209b..54edb39b 100644 --- a/src/main/java/com/yello/server/domain/group/entity/UserGroup.java +++ b/src/main/java/com/yello/server/domain/group/entity/UserGroup.java @@ -1,14 +1,14 @@ package com.yello.server.domain.group.entity; -import javax.persistence.Column; -import javax.persistence.Convert; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Index; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/src/main/java/com/yello/server/domain/group/entity/UserGroupData.java b/src/main/java/com/yello/server/domain/group/entity/UserGroupData.java index a025ffae..ac4df791 100644 --- a/src/main/java/com/yello/server/domain/group/entity/UserGroupData.java +++ b/src/main/java/com/yello/server/domain/group/entity/UserGroupData.java @@ -1,19 +1,21 @@ package com.yello.server.domain.group.entity; import com.yello.server.global.common.dto.AuditingTimeEntity; -import javax.persistence.Convert; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; @Getter @Entity @@ -28,6 +30,7 @@ public class UserGroupData extends AuditingTimeEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "groupName", referencedColumnName = "groupName") + @OnDelete(action = OnDeleteAction.RESTRICT) private UserGroup group; @Convert(converter = UserGroupDataTagConterver.class) diff --git a/src/main/java/com/yello/server/domain/group/entity/UserGroupDataTagConterver.java b/src/main/java/com/yello/server/domain/group/entity/UserGroupDataTagConterver.java index d8facf03..0086d0c9 100644 --- a/src/main/java/com/yello/server/domain/group/entity/UserGroupDataTagConterver.java +++ b/src/main/java/com/yello/server/domain/group/entity/UserGroupDataTagConterver.java @@ -1,7 +1,7 @@ package com.yello.server.domain.group.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter diff --git a/src/main/java/com/yello/server/domain/group/entity/UserGroupTypeConverter.java b/src/main/java/com/yello/server/domain/group/entity/UserGroupTypeConverter.java index 5382169b..76a24212 100644 --- a/src/main/java/com/yello/server/domain/group/entity/UserGroupTypeConverter.java +++ b/src/main/java/com/yello/server/domain/group/entity/UserGroupTypeConverter.java @@ -1,7 +1,7 @@ package com.yello.server.domain.group.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter diff --git a/src/main/java/com/yello/server/domain/keyword/entity/Keyword.java b/src/main/java/com/yello/server/domain/keyword/entity/Keyword.java index 83941cd4..2014b69d 100644 --- a/src/main/java/com/yello/server/domain/keyword/entity/Keyword.java +++ b/src/main/java/com/yello/server/domain/keyword/entity/Keyword.java @@ -1,19 +1,21 @@ package com.yello.server.domain.keyword.entity; import com.yello.server.domain.question.entity.Question; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; @Getter @Entity @@ -31,6 +33,7 @@ public class Keyword { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "questionId") + @OnDelete(action = OnDeleteAction.RESTRICT) private Question question; public static Keyword of(String keywordName, Question question) { diff --git a/src/main/java/com/yello/server/domain/notice/controller/NoticeController.java b/src/main/java/com/yello/server/domain/notice/controller/NoticeController.java index 5911f6e5..51b9be99 100644 --- a/src/main/java/com/yello/server/domain/notice/controller/NoticeController.java +++ b/src/main/java/com/yello/server/domain/notice/controller/NoticeController.java @@ -1,8 +1,9 @@ package com.yello.server.domain.notice.controller; +import static com.yello.server.global.common.SuccessCode.READ_NOTICE_SUCCESS; + import com.yello.server.domain.notice.dto.NoticeDataResponse; -import com.yello.server.domain.notice.entity.NoticeType; import com.yello.server.domain.notice.service.NoticeService; import com.yello.server.domain.user.entity.User; import com.yello.server.global.common.annotation.AccessTokenUser; @@ -14,8 +15,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import static com.yello.server.global.common.SuccessCode.READ_NOTICE_SUCCESS; - @RestController @RequiredArgsConstructor @RequestMapping("api/v1") diff --git a/src/main/java/com/yello/server/domain/notice/entity/Notice.java b/src/main/java/com/yello/server/domain/notice/entity/Notice.java index 4d6d4103..e70e27ba 100644 --- a/src/main/java/com/yello/server/domain/notice/entity/Notice.java +++ b/src/main/java/com/yello/server/domain/notice/entity/Notice.java @@ -1,13 +1,14 @@ package com.yello.server.domain.notice.entity; import com.yello.server.global.common.dto.AuditingTimeEntity; +import com.yello.server.global.common.entity.ZonedDateTimeConverter; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; import java.time.ZonedDateTime; -import javax.persistence.Column; -import javax.persistence.Convert; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -32,9 +33,11 @@ public class Notice extends AuditingTimeEntity { private String redirectUrl; @Column(nullable = false) + @Convert(converter = ZonedDateTimeConverter.class) private ZonedDateTime startDate; @Column(nullable = false) + @Convert(converter = ZonedDateTimeConverter.class) private ZonedDateTime endDate; @Column(nullable = false) diff --git a/src/main/java/com/yello/server/domain/notice/entity/NoticeTypeConverter.java b/src/main/java/com/yello/server/domain/notice/entity/NoticeTypeConverter.java index c84cffc1..169b9ea3 100644 --- a/src/main/java/com/yello/server/domain/notice/entity/NoticeTypeConverter.java +++ b/src/main/java/com/yello/server/domain/notice/entity/NoticeTypeConverter.java @@ -1,7 +1,7 @@ package com.yello.server.domain.notice.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter diff --git a/src/main/java/com/yello/server/domain/notice/repository/NoticeRepository.java b/src/main/java/com/yello/server/domain/notice/repository/NoticeRepository.java index b4af79f0..78db8741 100644 --- a/src/main/java/com/yello/server/domain/notice/repository/NoticeRepository.java +++ b/src/main/java/com/yello/server/domain/notice/repository/NoticeRepository.java @@ -2,12 +2,18 @@ import com.yello.server.domain.notice.entity.Notice; import com.yello.server.domain.notice.entity.NoticeType; - +import java.util.List; import java.util.Optional; public interface NoticeRepository { Optional findTopNotice(NoticeType tag); + + List findAll(); + + Notice getById(Long id); + Notice save(Notice notice); + void update(Notice newNotice); } diff --git a/src/main/java/com/yello/server/domain/notice/repository/NoticeRepositoryImpl.java b/src/main/java/com/yello/server/domain/notice/repository/NoticeRepositoryImpl.java index 8185f4ba..fab23ec4 100644 --- a/src/main/java/com/yello/server/domain/notice/repository/NoticeRepositoryImpl.java +++ b/src/main/java/com/yello/server/domain/notice/repository/NoticeRepositoryImpl.java @@ -1,38 +1,51 @@ package com.yello.server.domain.notice.repository; +import static com.yello.server.domain.notice.entity.QNotice.notice; +import static com.yello.server.global.common.ErrorCode.NOT_FOUND_NOTICE_EXCEPTION; + import com.querydsl.jpa.impl.JPAQueryFactory; import com.yello.server.domain.notice.entity.Notice; import com.yello.server.domain.notice.entity.NoticeType; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; - +import com.yello.server.domain.notice.exception.NoticeNotFoundException; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.List; import java.util.Optional; - -import static com.yello.server.domain.notice.entity.QNotice.notice; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; @Repository @RequiredArgsConstructor @Transactional(readOnly = true) public class NoticeRepositoryImpl implements NoticeRepository { - private final NoticeJpaRepository noticeJpaRepository; private final JPAQueryFactory jpaQueryFactory; + private final NoticeJpaRepository noticeJpaRepository; @Override public Optional findTopNotice(NoticeType tag) { ZoneId zoneId = ZoneId.of("Asia/Seoul"); ZonedDateTime zonedDateTime = ZonedDateTime.now(zoneId); return Optional.ofNullable(jpaQueryFactory - .selectFrom(notice) - .where(notice.isAvailable.eq(true) - .and(notice.startDate.loe(zonedDateTime)) - .and(notice.endDate.goe(zonedDateTime)) - .and(notice.tag.eq(tag))) - .orderBy(notice.endDate.desc()) - .fetchFirst()); + .selectFrom(notice) + .where(notice.isAvailable.eq(true) + .and(notice.startDate.loe(zonedDateTime)) + .and(notice.endDate.goe(zonedDateTime)) + .and(notice.tag.eq(tag))) + .orderBy(notice.endDate.desc()) + .fetchFirst()); + } + + @Override + public List findAll() { + return jpaQueryFactory.selectFrom(notice).fetch(); + } + + @Override + public Notice getById(Long id) { + return noticeJpaRepository.findById(id) + .orElseThrow(() -> new NoticeNotFoundException(NOT_FOUND_NOTICE_EXCEPTION)); } @Override @@ -40,4 +53,18 @@ public Notice save(Notice notice) { return noticeJpaRepository.save(notice); } + @Override + public void update(Notice newNotice) { + jpaQueryFactory.update(notice) + .set(notice.imageUrl, newNotice.getImageUrl()) + .set(notice.redirectUrl, newNotice.getRedirectUrl()) + .set(notice.startDate, newNotice.getStartDate()) + .set(notice.endDate, newNotice.getEndDate()) + .set(notice.isAvailable, newNotice.getIsAvailable()) + .set(notice.tag, newNotice.getTag()) + .set(notice.title, newNotice.getTitle()) + .where(notice.id.eq(newNotice.getId())) + .execute(); + } + } diff --git a/src/main/java/com/yello/server/domain/pay/entity/Pay.java b/src/main/java/com/yello/server/domain/pay/entity/Pay.java index a1d73a58..47463c7d 100644 --- a/src/main/java/com/yello/server/domain/pay/entity/Pay.java +++ b/src/main/java/com/yello/server/domain/pay/entity/Pay.java @@ -1,18 +1,20 @@ package com.yello.server.domain.pay.entity; import com.yello.server.domain.user.entity.User; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; @Entity @Getter @@ -29,6 +31,7 @@ public class Pay { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "userId") + @OnDelete(action = OnDeleteAction.CASCADE) private User user; public static Pay of(Integer optionIndex, User user) { diff --git a/src/main/java/com/yello/server/domain/purchase/entity/GatewayConverter.java b/src/main/java/com/yello/server/domain/purchase/entity/GatewayConverter.java index 433c11fa..f8dce446 100644 --- a/src/main/java/com/yello/server/domain/purchase/entity/GatewayConverter.java +++ b/src/main/java/com/yello/server/domain/purchase/entity/GatewayConverter.java @@ -1,7 +1,7 @@ package com.yello.server.domain.purchase.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter diff --git a/src/main/java/com/yello/server/domain/purchase/entity/ProductTypeConverter.java b/src/main/java/com/yello/server/domain/purchase/entity/ProductTypeConverter.java index 752fbffa..de21eed2 100644 --- a/src/main/java/com/yello/server/domain/purchase/entity/ProductTypeConverter.java +++ b/src/main/java/com/yello/server/domain/purchase/entity/ProductTypeConverter.java @@ -1,7 +1,7 @@ package com.yello.server.domain.purchase.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter diff --git a/src/main/java/com/yello/server/domain/purchase/entity/Purchase.java b/src/main/java/com/yello/server/domain/purchase/entity/Purchase.java index 356c4a8c..f1741ca1 100644 --- a/src/main/java/com/yello/server/domain/purchase/entity/Purchase.java +++ b/src/main/java/com/yello/server/domain/purchase/entity/Purchase.java @@ -3,23 +3,25 @@ import com.yello.server.domain.user.entity.User; import com.yello.server.global.common.dto.AuditingTimeEntity; import com.yello.server.global.common.util.ConstantUtil; -import javax.persistence.Column; -import javax.persistence.Convert; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; @Entity @Getter @@ -53,6 +55,7 @@ public class Purchase extends AuditingTimeEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "userId") + @OnDelete(action = OnDeleteAction.SET_NULL) private User user; @Column(nullable = false) diff --git a/src/main/java/com/yello/server/domain/purchase/entity/PurchaseStateConverter.java b/src/main/java/com/yello/server/domain/purchase/entity/PurchaseStateConverter.java index 35280400..9ae9c6ad 100644 --- a/src/main/java/com/yello/server/domain/purchase/entity/PurchaseStateConverter.java +++ b/src/main/java/com/yello/server/domain/purchase/entity/PurchaseStateConverter.java @@ -1,7 +1,7 @@ package com.yello.server.domain.purchase.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter diff --git a/src/main/java/com/yello/server/domain/question/entity/Question.java b/src/main/java/com/yello/server/domain/question/entity/Question.java index 31556db1..7f0483a6 100644 --- a/src/main/java/com/yello/server/domain/question/entity/Question.java +++ b/src/main/java/com/yello/server/domain/question/entity/Question.java @@ -1,17 +1,17 @@ package com.yello.server.domain.question.entity; import com.yello.server.domain.keyword.entity.Keyword; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToMany; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -50,7 +50,7 @@ public Question(String nameHead, String nameFoot, String keywordHead, String key 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; } public static Question of(String nameHead, String nameFoot, String keywordHead, String keywordFoot) { @@ -68,18 +68,18 @@ public void addKeyword(Keyword keyword) { public String toNotificationSentence() { final String nameFootPart = deleteBracket(this.nameFoot); - final String nameHeadPart = (this.nameHead!=null) ? MessageFormat.format("{0} ", this.nameHead) : ""; - final String keywordHeadPart = (this.keywordHead!=null) ? MessageFormat.format(" {0}", this.keywordHead) : ""; + final String nameHeadPart = (this.nameHead != null) ? MessageFormat.format("{0} ", this.nameHead) : ""; + final String keywordHeadPart = (this.keywordHead != null) ? MessageFormat.format(" {0}", this.keywordHead) : ""; return MessageFormat.format("{0}너{1}{2} ...", nameHeadPart, nameFootPart, keywordHeadPart); } @Override public boolean equals(Object o) { - if (this==o) { + if (this == o) { return true; } - if (o==null || getClass()!=o.getClass()) { + if (o == null || getClass() != o.getClass()) { return false; } Question question = (Question) o; diff --git a/src/main/java/com/yello/server/domain/question/entity/QuestionGroupType.java b/src/main/java/com/yello/server/domain/question/entity/QuestionGroupType.java index c8e003a6..84a3ded4 100644 --- a/src/main/java/com/yello/server/domain/question/entity/QuestionGroupType.java +++ b/src/main/java/com/yello/server/domain/question/entity/QuestionGroupType.java @@ -3,15 +3,15 @@ import com.yello.server.domain.group.entity.UserGroupType; import com.yello.server.domain.group.entity.UserGroupTypeConverter; -import javax.persistence.Column; -import javax.persistence.Convert; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/src/main/java/com/yello/server/domain/user/entity/GenderConverter.java b/src/main/java/com/yello/server/domain/user/entity/GenderConverter.java index 7039df74..95ded004 100644 --- a/src/main/java/com/yello/server/domain/user/entity/GenderConverter.java +++ b/src/main/java/com/yello/server/domain/user/entity/GenderConverter.java @@ -1,7 +1,7 @@ package com.yello.server.domain.user.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter diff --git a/src/main/java/com/yello/server/domain/user/entity/SocialConverter.java b/src/main/java/com/yello/server/domain/user/entity/SocialConverter.java index c03ad1ba..d4d8a65f 100644 --- a/src/main/java/com/yello/server/domain/user/entity/SocialConverter.java +++ b/src/main/java/com/yello/server/domain/user/entity/SocialConverter.java @@ -1,7 +1,7 @@ package com.yello.server.domain.user.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter diff --git a/src/main/java/com/yello/server/domain/user/entity/SubscribeConverter.java b/src/main/java/com/yello/server/domain/user/entity/SubscribeConverter.java index 2a7080dc..7dc12eac 100644 --- a/src/main/java/com/yello/server/domain/user/entity/SubscribeConverter.java +++ b/src/main/java/com/yello/server/domain/user/entity/SubscribeConverter.java @@ -1,7 +1,7 @@ package com.yello.server.domain.user.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter 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 4bcc7ff4..c9afcfdb 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 @@ -5,26 +5,28 @@ import com.yello.server.domain.group.entity.UserGroup; import com.yello.server.domain.user.dto.request.UserUpdateRequest; import com.yello.server.global.common.dto.AuditingTimeEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import jakarta.validation.constraints.Email; import java.time.LocalDateTime; import java.util.Objects; -import javax.persistence.Column; -import javax.persistence.Convert; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; -import javax.validation.constraints.Email; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; @Getter @Entity @@ -68,8 +70,8 @@ public class User extends AuditingTimeEntity { private Gender gender; @Column(nullable = false) - @ColumnDefault("200") - private Integer point; + @Builder.Default + private Integer point = 200; @Column(nullable = false) @Convert(converter = SocialConverter.class) @@ -85,6 +87,7 @@ public class User extends AuditingTimeEntity { private LocalDateTime deletedAt; @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.RESTRICT) @JoinColumn(name = "groupId") private UserGroup group; @@ -104,9 +107,9 @@ public class User extends AuditingTimeEntity { private String deviceToken; @Column(nullable = false) - @ColumnDefault("normal") @Convert(converter = SubscribeConverter.class) - private Subscribe subscribe; + @Builder.Default + private Subscribe subscribe = Subscribe.NORMAL; public static User of(SignUpRequest signUpRequest, UserGroup group) { return User.builder() diff --git a/src/main/java/com/yello/server/domain/user/entity/UserData.java b/src/main/java/com/yello/server/domain/user/entity/UserData.java index 208f7958..75a3a04c 100644 --- a/src/main/java/com/yello/server/domain/user/entity/UserData.java +++ b/src/main/java/com/yello/server/domain/user/entity/UserData.java @@ -1,25 +1,29 @@ package com.yello.server.domain.user.entity; -import javax.persistence.Column; -import javax.persistence.Convert; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; @Getter @Entity @Builder @AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table public class UserData { @Id @@ -27,6 +31,7 @@ public class UserData { private Long id; @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.CASCADE) @JoinColumn(name = "userId") private User user; diff --git a/src/main/java/com/yello/server/domain/user/entity/UserDataTypeConverter.java b/src/main/java/com/yello/server/domain/user/entity/UserDataTypeConverter.java index 2931a976..69173534 100644 --- a/src/main/java/com/yello/server/domain/user/entity/UserDataTypeConverter.java +++ b/src/main/java/com/yello/server/domain/user/entity/UserDataTypeConverter.java @@ -1,6 +1,6 @@ package com.yello.server.domain.user.entity; -import javax.persistence.AttributeConverter; +import jakarta.persistence.AttributeConverter; import lombok.extern.slf4j.Slf4j; @Slf4j diff --git a/src/main/java/com/yello/server/domain/vote/entity/Vote.java b/src/main/java/com/yello/server/domain/vote/entity/Vote.java index a8b3b265..fb30b63f 100644 --- a/src/main/java/com/yello/server/domain/vote/entity/Vote.java +++ b/src/main/java/com/yello/server/domain/vote/entity/Vote.java @@ -3,21 +3,24 @@ import com.yello.server.domain.question.entity.Question; import com.yello.server.domain.user.entity.User; import com.yello.server.global.common.dto.AuditingTimeEntity; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; @Entity @Getter @@ -38,23 +41,26 @@ public class Vote extends AuditingTimeEntity { @Column(nullable = false) private Integer nameHint; - @ColumnDefault("false") @Column(nullable = false) - private Boolean isAnswerRevealed; + @Builder.Default + private Boolean isAnswerRevealed = false; - @ColumnDefault("false") @Column(nullable = false) - private Boolean isRead; + @Builder.Default + private Boolean isRead = false; @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.SET_NULL) @JoinColumn(name = "senderId") private User sender; @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.SET_NULL) @JoinColumn(name = "receiverId") private User receiver; @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.RESTRICT) @JoinColumn(name = "questionId") private Question question; diff --git a/src/main/java/com/yello/server/domain/vote/entity/VoteTypeConverter.java b/src/main/java/com/yello/server/domain/vote/entity/VoteTypeConverter.java index f1f9df85..472d350e 100644 --- a/src/main/java/com/yello/server/domain/vote/entity/VoteTypeConverter.java +++ b/src/main/java/com/yello/server/domain/vote/entity/VoteTypeConverter.java @@ -1,7 +1,7 @@ package com.yello.server.domain.vote.entity; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import lombok.extern.log4j.Log4j2; @Converter 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 3f77b767..440774b2 100644 --- a/src/main/java/com/yello/server/global/common/ErrorCode.java +++ b/src/main/java/com/yello/server/global/common/ErrorCode.java @@ -39,6 +39,7 @@ public enum ErrorCode { USER_ADMIN_BAD_REQUEST_EXCEPTION(BAD_REQUEST, "검색 필드가 없습니다."), USER_DATA_INVALID_ARGUMENT_EXCEPTION(BAD_REQUEST, "입력한 유저 데이터의 값이 올바르지 않습니다."), ENUM_BAD_REQUEST_EXCEPTION(BAD_REQUEST, "존재하지 않는 열거형 타입입니다."), + PROBABILITY_BAD_REQUEST_EXCEPTION(BAD_REQUEST, "확률의 합이 100이 아닙니다."), /** * 401 UNAUTHORIZED @@ -96,6 +97,9 @@ public enum ErrorCode { NOT_FOUND_NOTICE_EXCEPTION(NOT_FOUND, "공지가 존재하지 않습니다."), ADMIN_CONFIGURATION_NOT_FOUND_EXCEPTION(NOT_FOUND, "해당 설정이 존재하지 않습니다."), USER_DATA_NOT_FOUND_EXCEPTION(NOT_FOUND, "해당 유저 데이터가 존재하지 않습니다."), + EVENT_REWARD_NOT_FOUND_EXCEPTION(NOT_FOUND, "해당 EventReward가 존재하지 않습니다."), + EVENT_NOT_FOUND_EXCEPTION(NOT_FOUND, "해당 Event가 존재하지 않습니다."), + EVENT_TIME_NOT_FOUND_EXCEPTION(NOT_FOUND, "해당 EventTime가 존재하지 않습니다."), /** * 409 CONFLICT 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 524ecb24..34d94520 100644 --- a/src/main/java/com/yello/server/global/common/SuccessCode.java +++ b/src/main/java/com/yello/server/global/common/SuccessCode.java @@ -54,6 +54,12 @@ public enum SuccessCode { READ_NOTICE_SUCCESS(OK, "공지 조회에 성공하였습니다."), CONFIGURATION_READ_ADMIN_SUCCESS(OK, "어드민 권한으로 설정 조회에 성공하였습니다."), CONFIGURATION_UPDATE_ADMIN_SUCCESS(OK, "어드민 권한으로 설정 수정에 성공하였습니다."), + NOTICE_CREATE_ADMIN_SUCCESS(OK, "어드민 권한으로 공지 생성에 성공하였습니다."), + NOTICE_READ_ADMIN_SUCCESS(OK, "어드민 권한으로 공지 조회에 성공하였습니다."), + NOTICE_UPDATE_DETAIL_ADMIN_SUCCESS(OK, "어드민 권한으로 공지 수정에 성공하였습니다."), + EVENT_CREATE_ADMIN_SUCCESS(OK, "어드민 권한으로 이벤트 생성에 성공하였습니다."), + EVENT_NOTICE_SUCCESS(OK, "이벤트 전체 조회에 성공하였습니다."), + EVENT_REWARD_CREATE_ADMIN_SUCCESS(OK, "어드민 권한으로 이벤트 보상 생성에 성공하였습니다."), /** * 201 CREATED diff --git a/src/main/java/com/yello/server/global/common/dto/AuditingTimeEntity.java b/src/main/java/com/yello/server/global/common/dto/AuditingTimeEntity.java index 6fbc28bd..76221f23 100644 --- a/src/main/java/com/yello/server/global/common/dto/AuditingTimeEntity.java +++ b/src/main/java/com/yello/server/global/common/dto/AuditingTimeEntity.java @@ -1,8 +1,8 @@ package com.yello.server.global.common.dto; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; import java.time.LocalDateTime; -import javax.persistence.EntityListeners; -import javax.persistence.MappedSuperclass; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/com/yello/server/global/common/dto/MultiReadHttpServletRequest.java b/src/main/java/com/yello/server/global/common/dto/MultiReadHttpServletRequest.java index 73dd0dc1..be95d707 100644 --- a/src/main/java/com/yello/server/global/common/dto/MultiReadHttpServletRequest.java +++ b/src/main/java/com/yello/server/global/common/dto/MultiReadHttpServletRequest.java @@ -1,5 +1,9 @@ package com.yello.server.global.common.dto; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -7,10 +11,6 @@ import java.io.InputStreamReader; import java.util.Enumeration; import java.util.Map; -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; import org.apache.tomcat.util.http.fileupload.IOUtils; public class MultiReadHttpServletRequest extends HttpServletRequestWrapper { @@ -65,7 +65,7 @@ public String toString() { .append(headers.get(key)) .append("\n"); }); - + return builder.toString(); } diff --git a/src/main/java/com/yello/server/global/common/entity/GoogleToken.java b/src/main/java/com/yello/server/global/common/entity/GoogleToken.java index 28e19cb1..43bf7ce5 100644 --- a/src/main/java/com/yello/server/global/common/entity/GoogleToken.java +++ b/src/main/java/com/yello/server/global/common/entity/GoogleToken.java @@ -1,10 +1,10 @@ package com.yello.server.global.common.entity; import com.yello.server.global.common.dto.AuditingTimeEntity; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/com/yello/server/global/common/entity/OffsetTimeConverter.java b/src/main/java/com/yello/server/global/common/entity/OffsetTimeConverter.java new file mode 100644 index 00000000..f6cbafbc --- /dev/null +++ b/src/main/java/com/yello/server/global/common/entity/OffsetTimeConverter.java @@ -0,0 +1,28 @@ +package com.yello.server.global.common.entity; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +import java.time.OffsetTime; +import java.time.format.DateTimeFormatter; + +@Converter +public class OffsetTimeConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(OffsetTime offsetTime) { + if (offsetTime == null) { + return null; + } + + return offsetTime.format(DateTimeFormatter.ISO_OFFSET_TIME); + } + + @Override + public OffsetTime convertToEntityAttribute(String sqlTimestamp) { + if (sqlTimestamp == null) { + return null; + } + + return OffsetTime.parse(sqlTimestamp, DateTimeFormatter.ISO_OFFSET_TIME); + } +} diff --git a/src/main/java/com/yello/server/global/common/entity/ZonedDateTimeConverter.java b/src/main/java/com/yello/server/global/common/entity/ZonedDateTimeConverter.java new file mode 100644 index 00000000..d8b31b86 --- /dev/null +++ b/src/main/java/com/yello/server/global/common/entity/ZonedDateTimeConverter.java @@ -0,0 +1,28 @@ +package com.yello.server.global.common.entity; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +@Converter +public class ZonedDateTimeConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(ZonedDateTime zonedDateTime) { + if (zonedDateTime == null) { + return null; + } + + return zonedDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + + @Override + public ZonedDateTime convertToEntityAttribute(String sqlTimestamp) { + if (sqlTimestamp == null) { + return null; + } + + return ZonedDateTime.parse(sqlTimestamp, DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } +} diff --git a/src/main/java/com/yello/server/global/configuration/QueryDslConfiguration.java b/src/main/java/com/yello/server/global/configuration/QueryDslConfiguration.java index fadbf0eb..24cc3417 100644 --- a/src/main/java/com/yello/server/global/configuration/QueryDslConfiguration.java +++ b/src/main/java/com/yello/server/global/configuration/QueryDslConfiguration.java @@ -1,8 +1,8 @@ package com.yello.server.global.configuration; import com.querydsl.jpa.impl.JPAQueryFactory; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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 dc47dd57..1e54d6aa 100644 --- a/src/main/java/com/yello/server/global/exception/ControllerExceptionAdvice.java +++ b/src/main/java/com/yello/server/global/exception/ControllerExceptionAdvice.java @@ -41,7 +41,7 @@ import com.yello.server.domain.vote.exception.VoteNotFoundException; import com.yello.server.global.common.dto.BaseResponse; import com.yello.server.infrastructure.slack.factory.SlackWebhookMessageFactory; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import net.gpedro.integrations.slack.SlackApi; import net.gpedro.integrations.slack.SlackMessage; import org.springframework.beans.factory.annotation.Qualifier; diff --git a/src/main/java/com/yello/server/global/exception/ExceptionHandlerFilter.java b/src/main/java/com/yello/server/global/exception/ExceptionHandlerFilter.java index 66be1ebf..40153f02 100644 --- a/src/main/java/com/yello/server/global/exception/ExceptionHandlerFilter.java +++ b/src/main/java/com/yello/server/global/exception/ExceptionHandlerFilter.java @@ -7,11 +7,11 @@ import com.yello.server.global.common.ErrorCode; import com.yello.server.global.common.dto.BaseResponse; import com.yello.server.global.common.dto.MultiReadHttpServletRequest; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import org.springframework.web.filter.OncePerRequestFilter; public class ExceptionHandlerFilter extends OncePerRequestFilter { @@ -23,7 +23,7 @@ protected void doFilterInternal( FilterChain filterChain ) throws ServletException, IOException { MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest(request); - + try { filterChain.doFilter(multiReadRequest, response); } catch (CustomException exception) { diff --git a/src/main/java/com/yello/server/infrastructure/client/AppleApiWebClient.java b/src/main/java/com/yello/server/infrastructure/client/AppleApiWebClient.java index a3626bbc..766150f8 100644 --- a/src/main/java/com/yello/server/infrastructure/client/AppleApiWebClient.java +++ b/src/main/java/com/yello/server/infrastructure/client/AppleApiWebClient.java @@ -11,6 +11,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.WebClient; @@ -32,9 +33,9 @@ public ResponseEntity appleGetTransaction( ResponseEntity transactionResponse = getTransactionByWebClient(appleTransaction, APPLE_PRODUCTION_URL); - HttpStatus statusCode = transactionResponse.getStatusCode(); + HttpStatusCode statusCode = transactionResponse.getStatusCode(); - if (transactionResponse==null) { + if (transactionResponse == null) { throw new PurchaseException(NOT_FOUND_TRANSACTION_EXCEPTION); } if (statusCode.equals(HttpStatus.NOT_FOUND)) { diff --git a/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackApplePurchaseNotificationAspect.java b/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackApplePurchaseNotificationAspect.java index b7400a90..37b0f487 100644 --- a/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackApplePurchaseNotificationAspect.java +++ b/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackApplePurchaseNotificationAspect.java @@ -1,7 +1,7 @@ package com.yello.server.infrastructure.slack.aspect; import com.yello.server.infrastructure.slack.factory.SlackWebhookMessageFactory; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import net.gpedro.integrations.slack.SlackApi; import net.gpedro.integrations.slack.SlackMessage; import org.aspectj.lang.ProceedingJoinPoint; 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 index 1a1d9853..f2f60320 100644 --- a/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackPurchaseNotificationAspect.java +++ b/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackPurchaseNotificationAspect.java @@ -1,7 +1,7 @@ package com.yello.server.infrastructure.slack.aspect; import com.yello.server.infrastructure.slack.factory.SlackWebhookMessageFactory; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import net.gpedro.integrations.slack.SlackApi; import net.gpedro.integrations.slack.SlackMessage; import org.aspectj.lang.ProceedingJoinPoint; diff --git a/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackSignUpNotificationAspect.java b/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackSignUpNotificationAspect.java index 03b50b12..e8c31d78 100644 --- a/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackSignUpNotificationAspect.java +++ b/src/main/java/com/yello/server/infrastructure/slack/aspect/SlackSignUpNotificationAspect.java @@ -1,7 +1,7 @@ package com.yello.server.infrastructure.slack.aspect; import com.yello.server.infrastructure.slack.factory.SlackWebhookMessageFactory; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import net.gpedro.integrations.slack.SlackApi; import net.gpedro.integrations.slack.SlackMessage; import org.aspectj.lang.ProceedingJoinPoint; 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 index 8d164f94..82b19f0c 100644 --- a/src/main/java/com/yello/server/infrastructure/slack/factory/SlackWebhookMessageFactory.java +++ b/src/main/java/com/yello/server/infrastructure/slack/factory/SlackWebhookMessageFactory.java @@ -8,6 +8,7 @@ import com.yello.server.domain.user.repository.UserRepository; import com.yello.server.global.common.factory.TimeFactory; import com.yello.server.infrastructure.slack.dto.response.SlackAppleNotificationResponse; +import jakarta.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -17,7 +18,6 @@ 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; @@ -39,10 +39,9 @@ public class SlackWebhookMessageFactory { private static final String APPLE_PURCHASE_ALARM_TITLE = "애플이 결제 관련 알림을 보냈습니다."; private static final String APPLE_PURCHASE_ALARM_USERNAME = "애플 뱅크 알림"; - - private final UserRepository userRepository; - private final TokenProvider tokenProvider; private final PurchaseManager purchaseManager; + private final TokenProvider tokenProvider; + private final UserRepository userRepository; private static String getRequestBody(HttpServletRequest request) throws IOException { @@ -52,7 +51,7 @@ private static String getRequestBody(HttpServletRequest request) throws IOExcept try { InputStream inputStream = request.getInputStream(); - if (inputStream!=null) { + if (inputStream != null) { bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); char[] charBuffer = new char[128]; int bytesRead = -1; @@ -63,7 +62,7 @@ private static String getRequestBody(HttpServletRequest request) throws IOExcept } catch (IOException ex) { throw ex; } finally { - if (bufferedReader!=null) { + if (bufferedReader != null) { try { bufferedReader.close(); } catch (IOException ex) { @@ -173,10 +172,10 @@ private List generateSlackFieldList( HttpServletRequest request ) throws IOException { final String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION); - final String token = authHeader==null ? "null" : authHeader.substring("Bearer ".length()); - final Long userId = authHeader==null ? -1L : tokenProvider.getUserId(token); + final String token = authHeader == null ? "null" : authHeader.substring("Bearer ".length()); + final Long userId = authHeader == null ? -1L : tokenProvider.getUserId(token); final Optional user = - authHeader==null ? Optional.empty() : userRepository.findById(userId); + authHeader == null ? Optional.empty() : userRepository.findById(userId); final String yelloId = user.isPresent() ? user.get().getYelloId() : "null"; final String deviceToken = user.isPresent() ? user.get().getDeviceToken() : "null"; diff --git a/src/main/resources/static/docs/add-friend.html b/src/main/resources/static/docs/add-friend.html index 70ee9041..64bb0f9c 100644 --- a/src/main/resources/static/docs/add-friend.html +++ b/src/main/resources/static/docs/add-friend.html @@ -4,25 +4,23 @@ - + 친구 추가하기 + + + +
+
+

공지 조회

+
+
+

요청

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

응답

+
+
+
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" : "LUNCH_EVENT",
+    "startDate" : "2024-01-01T00:00:00+09:00",
+    "endDate" : "2024-12-31T00:00:00+09:00",
+    "title" : "점심 시간 깜짝 선물!",
+    "subTitle" : "평일 12-14시 최대 1회까지 참여 가능",
+    "animationList" : [ {
+      "v" : "로티1"
+    }, {
+      "v" : "로티2"
+    } ],
+    "eventReward" : {
+      "startTime" : "12:00+09:00",
+      "endTime" : "14:00+09:00",
+      "rewardCount" : 1,
+      "eventRewardItem" : [ {
+        "tag" : "POINT",
+        "eventRewardTitle" : "최대 200P",
+        "eventRewardImage" : "https://storage.googleapis.com/yelloworld/image/coin-stack.svg",
+        "maxRewardValue" : 200,
+        "minRewardValue" : 10,
+        "eventRewardProbability" : 10,
+        "randomTag" : "FIXED"
+      }, {
+        "tag" : "TICKET",
+        "eventRewardTitle" : "열람권 1개",
+        "eventRewardImage" : "https://storage.googleapis.com/yelloworld/image/key.svg",
+        "maxRewardValue" : 1,
+        "minRewardValue" : 1,
+        "eventRewardProbability" : 90,
+        "randomTag" : "RANDOM"
+      } ]
+    }
+  }, {
+    "tag" : "ADMOB",
+    "startDate" : "2024-01-01T00:00:00+09:00",
+    "endDate" : "2024-12-31T00:00:00+09:00",
+    "title" : "ADMOB 광고입니다.",
+    "subTitle" : "ADMOB 광고는 영구 사용 가능 설정입니다",
+    "animationList" : [ ],
+    "eventReward" : {
+      "startTime" : "00:00+09:00",
+      "endTime" : "23:59:59.000999999+09:00",
+      "rewardCount" : 1,
+      "eventRewardItem" : [ {
+        "tag" : "ADMOB_POINT",
+        "eventRewardTitle" : "광고 보고 포인트 얻기",
+        "eventRewardImage" : "https://storage.googleapis.com/yelloworld/image/coin-stack.svg",
+        "maxRewardValue" : 50,
+        "minRewardValue" : 50,
+        "eventRewardProbability" : 100,
+        "randomTag" : "FIXED"
+      } ]
+    }
+  } ]
+}
+
+
+
+
+
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" : "LUNCH_EVENT",
+    "startDate" : "2024-01-01T00:00:00+09:00",
+    "endDate" : "2024-12-31T00:00:00+09:00",
+    "title" : "점심 시간 깜짝 선물!",
+    "subTitle" : "평일 12-14시 최대 1회까지 참여 가능",
+    "animationList" : [ {
+      "v" : "로티1"
+    }, {
+      "v" : "로티2"
+    } ],
+    "eventReward" : {
+      "startTime" : "22:00+09:00",
+      "endTime" : "00:00+09:00",
+      "rewardCount" : 1,
+      "eventRewardItem" : [ {
+        "tag" : "POINT",
+        "eventRewardTitle" : "최대 200P",
+        "eventRewardImage" : "https://storage.googleapis.com/yelloworld/image/coin-stack.svg",
+        "maxRewardValue" : 200,
+        "minRewardValue" : 10,
+        "eventRewardProbability" : 40,
+        "randomTag" : "FIXED"
+      }, {
+        "tag" : "TICKET",
+        "eventRewardTitle" : "열람권 1개",
+        "eventRewardImage" : "https://storage.googleapis.com/yelloworld/image/key.svg",
+        "maxRewardValue" : 1,
+        "minRewardValue" : 1,
+        "eventRewardProbability" : 60,
+        "randomTag" : "RANDOM"
+      } ]
+    }
+  }, {
+    "tag" : "ADMOB",
+    "startDate" : "2024-01-01T00:00:00+09:00",
+    "endDate" : "2024-12-31T00:00:00+09:00",
+    "title" : "ADMOB 광고입니다.",
+    "subTitle" : "ADMOB 광고는 영구 사용 가능 설정입니다",
+    "animationList" : [ ],
+    "eventReward" : {
+      "startTime" : "00:00+09:00",
+      "endTime" : "23:59:59.000999999+09:00",
+      "rewardCount" : 1,
+      "eventRewardItem" : [ {
+        "tag" : "ADMOB_POINT",
+        "eventRewardTitle" : "광고 보고 포인트 얻기",
+        "eventRewardImage" : "https://storage.googleapis.com/yelloworld/image/coin-stack.svg",
+        "maxRewardValue" : 50,
+        "minRewardValue" : 50,
+        "eventRewardProbability" : 100,
+        "randomTag" : "FIXED"
+      } ]
+    }
+  } ]
+}
+
+
+
+
+
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" : "LUNCH_EVENT",
+    "startDate" : "2024-01-01T00:00:00+09:00",
+    "endDate" : "2024-12-31T00:00:00+09:00",
+    "title" : "점심 시간 깜짝 선물!",
+    "subTitle" : "평일 12-14시 최대 1회까지 참여 가능",
+    "animationList" : [ {
+      "v" : "로티1"
+    }, {
+      "v" : "로티2"
+    } ],
+    "eventReward" : null
+  }, {
+    "tag" : "ADMOB",
+    "startDate" : "2024-01-01T00:00:00+09:00",
+    "endDate" : "2024-12-31T00:00:00+09:00",
+    "title" : "ADMOB 광고입니다.",
+    "subTitle" : "ADMOB 광고는 영구 사용 가능 설정입니다",
+    "animationList" : [ ],
+    "eventReward" : {
+      "startTime" : "00:00+09:00",
+      "endTime" : "23:59:59.000999999+09:00",
+      "rewardCount" : 1,
+      "eventRewardItem" : [ {
+        "tag" : "ADMOB_POINT",
+        "eventRewardTitle" : "광고 보고 포인트 얻기",
+        "eventRewardImage" : "https://storage.googleapis.com/yelloworld/image/coin-stack.svg",
+        "maxRewardValue" : 50,
+        "minRewardValue" : 50,
+        "eventRewardProbability" : 100,
+        "randomTag" : "FIXED"
+      } ]
+    }
+  } ]
+}
+
+
+
+
+

주의

+
+
    +
  • +

    data: Response[]

    +
  • +
  • +

    Response

    +
  • +
  • +

    tag : "LUNCH_EVENT" | "ADMOB"

    +
    +
      +
    • +

      LUNCH_EVENT에 해당하는 *Response*가 없으면 Render 해주지 말아주세요

      +
    • +
    +
    +
  • +
  • +

    startDate : "2024-01-01T00:00:00+09:00"

    +
  • +
  • +

    endDate : "2024-12-31T00:00:00+09:00"

    +
  • +
  • +

    title : "점심 시간 깜짝 선물!"

    +
  • +
  • +

    subTitle : "평일 12-14시 최대 1회까지 참여 가능"

    +
  • +
  • +

    animationList : [{…​json1…​}, {…​json2…​}]

    +
  • +
  • +

    eventReward: EventReward | null

    +
    +
      +
    • +

      해당 필드가 null일 시, 이벤트 보여주지 않도록 해주세요.

      +
    • +
    +
    +
  • +
+
+
+
+

NOTE

+
+
    +
  • +

    ! LUNCH_EVENT에 해당하는 Response가 없거나, LUNCH_EVENT Response의 eventReward가 null이면, 메인화면 접속시, 이벤트 화면을 띄워주지마세요.

    +
  • +
  • +

    이벤트 참여 요청, 이벤트 보상 반환 API 문서 작성중..

    +
  • +
+
+
+
+

CHANGELOG

+
+
    +
  • +

    2024.02.06 릴리즈

    +
  • +
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/find-friend-votes-v2.html b/src/main/resources/static/docs/find-friend-votes-v2.html index 1d226c3a..c799b0c0 100644 --- a/src/main/resources/static/docs/find-friend-votes-v2.html +++ b/src/main/resources/static/docs/find-friend-votes-v2.html @@ -4,25 +4,23 @@ - + 친구 투표 전체 조회 v2 + +
+

Event API

+
+ +
+
- - - + + \ No newline at end of file diff --git a/src/main/resources/static/docs/login.html b/src/main/resources/static/docs/login.html index fd84b612..79046842 100644 --- a/src/main/resources/static/docs/login.html +++ b/src/main/resources/static/docs/login.html @@ -4,25 +4,23 @@ - + 소셜 로그인