From 43e9785f0d322804f5c9e38b1e09d3cdd33d048f Mon Sep 17 00:00:00 2001 From: seokjin8678 Date: Thu, 31 Aug 2023 14:11:19 +0900 Subject: [PATCH 01/74] =?UTF-8?q?[BE]=20hot-fix:=20=ED=9A=8C=EC=9B=90=20?= =?UTF-8?q?=ED=83=88=ED=87=B4=20Path=EC=97=90=20Interceptor=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20(#389)=20(#391)=20(#394)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: AuthPayload id 검증 제거 * fix: 누락된 경로 인터셉터에 추가 * chore: 테스트명 수정 --- .../com/festago/auth/config/LoginConfig.java | 3 +- .../com/festago/auth/domain/AuthPayload.java | 6 ++-- .../infrastructure/JwtAuthExtractorTest.java | 15 ---------- .../auth/presentation/AuthControllerTest.java | 28 +++++++++++++++++++ 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/backend/src/main/java/com/festago/auth/config/LoginConfig.java b/backend/src/main/java/com/festago/auth/config/LoginConfig.java index 68a6eff6d..72439a2eb 100644 --- a/backend/src/main/java/com/festago/auth/config/LoginConfig.java +++ b/backend/src/main/java/com/festago/auth/config/LoginConfig.java @@ -38,7 +38,8 @@ public void addInterceptors(InterceptorRegistry registry) { .addPathPatterns("/admin/**", "/js/admin/**") .excludePathPatterns("/admin/login", "/admin/initialize"); registry.addInterceptor(memberAuthInterceptor()) - .addPathPatterns("/member-tickets/**", "/members/**"); + .addPathPatterns("/member-tickets/**", "/members/**", "/auth/**") + .excludePathPatterns("/auth/oauth2"); } @Bean diff --git a/backend/src/main/java/com/festago/auth/domain/AuthPayload.java b/backend/src/main/java/com/festago/auth/domain/AuthPayload.java index 253b559e8..0c8f91b12 100644 --- a/backend/src/main/java/com/festago/auth/domain/AuthPayload.java +++ b/backend/src/main/java/com/festago/auth/domain/AuthPayload.java @@ -9,13 +9,13 @@ public class AuthPayload { private final Role role; public AuthPayload(Long memberId, Role role) { - validate(memberId, role); + validate(role); this.memberId = memberId; this.role = role; } - private void validate(Long memberId, Role role) { - if (memberId == null || role == null) { + private void validate(Role role) { + if (role == null) { throw new InternalServerException(ErrorCode.INVALID_AUTH_TOKEN_PAYLOAD); } } diff --git a/backend/src/test/java/com/festago/auth/infrastructure/JwtAuthExtractorTest.java b/backend/src/test/java/com/festago/auth/infrastructure/JwtAuthExtractorTest.java index d23eeac46..209ce2558 100644 --- a/backend/src/test/java/com/festago/auth/infrastructure/JwtAuthExtractorTest.java +++ b/backend/src/test/java/com/festago/auth/infrastructure/JwtAuthExtractorTest.java @@ -71,21 +71,6 @@ class JwtAuthExtractorTest { .hasMessage("올바르지 않은 로그인 토큰입니다."); } - @Test - void memberId_필드가_없으면_예외() { - // given - String token = Jwts.builder() - .claim(ROLE_ID_KEY, Role.MEMBER) - .setExpiration(new Date(new Date().getTime() + 10000)) - .signWith(KEY, SignatureAlgorithm.HS256) - .compact(); - - // when & then - assertThatThrownBy(() -> jwtAuthExtractor.extract(token)) - .isInstanceOf(InternalServerException.class) - .hasMessage("유효하지 않은 로그인 토큰 payload 입니다."); - } - @Test void role_필드가_없으면_예외() { // given diff --git a/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java b/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java index c7edf6904..738b648fb 100644 --- a/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java +++ b/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java @@ -3,16 +3,19 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; import com.festago.auth.application.AuthService; +import com.festago.auth.domain.Role; import com.festago.auth.domain.SocialType; import com.festago.auth.dto.LoginRequest; import com.festago.auth.dto.LoginResponse; import com.festago.support.CustomWebMvcTest; +import com.festago.support.WithMockAuth; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; @@ -56,4 +59,29 @@ class AuthControllerTest { assertThat(actual).isEqualTo(expected); } + + @Test + void 로그인을_하지_않고_탈퇴를_하면_예외() throws Exception { + mockMvc.perform(delete("/auth") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockAuth(role = Role.ADMIN) + void 멤버_권한이_아닌데_탈퇴하면_예외() throws Exception { + mockMvc.perform(delete("/auth") + .header("Authorization", "Bearer token") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockAuth + void 회원_탈퇴를_한다() throws Exception { + mockMvc.perform(delete("/auth") + .header("Authorization", "Bearer token") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } } From 93d8aeed2791c1c0e5376aac95a1eccb7e34bab9 Mon Sep 17 00:00:00 2001 From: seokjin8678 Date: Thu, 31 Aug 2023 14:40:58 +0900 Subject: [PATCH 02/74] =?UTF-8?q?[BE]=20refactor:=20LocalDateTime.now()=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9D=84=20LocalDateTime.now(clock)=20?= =?UTF-8?q?=ED=98=95=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20(#3?= =?UTF-8?q?95)=20(#400)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: LocalDateTime.now(Clock) 형식으로 변경 * test: 현재 시간 -> 고정된 시간으로 변경 * test: Clock의 instant를 생성하는 support class 추가 * test: TimeInstantProvider 메소드 명 변경 --------- Co-authored-by: hyunseo --- .../com/festago/application/EntryService.java | 7 ++- .../application/MemberTicketService.java | 7 ++- .../festago/application/EntryServiceTest.java | 52 +++++++++++++++---- .../application/MemberTicketServiceTest.java | 5 ++ .../festago/support/TimeInstantProvider.java | 17 ++++++ 5 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 backend/src/test/java/com/festago/support/TimeInstantProvider.java diff --git a/backend/src/main/java/com/festago/application/EntryService.java b/backend/src/main/java/com/festago/application/EntryService.java index e71eeec3e..e4073a633 100644 --- a/backend/src/main/java/com/festago/application/EntryService.java +++ b/backend/src/main/java/com/festago/application/EntryService.java @@ -12,6 +12,7 @@ import com.festago.exception.BadRequestException; import com.festago.exception.ErrorCode; import com.festago.exception.NotFoundException; +import java.time.Clock; import java.time.LocalDateTime; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -23,12 +24,14 @@ public class EntryService { private final EntryCodeProvider entryCodeProvider; private final EntryCodeExtractor entryCodeExtractor; private final MemberTicketRepository memberTicketRepository; + private final Clock clock; public EntryService(EntryCodeProvider entryCodeProvider, EntryCodeExtractor entryCodeExtractor, - MemberTicketRepository memberTicketRepository) { + MemberTicketRepository memberTicketRepository, Clock clock) { this.entryCodeProvider = entryCodeProvider; this.entryCodeExtractor = entryCodeExtractor; this.memberTicketRepository = memberTicketRepository; + this.clock = clock; } public EntryCodeResponse createEntryCode(Long memberId, Long memberTicketId) { @@ -36,7 +39,7 @@ public EntryCodeResponse createEntryCode(Long memberId, Long memberTicketId) { if (!memberTicket.isOwner(memberId)) { throw new BadRequestException(ErrorCode.NOT_MEMBER_TICKET_OWNER); } - if (!memberTicket.canEntry(LocalDateTime.now())) { + if (!memberTicket.canEntry(LocalDateTime.now(clock))) { throw new BadRequestException(ErrorCode.NOT_ENTRY_TIME); } EntryCode entryCode = EntryCode.create(entryCodeProvider, memberTicket); diff --git a/backend/src/main/java/com/festago/application/MemberTicketService.java b/backend/src/main/java/com/festago/application/MemberTicketService.java index 6768311c0..050d05f46 100644 --- a/backend/src/main/java/com/festago/application/MemberTicketService.java +++ b/backend/src/main/java/com/festago/application/MemberTicketService.java @@ -12,6 +12,7 @@ import com.festago.exception.BadRequestException; import com.festago.exception.ErrorCode; import com.festago.exception.NotFoundException; +import java.time.Clock; import java.time.Duration; import java.time.LocalDateTime; import java.util.List; @@ -25,11 +26,13 @@ public class MemberTicketService { private final MemberTicketRepository memberTicketRepository; private final MemberRepository memberRepository; + private final Clock clock; public MemberTicketService(MemberTicketRepository memberTicketRepository, - MemberRepository memberRepository) { + MemberRepository memberRepository, Clock clock) { this.memberTicketRepository = memberTicketRepository; this.memberRepository = memberRepository; + this.clock = clock; } @Transactional(readOnly = true) @@ -59,7 +62,7 @@ public MemberTicketsResponse findCurrent(Long memberId, Pageable pageable) { } private List filterCurrentMemberTickets(List memberTickets) { - LocalDateTime currentTime = LocalDateTime.now(); + LocalDateTime currentTime = LocalDateTime.now(clock); return memberTickets.stream() .filter(memberTicket -> memberTicket.isBeforeEntry(currentTime) || memberTicket.canEntry(currentTime)) .sorted(comparing((MemberTicket memberTicket) -> memberTicket.isBeforeEntry(currentTime)) diff --git a/backend/src/test/java/com/festago/application/EntryServiceTest.java b/backend/src/test/java/com/festago/application/EntryServiceTest.java index 87bc9716b..47c55e311 100644 --- a/backend/src/test/java/com/festago/application/EntryServiceTest.java +++ b/backend/src/test/java/com/festago/application/EntryServiceTest.java @@ -25,7 +25,12 @@ import com.festago.support.MemberFixture; import com.festago.support.MemberTicketFixture; import com.festago.support.StageFixture; +import com.festago.support.TimeInstantProvider; +import java.time.Clock; +import java.time.Instant; import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.Optional; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; @@ -34,6 +39,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) @@ -50,6 +56,9 @@ class EntryServiceTest { @Mock MemberTicketRepository memberTicketRepository; + @Spy + Clock clock = Clock.systemDefaultZone(); + @InjectMocks EntryService entryService; @@ -59,9 +68,15 @@ class 티켓의_QR_생성_요청 { @Test void 입장_시간_전_요청하면_예외() { // given - LocalDateTime entryTime = LocalDateTime.now().plusMinutes(30); + LocalDateTime entryTime = LocalDateTime.parse("2023-07-30T16:00:00"); + Festival festival = FestivalFixture.festival() + .startDate(entryTime.toLocalDate()) + .endDate(entryTime.toLocalDate()) + .build(); Stage stage = StageFixture.stage() - .startTime(LocalDateTime.now().plusHours(1)) + .festival(festival) + .startTime(entryTime.plusHours(2)) + .ticketOpenTime(entryTime.minusHours(1)) .build(); MemberTicket memberTicket = MemberTicketFixture.memberTicket() .id(1L) @@ -70,9 +85,10 @@ class 티켓의_QR_생성_요청 { .build(); Long memberId = memberTicket.getOwner().getId(); Long memberTicketId = memberTicket.getId(); - given(memberTicketRepository.findById(anyLong())) .willReturn(Optional.of(memberTicket)); + given(clock.instant()) + .willReturn(TimeInstantProvider.from(entryTime.minusHours(1))); // when & then assertThatThrownBy(() -> entryService.createEntryCode(memberId, memberTicketId)) @@ -83,15 +99,15 @@ class 티켓의_QR_생성_요청 { @Test void 입장_시간이_24시간이_넘은_경우_예외() { // given - LocalDateTime stageStartTime = LocalDateTime.now().minusHours(24); - LocalDateTime entryTime = stageStartTime.minusSeconds(10); + LocalDateTime entryTime = LocalDateTime.parse("2023-07-30T16:00:00"); Festival festival = FestivalFixture.festival() - .startDate(stageStartTime.toLocalDate()) - .endDate(stageStartTime.toLocalDate()) + .startDate(entryTime.toLocalDate()) + .endDate(entryTime.toLocalDate()) .build(); Stage stage = StageFixture.stage() .festival(festival) - .startTime(stageStartTime) + .startTime(entryTime.plusHours(2)) + .ticketOpenTime(entryTime.minusHours(1)) .build(); MemberTicket memberTicket = MemberTicketFixture.memberTicket() .id(1L) @@ -100,9 +116,10 @@ class 티켓의_QR_생성_요청 { .build(); Long memberId = memberTicket.getOwner().getId(); Long memberTicketId = memberTicket.getId(); - given(memberTicketRepository.findById(anyLong())) .willReturn(Optional.of(memberTicket)); + given(clock.instant()) + .willReturn(TimeInstantProvider.from((entryTime.plusHours(24)))); // when & then assertThatThrownBy(() -> entryService.createEntryCode(memberId, memberTicketId)) @@ -113,14 +130,12 @@ class 티켓의_QR_생성_요청 { @Test void 자신의_티켓이_아니면_예외() { // given - LocalDateTime entryTime = LocalDateTime.now().minusMinutes(30); Long memberId = 1L; Member other = MemberFixture.member() .id(2L) .build(); MemberTicket otherTicket = MemberTicketFixture.memberTicket() .id(1L) - .entryTime(entryTime) .owner(other) .build(); Long memberTicketId = otherTicket.getId(); @@ -150,8 +165,21 @@ class 티켓의_QR_생성_요청 { @Test void 성공() { // given + LocalDateTime entryTime = LocalDateTime.parse("2023-07-30T16:00:00"); + Instant now = Instant.from(ZonedDateTime.of(entryTime, ZoneId.systemDefault())); + Festival festival = FestivalFixture.festival() + .startDate(entryTime.toLocalDate()) + .endDate(entryTime.toLocalDate()) + .build(); + Stage stage = StageFixture.stage() + .festival(festival) + .startTime(entryTime.plusHours(2)) + .ticketOpenTime(entryTime.minusHours(1)) + .build(); MemberTicket memberTicket = MemberTicketFixture.memberTicket() .id(1L) + .stage(stage) + .entryTime(entryTime) .build(); String code = "3112321312123"; Long memberId = memberTicket.getOwner().getId(); @@ -161,6 +189,8 @@ class 티켓의_QR_생성_요청 { .willReturn(Optional.of(memberTicket)); given(entryCodeProvider.provide(any(), any())) .willReturn(code); + given(clock.instant()) + .willReturn(now); // when EntryCodeResponse entryCode = entryService.createEntryCode(memberId, memberTicketId); diff --git a/backend/src/test/java/com/festago/application/MemberTicketServiceTest.java b/backend/src/test/java/com/festago/application/MemberTicketServiceTest.java index fb111b411..591a820c1 100644 --- a/backend/src/test/java/com/festago/application/MemberTicketServiceTest.java +++ b/backend/src/test/java/com/festago/application/MemberTicketServiceTest.java @@ -19,6 +19,7 @@ import com.festago.support.MemberFixture; import com.festago.support.MemberTicketFixture; import com.festago.support.StageFixture; +import java.time.Clock; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -29,6 +30,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -44,6 +46,9 @@ class MemberTicketServiceTest { @Mock MemberRepository memberRepository; + @Spy + Clock clock = Clock.systemDefaultZone(); + @InjectMocks MemberTicketService memberTicketService; diff --git a/backend/src/test/java/com/festago/support/TimeInstantProvider.java b/backend/src/test/java/com/festago/support/TimeInstantProvider.java new file mode 100644 index 000000000..3de862d1e --- /dev/null +++ b/backend/src/test/java/com/festago/support/TimeInstantProvider.java @@ -0,0 +1,17 @@ +package com.festago.support; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +public class TimeInstantProvider { + + public static Instant from(String localDateTime) { + return from(LocalDateTime.parse(localDateTime)); + } + + public static Instant from(LocalDateTime localDateTime) { + return Instant.from(ZonedDateTime.of(localDateTime, ZoneId.systemDefault())); + } +} From a8f541b3140992cb220d60f92aef97272d6fc0c3 Mon Sep 17 00:00:00 2001 From: seokjin8678 Date: Thu, 31 Aug 2023 14:49:38 +0900 Subject: [PATCH 03/74] =?UTF-8?q?[ALL]=20feat:=20Github=20Action=20workflo?= =?UTF-8?q?w=20=EC=8B=A4=ED=96=89=20=EC=A1=B0=EA=B1=B4=EC=97=90=20main=20?= =?UTF-8?q?=EB=B8=8C=EB=9E=9C=EC=B9=98=20=ED=8F=AC=ED=95=A8=20(#392)=20(#3?= =?UTF-8?q?93)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/assign-reviewer.yml | 7 +- .github/workflows/ci-back.yml | 1 + .github/workflows/ci-user-aos.yml | 66 +++++++++--------- .../workflows/closed-issue-notification.yml | 69 ++++++++++--------- .github/workflows/closed-pr-notification.yml | 7 +- .../workflows/opend-issue-notification.yml | 69 ++++++++++--------- .github/workflows/opened-pr-notification.yml | 7 +- 7 files changed, 120 insertions(+), 106 deletions(-) diff --git a/.github/workflows/assign-reviewer.yml b/.github/workflows/assign-reviewer.yml index d3ea0164e..722ea9786 100644 --- a/.github/workflows/assign-reviewer.yml +++ b/.github/workflows/assign-reviewer.yml @@ -1,8 +1,11 @@ name: Assign Reviewer By Label on: pull_request: - types: [ opened, edited, labeled, unlabeled ] - + types: + - opened + - edited + - labeled + - unlabeled jobs: assign-reviewer: runs-on: ubuntu-latest diff --git a/.github/workflows/ci-back.yml b/.github/workflows/ci-back.yml index cec9580d9..849fea334 100644 --- a/.github/workflows/ci-back.yml +++ b/.github/workflows/ci-back.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - dev + - main paths: 'backend/**' defaults: diff --git a/.github/workflows/ci-user-aos.yml b/.github/workflows/ci-user-aos.yml index d31f3b75a..2ef6e561b 100644 --- a/.github/workflows/ci-user-aos.yml +++ b/.github/workflows/ci-user-aos.yml @@ -4,10 +4,12 @@ on: push: branches: - dev - paths: ['android/festago/**'] + - main + paths: [ 'android/festago/**' ] pull_request: branches: - dev + - main paths: 'android/festago/**' defaults: @@ -20,35 +22,35 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: 17 - distribution: zulu - cache: gradle - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: add google-services.json - run: echo '${{ secrets.ANDROID_USER_GOOGLE_SERVICES_JSON }}' > ./app/google-services.json - - - name: add local.properties - run: | - echo kakao_native_app_key=\"${{ secrets.ANDROID_USER_KAKAO_NATIVE_APP_KEY }}\" >> ./local.properties - echo kakao_redirection_scheme=\"${{ secrets.ANDROID_USER_KAKAO_REDIRECTION_SCHEME }}\" >> ./local.properties - echo base_url=\"$${{ secrets.ANDROID_USER_BASE_URL }}\" >> ./local.properties - - - name: Build with Gradle - run: ./gradlew build - - - name: Run ktlint - run: ./gradlew ktlintCheck - - - name: Run unit tests - run: ./gradlew testDebugUnitTest - - - name: Build assemble release apk - run: ./gradlew assembleRelease + - uses: actions/checkout@v3 + - name: set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: zulu + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: add google-services.json + run: echo '${{ secrets.ANDROID_USER_GOOGLE_SERVICES_JSON }}' > ./app/google-services.json + + - name: add local.properties + run: | + echo kakao_native_app_key=\"${{ secrets.ANDROID_USER_KAKAO_NATIVE_APP_KEY }}\" >> ./local.properties + echo kakao_redirection_scheme=\"${{ secrets.ANDROID_USER_KAKAO_REDIRECTION_SCHEME }}\" >> ./local.properties + echo base_url=\"$${{ secrets.ANDROID_USER_BASE_URL }}\" >> ./local.properties + + - name: Build with Gradle + run: ./gradlew build + + - name: Run ktlint + run: ./gradlew ktlintCheck + + - name: Run unit tests + run: ./gradlew testDebugUnitTest + + - name: Build assemble release apk + run: ./gradlew assembleRelease diff --git a/.github/workflows/closed-issue-notification.yml b/.github/workflows/closed-issue-notification.yml index 37da67fbc..6031248af 100644 --- a/.github/workflows/closed-issue-notification.yml +++ b/.github/workflows/closed-issue-notification.yml @@ -1,39 +1,40 @@ name: Closed Issue Notification on: - issues: - types: [closed] - + issues: + types: + - closed + jobs: - create-issue: + create-issue: name: Send closed issue notification to slack - runs-on: ubuntu-latest - steps: - - name: Send Issue - uses: 8398a7/action-slack@v3 - with: - status: custom - custom_payload: | - { - text: "*이슈가 닫혔습니다!*", - attachments: [{ - fallback: 'fallback', - color: '#7539DE', - title: 'Title', - text: '<${{ github.event.issue.html_url }}|${{ github.event.issue.title }}>', - fields: [{ - title: 'Issue number', - value: '#${{ github.event.issue.number }}', - short: true - }, - { - title: 'Author', - value: '${{ github.event.issue.user.login }}', - short: true - }], - actions: [{ + runs-on: ubuntu-latest + steps: + - name: Send Issue + uses: 8398a7/action-slack@v3 + with: + status: custom + custom_payload: | + { + text: "*이슈가 닫혔습니다!*", + attachments: [{ + fallback: 'fallback', + color: '#7539DE', + title: 'Title', + text: '<${{ github.event.issue.html_url }}|${{ github.event.issue.title }}>', + fields: [{ + title: 'Issue number', + value: '#${{ github.event.issue.number }}', + short: true + }, + { + title: 'Author', + value: '${{ github.event.issue.user.login }}', + short: true + }], + actions: [{ + }] }] - }] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_ISSUE_WEBHOOK_URL }} - if: always() + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_ISSUE_WEBHOOK_URL }} + if: always() diff --git a/.github/workflows/closed-pr-notification.yml b/.github/workflows/closed-pr-notification.yml index eec190437..d92c2d37e 100644 --- a/.github/workflows/closed-pr-notification.yml +++ b/.github/workflows/closed-pr-notification.yml @@ -1,8 +1,11 @@ name: Closed PR Notification on: pull_request: - branches: [ dev ] - types: [ closed ] + branches: + - dev + - main + types: + - closed jobs: create-issue: diff --git a/.github/workflows/opend-issue-notification.yml b/.github/workflows/opend-issue-notification.yml index 4bda56c88..2204395bb 100644 --- a/.github/workflows/opend-issue-notification.yml +++ b/.github/workflows/opend-issue-notification.yml @@ -1,39 +1,40 @@ name: Opend Issue Notification on: - issues: - types: [opened] - + issues: + types: + - opened + jobs: - create-issue: + create-issue: name: Send opend issue notification to slack - runs-on: ubuntu-latest - steps: - - name: Send Issue - uses: 8398a7/action-slack@v3 - with: - status: custom - custom_payload: | - { - text: "*새로운 이슈가 생성되었습니다!*", - attachments: [{ - fallback: 'fallback', - color: '#1F7629', - title: 'Title', - text: '<${{ github.event.issue.html_url }}|${{ github.event.issue.title }}>', - fields: [{ - title: 'Issue number', - value: '#${{ github.event.issue.number }}', - short: true - }, - { - title: 'Author', - value: '${{ github.event.issue.user.login }}', - short: true - }], - actions: [{ + runs-on: ubuntu-latest + steps: + - name: Send Issue + uses: 8398a7/action-slack@v3 + with: + status: custom + custom_payload: | + { + text: "*새로운 이슈가 생성되었습니다!*", + attachments: [{ + fallback: 'fallback', + color: '#1F7629', + title: 'Title', + text: '<${{ github.event.issue.html_url }}|${{ github.event.issue.title }}>', + fields: [{ + title: 'Issue number', + value: '#${{ github.event.issue.number }}', + short: true + }, + { + title: 'Author', + value: '${{ github.event.issue.user.login }}', + short: true + }], + actions: [{ + }] }] - }] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_ISSUE_WEBHOOK_URL }} - if: always() + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_ISSUE_WEBHOOK_URL }} + if: always() diff --git a/.github/workflows/opened-pr-notification.yml b/.github/workflows/opened-pr-notification.yml index 00ff0314e..1ff6bba58 100644 --- a/.github/workflows/opened-pr-notification.yml +++ b/.github/workflows/opened-pr-notification.yml @@ -1,8 +1,11 @@ name: Opened PR Notification on: pull_request: - branches: [ dev ] - types: [ opened ] + branches: + - dev + - main + types: + - opened jobs: create-issue: From 6c7f8b194a8094b1a272c37b0423f85b12280f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=84=ED=81=AC?= <37167652+re4rk@users.noreply.github.com> Date: Thu, 31 Aug 2023 16:02:51 +0900 Subject: [PATCH 04/74] =?UTF-8?q?[AN]=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20presentation=20model=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20(#403)=20(#404)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 축제 정보 presentation model 삭제 * refactor: 예약 축제 정보 presentation model 삭제 --- .../presentation/mapper/FestivalMapper.kt | 9 ----- .../mapper/ReservationStageMapper.kt | 34 ------------------- .../presentation/model/FestivalUiModel.kt | 11 ------ .../model/ReservationStageUiModel.kt | 15 -------- 4 files changed, 69 deletions(-) delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/mapper/FestivalMapper.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationStageMapper.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/model/FestivalUiModel.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservationStageUiModel.kt diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/FestivalMapper.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/FestivalMapper.kt deleted file mode 100644 index b69bfa493..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/FestivalMapper.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.festago.festago.presentation.mapper - -import com.festago.festago.model.Festival -import com.festago.festago.presentation.model.FestivalUiModel - -fun Festival.toPresentation(): FestivalUiModel = - FestivalUiModel(id, name, startDate, endDate, thumbnail) - -fun List.toPresentation(): List = this.map { it.toPresentation() } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationStageMapper.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationStageMapper.kt deleted file mode 100644 index 4c5c35f64..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationStageMapper.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.festago.festago.presentation.mapper - -import com.festago.festago.model.ReservationStage -import com.festago.festago.presentation.model.ReservationStageUiModel -import com.festago.festago.presentation.ui.ticketreserve.TicketReserveItemUiState -import java.time.LocalDateTime - -fun List.toPresentation() = map { it.toPresentation() } - -fun ReservationStage.toPresentation() = ReservationStageUiModel( - id = id, - lineUp = lineUp, - reservationTickets = reservationTickets.map { it.toPresentation() }, - startTime = startTime, - ticketOpenTime = ticketOpenTime, - canReserve = LocalDateTime.now().isAfter(ticketOpenTime), -) - -fun ReservationStageUiModel.toDomain() = ReservationStage( - id = id, - lineUp = lineUp, - reservationTickets = reservationTickets.map { it.toDomain() }, - startTime = startTime, - ticketOpenTime = ticketOpenTime, -) - -fun TicketReserveItemUiState.toPresentation() = ReservationStageUiModel( - id = id, - lineUp = lineUp, - startTime = startTime, - ticketOpenTime = ticketOpenTime, - reservationTickets = reservationTickets, - canReserve = canReserve, -) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/model/FestivalUiModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/model/FestivalUiModel.kt deleted file mode 100644 index 44dadbad9..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/model/FestivalUiModel.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.festago.festago.presentation.model - -import java.time.LocalDate - -data class FestivalUiModel( - val id: Long, - val name: String, - val startDate: LocalDate, - val endDate: LocalDate, - val thumbnail: String, -) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservationStageUiModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservationStageUiModel.kt deleted file mode 100644 index a2662550a..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservationStageUiModel.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.festago.festago.presentation.model - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize -import java.time.LocalDateTime - -@Parcelize -data class ReservationStageUiModel( - val id: Int, - val lineUp: String, - val startTime: LocalDateTime, - val ticketOpenTime: LocalDateTime, - val reservationTickets: List, - val canReserve: Boolean, -) : Parcelable From d2ccd2357d979da195d597b5dcc2b0f08a98e0f6 Mon Sep 17 00:00:00 2001 From: xxeol2 Date: Thu, 31 Aug 2023 16:17:33 +0900 Subject: [PATCH 05/74] =?UTF-8?q?[BE]=20feat:=20=ED=95=99=EC=83=9D=20?= =?UTF-8?q?=EC=9D=B8=EC=A6=9D=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=A9=94=EC=9D=BC=20=EC=A0=84=EC=86=A1=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#125)=20(#388)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: spring-boot-starter-mail 의존성 추가 * feat: 인증 코드 생성 도메인 추가 * feat: 메일 발송 기능 추가 * feat: 메일 발송 API, 서비스 추가 * refactor: ThreadLocalRandom으로 변경 * refactor: 수정 -> 삭제로 변경 * test: StudentService 인증 메일 전송 테스트 작성 * fix: 최신 브랜치 반영 * refactor: 스레드간 독립적인 난수 생성 보장을 위한 ThreadLocalRandom 인스턴스변수화 * refactor: Random Code 생성 코드 리팩토링 * feat: 학생 인증 인증 기능 추가 * refactor: 사용하지 않는 메서드 삭제 * refactor: 코드 길이 상수로 추출 --------- Co-authored-by: seokjin8678 --- backend/build.gradle | 1 + .../festago/application/StudentService.java | 75 ++++++++ .../com/festago/auth/config/LoginConfig.java | 2 +- .../java/com/festago/config/AsyncConfig.java | 10 + .../java/com/festago/domain/MailClient.java | 6 + .../com/festago/domain/SchoolRepository.java | 7 + .../java/com/festago/domain/StudentCode.java | 57 ++++++ .../festago/domain/StudentCodeRepository.java | 8 + .../com/festago/domain/StudentRepository.java | 10 + .../com/festago/domain/VerificationCode.java | 53 ++++++ .../domain/VerificationCodeProvider.java | 6 + .../domain/VerificationMailPayload.java | 36 ++++ .../festago/dto/StudentSendMailRequest.java | 8 + .../java/com/festago/exception/ErrorCode.java | 3 + .../infrastructure/GoogleMailClient.java | 38 ++++ .../infrastructure/MockMailClient.java | 15 ++ .../RandomVerificationCodeProvider.java | 23 +++ .../presentation/StudentController.java | 33 ++++ .../application/StudentServiceTest.java | 171 ++++++++++++++++++ .../RandomVerificationCodeProviderTest.java | 24 +++ .../festago/domain/VerificationCodeTest.java | 54 ++++++ .../presentation/StudentControllerTest.java | 60 ++++++ 22 files changed, 699 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/com/festago/application/StudentService.java create mode 100644 backend/src/main/java/com/festago/config/AsyncConfig.java create mode 100644 backend/src/main/java/com/festago/domain/MailClient.java create mode 100644 backend/src/main/java/com/festago/domain/SchoolRepository.java create mode 100644 backend/src/main/java/com/festago/domain/StudentCode.java create mode 100644 backend/src/main/java/com/festago/domain/StudentCodeRepository.java create mode 100644 backend/src/main/java/com/festago/domain/StudentRepository.java create mode 100644 backend/src/main/java/com/festago/domain/VerificationCode.java create mode 100644 backend/src/main/java/com/festago/domain/VerificationCodeProvider.java create mode 100644 backend/src/main/java/com/festago/domain/VerificationMailPayload.java create mode 100644 backend/src/main/java/com/festago/dto/StudentSendMailRequest.java create mode 100644 backend/src/main/java/com/festago/infrastructure/GoogleMailClient.java create mode 100644 backend/src/main/java/com/festago/infrastructure/MockMailClient.java create mode 100644 backend/src/main/java/com/festago/infrastructure/RandomVerificationCodeProvider.java create mode 100644 backend/src/main/java/com/festago/presentation/StudentController.java create mode 100644 backend/src/test/java/com/festago/application/StudentServiceTest.java create mode 100644 backend/src/test/java/com/festago/domain/RandomVerificationCodeProviderTest.java create mode 100644 backend/src/test/java/com/festago/domain/VerificationCodeTest.java create mode 100644 backend/src/test/java/com/festago/presentation/StudentControllerTest.java diff --git a/backend/build.gradle b/backend/build.gradle index fc90dff7a..d28b12bcd 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -24,6 +24,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-mail' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' runtimeOnly 'com.h2database:h2' diff --git a/backend/src/main/java/com/festago/application/StudentService.java b/backend/src/main/java/com/festago/application/StudentService.java new file mode 100644 index 000000000..77e320730 --- /dev/null +++ b/backend/src/main/java/com/festago/application/StudentService.java @@ -0,0 +1,75 @@ +package com.festago.application; + +import com.festago.domain.MailClient; +import com.festago.domain.Member; +import com.festago.domain.MemberRepository; +import com.festago.domain.School; +import com.festago.domain.SchoolRepository; +import com.festago.domain.StudentCode; +import com.festago.domain.StudentCodeRepository; +import com.festago.domain.StudentRepository; +import com.festago.domain.VerificationCode; +import com.festago.domain.VerificationCodeProvider; +import com.festago.domain.VerificationMailPayload; +import com.festago.dto.StudentSendMailRequest; +import com.festago.exception.BadRequestException; +import com.festago.exception.ErrorCode; +import com.festago.exception.NotFoundException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class StudentService { + + private final MailClient mailClient; + private final VerificationCodeProvider codeProvider; + private final StudentCodeRepository studentCodeRepository; + private final SchoolRepository schoolRepository; + private final MemberRepository memberRepository; + private final StudentRepository studentRepository; + + public StudentService(MailClient mailClient, VerificationCodeProvider codeProvider, + StudentCodeRepository studentCodeRepository, SchoolRepository schoolRepository, + MemberRepository memberRepository, StudentRepository studentRepository) { + this.mailClient = mailClient; + this.codeProvider = codeProvider; + this.studentCodeRepository = studentCodeRepository; + this.schoolRepository = schoolRepository; + this.memberRepository = memberRepository; + this.studentRepository = studentRepository; + } + + public void sendVerificationMail(Long memberId, StudentSendMailRequest request) { + validateStudent(memberId); + validateDuplicateEmail(request); + Member member = findMember(memberId); + School school = findSchool(request.schoolId()); + VerificationCode code = codeProvider.provide(); + studentCodeRepository.deleteByMember(member); + studentCodeRepository.save(new StudentCode(code, member, school)); + mailClient.send(new VerificationMailPayload(code, request.username(), school.getDomain())); + } + + private void validateStudent(Long memberId) { + if (studentRepository.existsByMemberId(memberId)) { + throw new BadRequestException(ErrorCode.ALREADY_STUDENT_VERIFIED); + } + } + + private void validateDuplicateEmail(StudentSendMailRequest request) { + if (studentRepository.existsByUsernameAndSchoolId(request.username(), request.schoolId())) { + throw new BadRequestException(ErrorCode.DUPLICATE_STUDENT_EMAIL); + } + } + + private Member findMember(Long memberId) { + return memberRepository.findById(memberId) + .orElseThrow(() -> new NotFoundException(ErrorCode.MEMBER_NOT_FOUND)); + } + + private School findSchool(Long schoolId) { + return schoolRepository.findById(schoolId) + .orElseThrow(() -> new NotFoundException(ErrorCode.SCHOOL_NOT_FOUND)); + } +} diff --git a/backend/src/main/java/com/festago/auth/config/LoginConfig.java b/backend/src/main/java/com/festago/auth/config/LoginConfig.java index 72439a2eb..2c29c060f 100644 --- a/backend/src/main/java/com/festago/auth/config/LoginConfig.java +++ b/backend/src/main/java/com/festago/auth/config/LoginConfig.java @@ -38,7 +38,7 @@ public void addInterceptors(InterceptorRegistry registry) { .addPathPatterns("/admin/**", "/js/admin/**") .excludePathPatterns("/admin/login", "/admin/initialize"); registry.addInterceptor(memberAuthInterceptor()) - .addPathPatterns("/member-tickets/**", "/members/**", "/auth/**") + .addPathPatterns("/member-tickets/**", "/members/**", "/auth/**", "/students/**") .excludePathPatterns("/auth/oauth2"); } diff --git a/backend/src/main/java/com/festago/config/AsyncConfig.java b/backend/src/main/java/com/festago/config/AsyncConfig.java new file mode 100644 index 000000000..fbf428a9b --- /dev/null +++ b/backend/src/main/java/com/festago/config/AsyncConfig.java @@ -0,0 +1,10 @@ +package com.festago.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; + +@EnableAsync +@Configuration +public class AsyncConfig { + +} diff --git a/backend/src/main/java/com/festago/domain/MailClient.java b/backend/src/main/java/com/festago/domain/MailClient.java new file mode 100644 index 000000000..141c0aa57 --- /dev/null +++ b/backend/src/main/java/com/festago/domain/MailClient.java @@ -0,0 +1,6 @@ +package com.festago.domain; + +public interface MailClient { + + void send(VerificationMailPayload payload); +} diff --git a/backend/src/main/java/com/festago/domain/SchoolRepository.java b/backend/src/main/java/com/festago/domain/SchoolRepository.java new file mode 100644 index 000000000..1d5e27222 --- /dev/null +++ b/backend/src/main/java/com/festago/domain/SchoolRepository.java @@ -0,0 +1,7 @@ +package com.festago.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SchoolRepository extends JpaRepository { + +} diff --git a/backend/src/main/java/com/festago/domain/StudentCode.java b/backend/src/main/java/com/festago/domain/StudentCode.java new file mode 100644 index 000000000..2d00b2647 --- /dev/null +++ b/backend/src/main/java/com/festago/domain/StudentCode.java @@ -0,0 +1,57 @@ +package com.festago.domain; + +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; + +@Entity +public class StudentCode extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Embedded + private VerificationCode code; + + @ManyToOne(fetch = FetchType.LAZY) + private School school; + + @OneToOne(fetch = FetchType.LAZY) + private Member member; + + protected StudentCode() { + } + + public StudentCode(VerificationCode code, Member member, School school) { + this(null, code, member, school); + } + + public StudentCode(Long id, VerificationCode code, Member member, School school) { + this.id = id; + this.code = code; + this.member = member; + this.school = school; + } + + public Long getId() { + return id; + } + + public VerificationCode getCode() { + return code; + } + + public School getSchool() { + return school; + } + + public Member getMember() { + return member; + } +} diff --git a/backend/src/main/java/com/festago/domain/StudentCodeRepository.java b/backend/src/main/java/com/festago/domain/StudentCodeRepository.java new file mode 100644 index 000000000..312b93f6d --- /dev/null +++ b/backend/src/main/java/com/festago/domain/StudentCodeRepository.java @@ -0,0 +1,8 @@ +package com.festago.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface StudentCodeRepository extends JpaRepository { + + void deleteByMember(Member member); +} diff --git a/backend/src/main/java/com/festago/domain/StudentRepository.java b/backend/src/main/java/com/festago/domain/StudentRepository.java new file mode 100644 index 000000000..ab1cdf49d --- /dev/null +++ b/backend/src/main/java/com/festago/domain/StudentRepository.java @@ -0,0 +1,10 @@ +package com.festago.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface StudentRepository extends JpaRepository { + + boolean existsByUsernameAndSchoolId(String username, Long id); + + boolean existsByMemberId(Long id); +} diff --git a/backend/src/main/java/com/festago/domain/VerificationCode.java b/backend/src/main/java/com/festago/domain/VerificationCode.java new file mode 100644 index 000000000..1220650d7 --- /dev/null +++ b/backend/src/main/java/com/festago/domain/VerificationCode.java @@ -0,0 +1,53 @@ +package com.festago.domain; + +import com.festago.exception.ErrorCode; +import com.festago.exception.InternalServerException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import java.util.regex.Pattern; + +@Embeddable +public class VerificationCode { + + private static final Pattern POSITIVE_REGEX = Pattern.compile("^\\d+$"); + public static final int LENGTH = 6; + + @Column(name = "code") + private String value; + + protected VerificationCode() { + } + + public VerificationCode(String value) { + validate(value); + this.value = value; + } + + private void validate(String value) { + validateNull(value); + validateLength(value); + validatePositive(value); + } + + private void validateNull(String value) { + if (value == null) { + throw new InternalServerException(ErrorCode.INTERNAL_SERVER_ERROR); + } + } + + private void validateLength(String value) { + if (value.length() != LENGTH) { + throw new InternalServerException(ErrorCode.INTERNAL_SERVER_ERROR); + } + } + + private void validatePositive(String value) { + if (!POSITIVE_REGEX.matcher(value).matches()) { + throw new InternalServerException(ErrorCode.INTERNAL_SERVER_ERROR); + } + } + + public String getValue() { + return value; + } +} diff --git a/backend/src/main/java/com/festago/domain/VerificationCodeProvider.java b/backend/src/main/java/com/festago/domain/VerificationCodeProvider.java new file mode 100644 index 000000000..eb3b9e6e7 --- /dev/null +++ b/backend/src/main/java/com/festago/domain/VerificationCodeProvider.java @@ -0,0 +1,6 @@ +package com.festago.domain; + +public interface VerificationCodeProvider { + + VerificationCode provide(); +} diff --git a/backend/src/main/java/com/festago/domain/VerificationMailPayload.java b/backend/src/main/java/com/festago/domain/VerificationMailPayload.java new file mode 100644 index 000000000..3ed2fd4fb --- /dev/null +++ b/backend/src/main/java/com/festago/domain/VerificationMailPayload.java @@ -0,0 +1,36 @@ +package com.festago.domain; + +import com.festago.exception.ErrorCode; +import com.festago.exception.InternalServerException; + +public class VerificationMailPayload { + + private VerificationCode code; + private String username; + private String domain; + + public VerificationMailPayload(VerificationCode code, String username, String domain) { + validate(code, username, domain); + this.code = code; + this.username = username; + this.domain = domain; + } + + private void validate(VerificationCode code, String username, String domain) { + if (code == null || username == null || domain == null) { + throw new InternalServerException(ErrorCode.INTERNAL_SERVER_ERROR); + } + } + + public String getCode() { + return code.getValue(); + } + + public String getUsername() { + return username; + } + + public String getDomain() { + return domain; + } +} diff --git a/backend/src/main/java/com/festago/dto/StudentSendMailRequest.java b/backend/src/main/java/com/festago/dto/StudentSendMailRequest.java new file mode 100644 index 000000000..dbf8e8218 --- /dev/null +++ b/backend/src/main/java/com/festago/dto/StudentSendMailRequest.java @@ -0,0 +1,8 @@ +package com.festago.dto; + +public record StudentSendMailRequest( + String username, + Long schoolId +) { + +} diff --git a/backend/src/main/java/com/festago/exception/ErrorCode.java b/backend/src/main/java/com/festago/exception/ErrorCode.java index cefd692af..0de87ad2a 100644 --- a/backend/src/main/java/com/festago/exception/ErrorCode.java +++ b/backend/src/main/java/com/festago/exception/ErrorCode.java @@ -19,6 +19,8 @@ public enum ErrorCode { OAUTH2_NOT_SUPPORTED_SOCIAL_TYPE("해당 OAuth2 제공자는 지원되지 않습니다."), RESERVE_TICKET_OVER_AMOUNT("예매 가능한 수량을 초과했습니다."), OAUTH2_INVALID_TOKEN("잘못된 OAuth2 토큰입니다."), + ALREADY_STUDENT_VERIFIED("이미 학교 인증이 완료된 사용자입니다."), + DUPLICATE_STUDENT_EMAIL("이미 인증된 이메일입니다."), TICKET_CANNOT_RESERVE_STAGE_START("공연의 시작 시간 이후로 예매할 수 없습니다."), // 401 @@ -38,6 +40,7 @@ public enum ErrorCode { STAGE_NOT_FOUND("존재하지 않은 공연입니다."), FESTIVAL_NOT_FOUND("존재하지 않는 축제입니다."), TICKET_NOT_FOUND("존재하지 않는 티켓입니다."), + SCHOOL_NOT_FOUND("존재하지 않는 학교입니다."), // 500 INTERNAL_SERVER_ERROR("서버 내부에 문제가 발생했습니다."), diff --git a/backend/src/main/java/com/festago/infrastructure/GoogleMailClient.java b/backend/src/main/java/com/festago/infrastructure/GoogleMailClient.java new file mode 100644 index 000000000..713ba13c2 --- /dev/null +++ b/backend/src/main/java/com/festago/infrastructure/GoogleMailClient.java @@ -0,0 +1,38 @@ +package com.festago.infrastructure; + +import com.festago.domain.MailClient; +import com.festago.domain.VerificationMailPayload; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.mail.MailSender; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +@Component +@Profile({"prod", "dev"}) +public class GoogleMailClient implements MailClient { + + private final MailSender mailSender; + private final String fromEmail; + + public GoogleMailClient(MailSender mailSender, @Value("${spring.mail.username}") String fromEmail) { + this.mailSender = mailSender; + this.fromEmail = fromEmail; + } + + @Override + @Async + public void send(VerificationMailPayload payload) { + SimpleMailMessage mail = new SimpleMailMessage(); + mail.setFrom(fromEmail); + mail.setTo(payload.getUsername() + "@" + payload.getDomain()); + mail.setSubject("[페스타고] 학생 이메일 인증 코드"); + mail.setText(""" + 페스타고 학생 이메일 인증 코드입니다. + Code는 다음과 같습니다. + %s + """.formatted(payload.getCode())); + mailSender.send(mail); + } +} diff --git a/backend/src/main/java/com/festago/infrastructure/MockMailClient.java b/backend/src/main/java/com/festago/infrastructure/MockMailClient.java new file mode 100644 index 000000000..f4bea068d --- /dev/null +++ b/backend/src/main/java/com/festago/infrastructure/MockMailClient.java @@ -0,0 +1,15 @@ +package com.festago.infrastructure; + +import com.festago.domain.MailClient; +import com.festago.domain.VerificationMailPayload; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +@Component +@Profile({"local", "test"}) +public class MockMailClient implements MailClient { + + @Override + public void send(VerificationMailPayload payload) { + } +} diff --git a/backend/src/main/java/com/festago/infrastructure/RandomVerificationCodeProvider.java b/backend/src/main/java/com/festago/infrastructure/RandomVerificationCodeProvider.java new file mode 100644 index 000000000..fbf1f4451 --- /dev/null +++ b/backend/src/main/java/com/festago/infrastructure/RandomVerificationCodeProvider.java @@ -0,0 +1,23 @@ +package com.festago.infrastructure; + +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.joining; + +import com.festago.domain.VerificationCode; +import com.festago.domain.VerificationCodeProvider; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; +import org.springframework.stereotype.Component; + +@Component +public class RandomVerificationCodeProvider implements VerificationCodeProvider { + + @Override + public VerificationCode provide() { + Random random = ThreadLocalRandom.current(); + return random.ints(0, 10) + .mapToObj(String::valueOf) + .limit(VerificationCode.LENGTH) + .collect(collectingAndThen(joining(), VerificationCode::new)); + } +} diff --git a/backend/src/main/java/com/festago/presentation/StudentController.java b/backend/src/main/java/com/festago/presentation/StudentController.java new file mode 100644 index 000000000..ff04ea373 --- /dev/null +++ b/backend/src/main/java/com/festago/presentation/StudentController.java @@ -0,0 +1,33 @@ +package com.festago.presentation; + +import com.festago.application.StudentService; +import com.festago.auth.annotation.Member; +import com.festago.dto.StudentSendMailRequest; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/students") +@Tag(name = "학생 요청") +public class StudentController { + + private final StudentService studentService; + + public StudentController(StudentService studentService) { + this.studentService = studentService; + } + + @PostMapping("/send-verification") + @Operation(description = "학교 인증 이메일을 전송한다.", summary = "학생 인증 이메일 전송") + public ResponseEntity sendEmail(@Member Long memberId, + @RequestBody StudentSendMailRequest request) { + studentService.sendVerificationMail(memberId, request); + return ResponseEntity.ok() + .build(); + } +} diff --git a/backend/src/test/java/com/festago/application/StudentServiceTest.java b/backend/src/test/java/com/festago/application/StudentServiceTest.java new file mode 100644 index 000000000..b120fe6be --- /dev/null +++ b/backend/src/test/java/com/festago/application/StudentServiceTest.java @@ -0,0 +1,171 @@ +package com.festago.application; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.BDDMockito.given; + +import com.festago.domain.MailClient; +import com.festago.domain.Member; +import com.festago.domain.MemberRepository; +import com.festago.domain.School; +import com.festago.domain.SchoolRepository; +import com.festago.domain.StudentCodeRepository; +import com.festago.domain.StudentRepository; +import com.festago.domain.VerificationCode; +import com.festago.domain.VerificationCodeProvider; +import com.festago.dto.StudentSendMailRequest; +import com.festago.exception.BadRequestException; +import com.festago.exception.NotFoundException; +import com.festago.support.MemberFixture; +import java.util.Optional; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@DisplayNameGeneration(ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +@ExtendWith(MockitoExtension.class) +class StudentServiceTest { + + @InjectMocks + StudentService studentService; + + @Mock + MailClient mailClient; + + @Mock + VerificationCodeProvider codeProvider; + + @Mock + StudentCodeRepository studentCodeRepository; + + @Mock + SchoolRepository schoolRepository; + + @Mock + MemberRepository memberRepository; + + @Mock + StudentRepository studentRepository; + + @Nested + class 인증_메일_전송 { + + @Test + void 이미_학생인증정보가_존재하면_예외() { + // given + Long memberId = 1L; + Long schoolId = 1L; + String username = "user"; + StudentSendMailRequest request = new StudentSendMailRequest(username, schoolId); + given(studentRepository.existsByMemberId(memberId)) + .willReturn(true); + + // when & then + assertThatThrownBy(() -> studentService.sendVerificationMail(memberId, request)) + .isInstanceOf(BadRequestException.class) + .hasMessage("이미 학교 인증이 완료된 사용자입니다."); + } + + @Test + void 중복되는_이메일이면_예외() { + // given + Long memberId = 1L; + Long schoolId = 1L; + String username = "user"; + StudentSendMailRequest request = new StudentSendMailRequest(username, schoolId); + + given(studentRepository.existsByMemberId(memberId)) + .willReturn(false); + given(studentRepository.existsByUsernameAndSchoolId(username, schoolId)) + .willReturn(true); + + // when & then + assertThatThrownBy(() -> studentService.sendVerificationMail(memberId, request)) + .isInstanceOf(BadRequestException.class) + .hasMessage("이미 인증된 이메일입니다."); + } + + @Test + void 멤버가_없으면_예외() { + // given + Long memberId = 1L; + Long schoolId = 1L; + String username = "user"; + StudentSendMailRequest request = new StudentSendMailRequest(username, schoolId); + + given(studentRepository.existsByMemberId(memberId)) + .willReturn(false); + given(studentRepository.existsByUsernameAndSchoolId(username, schoolId)) + .willReturn(false); + given(memberRepository.findById(memberId)) + .willReturn(Optional.empty()); + + // when & then + assertThatThrownBy(() -> studentService.sendVerificationMail(memberId, request)) + .isInstanceOf(NotFoundException.class) + .hasMessage("존재하지 않는 멤버입니다."); + } + + @Test + void 학교가_없으면_예외() { + // given + Long memberId = 1L; + Long schoolId = 1L; + String username = "user"; + Member member = MemberFixture.member() + .id(memberId) + .build(); + StudentSendMailRequest request = new StudentSendMailRequest(username, schoolId); + + given(studentRepository.existsByMemberId(memberId)) + .willReturn(false); + given(studentRepository.existsByUsernameAndSchoolId(username, schoolId)) + .willReturn(false); + given(memberRepository.findById(memberId)) + .willReturn(Optional.empty()); + given(memberRepository.findById(memberId)) + .willReturn(Optional.of(member)); + given(schoolRepository.findById(schoolId)) + .willReturn(Optional.empty()); + + // when & then + assertThatThrownBy(() -> studentService.sendVerificationMail(memberId, request)) + .isInstanceOf(NotFoundException.class) + .hasMessage("존재하지 않는 학교입니다."); + } + + + @Test + void 성공() { + // given + Long memberId = 1L; + Long schoolId = 1L; + String username = "user"; + Member member = MemberFixture.member() + .id(memberId) + .build(); + StudentSendMailRequest request = new StudentSendMailRequest(username, schoolId); + + given(studentRepository.existsByMemberId(memberId)) + .willReturn(false); + given(studentRepository.existsByUsernameAndSchoolId(username, schoolId)) + .willReturn(false); + given(memberRepository.findById(memberId)) + .willReturn(Optional.of(member)); + given(schoolRepository.findById(schoolId)) + .willReturn(Optional.of(new School(schoolId, "festago.ac.kr", "페스타고대학교"))); + given(codeProvider.provide()) + .willReturn(new VerificationCode("123456")); + + // when & then + assertThatNoException() + .isThrownBy(() -> studentService.sendVerificationMail(memberId, request)); + } + } +} diff --git a/backend/src/test/java/com/festago/domain/RandomVerificationCodeProviderTest.java b/backend/src/test/java/com/festago/domain/RandomVerificationCodeProviderTest.java new file mode 100644 index 000000000..46c413959 --- /dev/null +++ b/backend/src/test/java/com/festago/domain/RandomVerificationCodeProviderTest.java @@ -0,0 +1,24 @@ +package com.festago.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.festago.infrastructure.RandomVerificationCodeProvider; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; + +@DisplayNameGeneration(ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class RandomVerificationCodeProviderTest { + + RandomVerificationCodeProvider codeProvider = new RandomVerificationCodeProvider(); + + @Test + void 생성() { + // when + VerificationCode code = codeProvider.provide(); + + // then + assertThat(code.getValue()).hasSize(6); + } +} diff --git a/backend/src/test/java/com/festago/domain/VerificationCodeTest.java b/backend/src/test/java/com/festago/domain/VerificationCodeTest.java new file mode 100644 index 000000000..cfc7e4771 --- /dev/null +++ b/backend/src/test/java/com/festago/domain/VerificationCodeTest.java @@ -0,0 +1,54 @@ +package com.festago.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.festago.exception.InternalServerException; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@DisplayNameGeneration(ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class VerificationCodeTest { + + @Test + void null_이면_예외() { + // when & then + assertThatThrownBy(() -> new VerificationCode(null)) + .isInstanceOf(InternalServerException.class); + } + + @ParameterizedTest + @ValueSource(strings = {"12345", "1234567"}) + void 길이가_6자리가_아니면_예외(String code) { + // when & then + assertThatThrownBy(() -> new VerificationCode(code)) + .isInstanceOf(InternalServerException.class); + } + + @Test + void 숫자가_아니면_예외() { + // when & then + assertThatThrownBy(() -> new VerificationCode("일이삼사오육")) + .isInstanceOf(InternalServerException.class); + } + + @Test + void 음수이면_예외() { + // when & then + assertThatThrownBy(() -> new VerificationCode("-12345")) + .isInstanceOf(InternalServerException.class); + } + + @Test + void 생성() { + // when + VerificationCode verificationCode = new VerificationCode("123456"); + + // then + assertThat(verificationCode.getValue()).isEqualTo("123456"); + } +} diff --git a/backend/src/test/java/com/festago/presentation/StudentControllerTest.java b/backend/src/test/java/com/festago/presentation/StudentControllerTest.java new file mode 100644 index 000000000..525b3c3cd --- /dev/null +++ b/backend/src/test/java/com/festago/presentation/StudentControllerTest.java @@ -0,0 +1,60 @@ +package com.festago.presentation; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.festago.application.StudentService; +import com.festago.dto.StudentSendMailRequest; +import com.festago.support.CustomWebMvcTest; +import com.festago.support.WithMockAuth; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +@DisplayNameGeneration(ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +@CustomWebMvcTest(StudentController.class) +class StudentControllerTest { + + @Autowired + MockMvc mockMvc; + + @Autowired + ObjectMapper objectMapper; + + @MockBean + StudentService studentService; + + @Test + void 인증이_되지_않으면_401() throws Exception { + // given + StudentSendMailRequest request = new StudentSendMailRequest("user", 1L); + + // when & then + mockMvc.perform(post("/students/send-verification") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockAuth + void 학교_인증_요청() throws Exception { + // given + StudentSendMailRequest request = new StudentSendMailRequest("user", 1L); + + // when & then + mockMvc.perform(post("/students/send-verification") + .contentType(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer token") + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()); + + } +} From 2c73f5214824e590f49b9a007e6e9def53e7f35c Mon Sep 17 00:00:00 2001 From: seokjin8678 Date: Thu, 31 Aug 2023 16:49:27 +0900 Subject: [PATCH 06/74] =?UTF-8?q?[BE]=20fix:=20dev,=20prod=20application.y?= =?UTF-8?q?ml=EC=97=90=20mail=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(#409)=20(#411)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/resources/festago-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/resources/festago-config b/backend/src/main/resources/festago-config index 22a881c78..c62207dbc 160000 --- a/backend/src/main/resources/festago-config +++ b/backend/src/main/resources/festago-config @@ -1 +1 @@ -Subproject commit 22a881c7874468b009b559f29e9fb08433fceaa7 +Subproject commit c62207dbc32365bd0b0f6944a355f4f879073bc2 From 3e86d6d39005aa2e2cf5c0b741751c277019dfdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=84=ED=81=AC?= <37167652+re4rk@users.noreply.github.com> Date: Thu, 31 Aug 2023 17:08:07 +0900 Subject: [PATCH 07/74] =?UTF-8?q?[AN]=20refactor:=20=EC=98=88=EB=A7=A4=20?= =?UTF-8?q?=EC=A0=9C=EC=8B=9C=20=ED=99=94=EB=A9=B4=20Presentation=20UiMode?= =?UTF-8?q?l=20=EC=A0=9C=EA=B1=B0=20(#405)=20(#408)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 티켓 model을 presentation에서 domain으로 변경 * refactor: sealed interface로 변경 --- .../ui/ticketentry/TicketEntryUiState.kt | 12 ++++++------ .../ui/ticketentry/TicketEntryViewModel.kt | 3 +-- .../src/main/res/layout/activity_ticket_entry.xml | 4 ++-- .../ui/ticketentry/TicketEntryViewModelTest.kt | 3 +-- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryUiState.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryUiState.kt index 55762d2a2..1ab505157 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryUiState.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryUiState.kt @@ -1,17 +1,17 @@ package com.festago.festago.presentation.ui.ticketentry import com.festago.festago.R +import com.festago.festago.model.Ticket import com.festago.festago.model.TicketCode -import com.festago.festago.presentation.model.TicketConditionUiModel.AFTER_ENTRY -import com.festago.festago.presentation.model.TicketConditionUiModel.AWAY -import com.festago.festago.presentation.model.TicketConditionUiModel.BEFORE_ENTRY -import com.festago.festago.presentation.model.TicketUiModel +import com.festago.festago.model.TicketCondition.AFTER_ENTRY +import com.festago.festago.model.TicketCondition.AWAY +import com.festago.festago.model.TicketCondition.BEFORE_ENTRY -interface TicketEntryUiState { +sealed interface TicketEntryUiState { object Loading : TicketEntryUiState data class Success( - val ticket: TicketUiModel, + val ticket: Ticket, val ticketCode: TicketCode, val remainTime: Int, ) : TicketEntryUiState { diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryViewModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryViewModel.kt index 043ce7b3a..8c797aa4d 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryViewModel.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryViewModel.kt @@ -9,7 +9,6 @@ import com.festago.festago.analytics.logNetworkFailure import com.festago.festago.model.TicketCode import com.festago.festago.model.timer.Timer import com.festago.festago.model.timer.TimerListener -import com.festago.festago.presentation.mapper.toPresentation import com.festago.festago.repository.TicketRepository import kotlinx.coroutines.launch @@ -50,7 +49,7 @@ class TicketEntryViewModel( ticketRepository.loadTicketCode(ticketId) .onSuccess { ticketCode -> _uiState.value = TicketEntryUiState.Success( - ticket = ticket.toPresentation(), + ticket = ticket, ticketCode = ticketCode, remainTime = ticketCode.period, ) diff --git a/android/festago/app/src/main/res/layout/activity_ticket_entry.xml b/android/festago/app/src/main/res/layout/activity_ticket_entry.xml index 35e23675e..715ec927a 100644 --- a/android/festago/app/src/main/res/layout/activity_ticket_entry.xml +++ b/android/festago/app/src/main/res/layout/activity_ticket_entry.xml @@ -5,7 +5,7 @@ - + @@ -47,7 +47,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/space_llg" - android:text="@{successState.ticket.festivalName}" + android:text="@{successState.ticket.festivalTicket.name}" android:textColor="@color/md_theme_light_onSurface" android:textSize="@dimen/title_medium" android:textStyle="bold" diff --git a/android/festago/app/src/test/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryViewModelTest.kt b/android/festago/app/src/test/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryViewModelTest.kt index a2e01d3d5..55fec66bd 100644 --- a/android/festago/app/src/test/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryViewModelTest.kt +++ b/android/festago/app/src/test/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryViewModelTest.kt @@ -4,7 +4,6 @@ import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.festago.festago.analytics.AnalyticsHelper import com.festago.festago.model.TicketCode import com.festago.festago.presentation.fixture.TicketFixture -import com.festago.festago.presentation.mapper.toPresentation import com.festago.festago.repository.TicketRepository import io.mockk.coEvery import io.mockk.mockk @@ -72,7 +71,7 @@ class TicketEntryViewModelTest { // and val actualTicket = (vm.uiState.value as TicketEntryUiState.Success).ticket - assertThat(actualTicket).isEqualTo(TicketFixture.getMemberTicket().toPresentation()) + assertThat(actualTicket).isEqualTo(TicketFixture.getMemberTicket()) val actualTicketCode = (vm.uiState.value as TicketEntryUiState.Success).ticketCode assertThat(actualTicketCode).isEqualTo(getFakeTicketCode()) } From 68905fc1853ebc1abb478dc0f899d635577da22c Mon Sep 17 00:00:00 2001 From: SeongHoonC <108349655+SeongHoonC@users.noreply.github.com> Date: Thu, 31 Aug 2023 17:44:36 +0900 Subject: [PATCH 08/74] =?UTF-8?q?[AN]=20refactor:=20=EC=98=88=EB=A7=A4=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C=20=ED=99=94=EB=A9=B4=20Presentation=20UiMode?= =?UTF-8?q?l=20to=20Arg=20(#407)=20(#412)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 예약 완료 ui 모델 제거 * refactor: 값 전달을 위한 ReservedTicketArg 객체 정의 * refactor: 예매 완료 티켓 변수 이름 수정 * refactor: 예약된 티켓 완료 화면 수정 --- .../ReservationCompleteActivityTest.kt | 3 +-- .../presentation/mapper/ReservedTicketMapper.kt | 10 ---------- .../reservationcomplete/ReservationCompleteActivity.kt | 9 ++++----- .../reservationcomplete/ReservedTicketArg.kt} | 4 ++-- .../ui/ticketreserve/TicketReserveActivity.kt | 9 +++++++-- .../main/res/layout/activity_reservation_complete.xml | 10 +++++----- 6 files changed, 19 insertions(+), 26 deletions(-) delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservedTicketMapper.kt rename android/festago/app/src/main/java/com/festago/festago/presentation/{model/ReservedTicketUiModel.kt => ui/reservationcomplete/ReservedTicketArg.kt} (68%) diff --git a/android/festago/app/src/androidTest/java/com/festago/festago/presentation/ui/reservationcomplete/ReservationCompleteActivityTest.kt b/android/festago/app/src/androidTest/java/com/festago/festago/presentation/ui/reservationcomplete/ReservationCompleteActivityTest.kt index 57700a61c..867e40c6c 100644 --- a/android/festago/app/src/androidTest/java/com/festago/festago/presentation/ui/reservationcomplete/ReservationCompleteActivityTest.kt +++ b/android/festago/app/src/androidTest/java/com/festago/festago/presentation/ui/reservationcomplete/ReservationCompleteActivityTest.kt @@ -7,14 +7,13 @@ import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.ext.junit.rules.ActivityScenarioRule import com.festago.festago.R -import com.festago.festago.presentation.model.ReservedTicketUiModel import org.junit.Rule import org.junit.Test import java.time.LocalDateTime import java.time.format.DateTimeFormatter class ReservationCompleteActivityTest { - private val reservationComplete = ReservedTicketUiModel(1L, 123, LocalDateTime.now()) + private val reservationComplete = ReservedTicketArg(1L, 123, LocalDateTime.now()) private val intent = ReservationCompleteActivity.getIntent( diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservedTicketMapper.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservedTicketMapper.kt deleted file mode 100644 index 81eaaaca3..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservedTicketMapper.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.festago.festago.presentation.mapper - -import com.festago.festago.model.ReservedTicket -import com.festago.festago.presentation.model.ReservedTicketUiModel - -fun ReservedTicket.toPresentation() = ReservedTicketUiModel( - ticketId = id, - number = number, - entryTime = entryTime, -) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/reservationcomplete/ReservationCompleteActivity.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/reservationcomplete/ReservationCompleteActivity.kt index 0f3aa4c75..237a87b5f 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/reservationcomplete/ReservationCompleteActivity.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/reservationcomplete/ReservationCompleteActivity.kt @@ -5,7 +5,6 @@ import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.festago.festago.databinding.ActivityReservationCompleteBinding -import com.festago.festago.presentation.model.ReservedTicketUiModel import com.festago.festago.presentation.util.getParcelableExtraCompat class ReservationCompleteActivity : AppCompatActivity() { @@ -24,17 +23,17 @@ class ReservationCompleteActivity : AppCompatActivity() { } private fun initView() { - val reservationComplete = - intent.getParcelableExtraCompat( + val reservedTicket = + intent.getParcelableExtraCompat( KEY_RESERVATION_COMPLETE, ) - binding.reservationComplete = reservationComplete + binding.reservedTicket = reservedTicket } companion object { private const val KEY_RESERVATION_COMPLETE = "KEY_RESERVATION_COMPLETE" - fun getIntent(context: Context, reservationComplete: ReservedTicketUiModel): Intent { + fun getIntent(context: Context, reservationComplete: ReservedTicketArg): Intent { return Intent(context, ReservationCompleteActivity::class.java).apply { putExtra(KEY_RESERVATION_COMPLETE, reservationComplete) } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservedTicketUiModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/reservationcomplete/ReservedTicketArg.kt similarity index 68% rename from android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservedTicketUiModel.kt rename to android/festago/app/src/main/java/com/festago/festago/presentation/ui/reservationcomplete/ReservedTicketArg.kt index cab1d21be..bc202b487 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservedTicketUiModel.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/reservationcomplete/ReservedTicketArg.kt @@ -1,11 +1,11 @@ -package com.festago.festago.presentation.model +package com.festago.festago.presentation.ui.reservationcomplete import android.os.Parcelable import kotlinx.parcelize.Parcelize import java.time.LocalDateTime @Parcelize -data class ReservedTicketUiModel( +data class ReservedTicketArg( val ticketId: Long, val number: Int, val entryTime: LocalDateTime, diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveActivity.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveActivity.kt index dad5aade1..8f1895907 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveActivity.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveActivity.kt @@ -9,11 +9,11 @@ import androidx.recyclerview.widget.ConcatAdapter import com.festago.festago.R import com.festago.festago.databinding.ActivityTicketReserveBinding import com.festago.festago.model.ReservedTicket -import com.festago.festago.presentation.mapper.toPresentation import com.festago.festago.presentation.model.ReservationTicketUiModel import com.festago.festago.presentation.ui.FestagoViewModelFactory import com.festago.festago.presentation.ui.customview.OkDialogFragment import com.festago.festago.presentation.ui.reservationcomplete.ReservationCompleteActivity +import com.festago.festago.presentation.ui.reservationcomplete.ReservedTicketArg import com.festago.festago.presentation.ui.signin.SignInActivity import com.festago.festago.presentation.ui.ticketreserve.TicketReserveEvent.ReserveTicketFailed import com.festago.festago.presentation.ui.ticketreserve.TicketReserveEvent.ReserveTicketSuccess @@ -87,7 +87,12 @@ class TicketReserveActivity : AppCompatActivity() { } private fun handleReserveTicketSuccess(reservedTicket: ReservedTicket) { - val intent = ReservationCompleteActivity.getIntent(this, reservedTicket.toPresentation()) + val reservedTicketArg = ReservedTicketArg( + ticketId = reservedTicket.id, + number = reservedTicket.number, + entryTime = reservedTicket.entryTime, + ) + val intent = ReservationCompleteActivity.getIntent(this, reservedTicketArg) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK startActivity(intent) finish() diff --git a/android/festago/app/src/main/res/layout/activity_reservation_complete.xml b/android/festago/app/src/main/res/layout/activity_reservation_complete.xml index 4970e1629..39dbc9277 100644 --- a/android/festago/app/src/main/res/layout/activity_reservation_complete.xml +++ b/android/festago/app/src/main/res/layout/activity_reservation_complete.xml @@ -8,8 +8,8 @@ + name="reservedTicket" + type="com.festago.festago.presentation.ui.reservationcomplete.ReservedTicketArg" /> Date: Thu, 31 Aug 2023 17:51:23 +0900 Subject: [PATCH 09/74] =?UTF-8?q?[BE]=20=ED=8B=B0=EC=BC=93=ED=8C=85?= =?UTF-8?q?=EC=8B=9C=20Lazy=20loading=EC=9C=BC=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=9C=20N+1=EB=AC=B8=EC=A0=9C=EB=A5=BC=20=EA=B0=9C=EC=84=A0?= =?UTF-8?q?=20(#398)=20(#413)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/festago/application/TicketingService.java | 2 +- .../main/java/com/festago/domain/TicketRepository.java | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/com/festago/application/TicketingService.java b/backend/src/main/java/com/festago/application/TicketingService.java index 9d2afc5b4..2319fb673 100644 --- a/backend/src/main/java/com/festago/application/TicketingService.java +++ b/backend/src/main/java/com/festago/application/TicketingService.java @@ -49,7 +49,7 @@ public TicketingResponse ticketing(Long memberId, TicketingRequest request) { } private Ticket findTicketById(Long ticketId) { - return ticketRepository.findById(ticketId) + return ticketRepository.findByIdWithFetch(ticketId) .orElseThrow(() -> new NotFoundException(ErrorCode.TICKET_NOT_FOUND)); } diff --git a/backend/src/main/java/com/festago/domain/TicketRepository.java b/backend/src/main/java/com/festago/domain/TicketRepository.java index e6acfb0e4..75e7079cf 100644 --- a/backend/src/main/java/com/festago/domain/TicketRepository.java +++ b/backend/src/main/java/com/festago/domain/TicketRepository.java @@ -3,10 +3,20 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface TicketRepository extends JpaRepository { List findAllByStageId(Long stageId); Optional findByTicketTypeAndStage(TicketType ticketType, Stage stage); + + @Query(""" + SELECT t FROM Ticket t + JOIN FETCH t.stage s + JOIN FETCH t.ticketEntryTimes et + WHERE t.id = :ticketId + """) + Optional findByIdWithFetch(@Param("ticketId") Long ticketId); } From ff60523226b9fcd45532273da94861f7ef427424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=B4=EC=8B=9C?= <67777523+EmilyCh0@users.noreply.github.com> Date: Fri, 1 Sep 2023 16:03:41 +0900 Subject: [PATCH 10/74] =?UTF-8?q?[AN/USER]=20refactor:=20TicketHistory=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20presentation=20model=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=20(#406)=20(#410)=20(#416)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: TicketHistoryItemUiState로 수정 * test: 테스트에 변경사항 반영 * refactor: 의존성 분리를 위해서 레이아웃 분리 * refactor: 티켓 ui 모델 에서 domain 모델 사용하도록 변경 * refactor: default값이 없는 도메인 모델에 대응 * refactor: UserProfile의 도메인 모델을 사용하도록 변경 * refactor: 최근 티켓 상태 include 제거 * refactor: 티켓 히스토리 ktlint 적용 * refactor: 티켓 히스토리 테스트 ktlint 적용 * refactor: ui state로 매핑하는 메서드 팩토리메서드로 변경 --------- Co-authored-by: re4rk <37167652+re4rk@users.noreply.github.com> --- .../ui/home/mypage/MyPageUiState.kt | 10 +- .../ui/home/mypage/MyPageViewModel.kt | 46 +---- .../ui/tickethistory/TicketHistoryAdapter.kt | 9 +- .../tickethistory/TicketHistoryItemUiState.kt | 29 ++++ .../ui/tickethistory/TicketHistoryUiState.kt | 4 +- .../tickethistory/TicketHistoryViewHolder.kt | 3 +- .../tickethistory/TicketHistoryViewModel.kt | 5 +- .../src/main/res/layout/fragment_my_page.xml | 157 +++++++++++++++++- .../main/res/layout/item_ticket_history.xml | 6 +- .../ui/home/mypage/MyPageViewModelTest.kt | 20 +-- .../TicketHistoryViewModelTest.kt | 15 +- 11 files changed, 222 insertions(+), 82 deletions(-) create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryItemUiState.kt diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageUiState.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageUiState.kt index 389c85bba..4d6f74f69 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageUiState.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageUiState.kt @@ -1,16 +1,16 @@ package com.festago.festago.presentation.ui.home.mypage -import com.festago.festago.presentation.model.TicketUiModel -import com.festago.festago.presentation.model.UserProfileUiModel +import com.festago.festago.model.Ticket +import com.festago.festago.model.UserProfile sealed interface MyPageUiState { object Loading : MyPageUiState data class Success( - val userProfile: UserProfileUiModel = UserProfileUiModel(), - val ticket: TicketUiModel = TicketUiModel(), + val userProfile: UserProfile, + val ticket: Ticket?, ) : MyPageUiState { - val hasTicket: Boolean get() = ticket.id != -1L + val hasTicket: Boolean get() = ticket != null } object Error : MyPageUiState diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModel.kt index 33b8a3db6..6c254b915 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModel.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageViewModel.kt @@ -6,13 +6,12 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.festago.festago.analytics.AnalyticsHelper import com.festago.festago.analytics.logNetworkFailure -import com.festago.festago.presentation.mapper.toPresentation -import com.festago.festago.presentation.model.TicketUiModel import com.festago.festago.presentation.util.MutableSingleLiveData import com.festago.festago.presentation.util.SingleLiveData import com.festago.festago.repository.AuthRepository import com.festago.festago.repository.TicketRepository import com.festago.festago.repository.UserRepository +import kotlinx.coroutines.async import kotlinx.coroutines.launch class MyPageViewModel( @@ -35,44 +34,14 @@ class MyPageViewModel( return } viewModelScope.launch { - loadUserProfile() - loadFirstTicket() - } - } + val deferredUserProfile = async { userRepository.loadUserProfile() } + val deferredHistoryTicket = async { ticketRepository.loadHistoryTickets(size = 1) } - private suspend fun loadUserProfile() { - userRepository.loadUserProfile() - .onSuccess { - when (val current = uiState.value) { - is MyPageUiState.Error, - is MyPageUiState.Loading, - null, - -> _uiState.value = MyPageUiState.Success(userProfile = it.toPresentation()) - - is MyPageUiState.Success -> - _uiState.value = current.copy(userProfile = it.toPresentation()) - } - }.onFailure { - _uiState.value = MyPageUiState.Error - analyticsHelper.logNetworkFailure( - key = KEY_LOAD_USER_INFO, - value = it.message.toString(), + runCatching { + _uiState.value = MyPageUiState.Success( + userProfile = deferredUserProfile.await().getOrThrow(), + ticket = deferredHistoryTicket.await().getOrThrow().firstOrNull(), ) - } - } - - private suspend fun loadFirstTicket() { - ticketRepository.loadHistoryTickets(size = 1) - .onSuccess { - val ticket = it.firstOrNull()?.toPresentation() ?: TicketUiModel() - when (val current = uiState.value) { - is MyPageUiState.Error, null -> Unit - - is MyPageUiState.Loading -> - _uiState.value = MyPageUiState.Success(ticket = ticket) - - is MyPageUiState.Success -> _uiState.value = current.copy(ticket = ticket) - } }.onFailure { _uiState.value = MyPageUiState.Error analyticsHelper.logNetworkFailure( @@ -80,6 +49,7 @@ class MyPageViewModel( value = it.message.toString(), ) } + } } fun signOut() { diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryAdapter.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryAdapter.kt index fcdcfac66..0e80827d7 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryAdapter.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryAdapter.kt @@ -3,9 +3,8 @@ package com.festago.festago.presentation.ui.tickethistory import android.view.ViewGroup import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter -import com.festago.festago.presentation.model.TicketUiModel -class TicketHistoryAdapter : ListAdapter(ticketDiffUtil) { +class TicketHistoryAdapter : ListAdapter(ticketDiffUtil) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TicketHistoryViewHolder { return TicketHistoryViewHolder.from(parent) @@ -16,11 +15,11 @@ class TicketHistoryAdapter : ListAdapter } companion object { - private val ticketDiffUtil = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: TicketUiModel, newItem: TicketUiModel) = + private val ticketDiffUtil = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: TicketHistoryItemUiState, newItem: TicketHistoryItemUiState) = oldItem.id == newItem.id - override fun areContentsTheSame(oldItem: TicketUiModel, newItem: TicketUiModel) = + override fun areContentsTheSame(oldItem: TicketHistoryItemUiState, newItem: TicketHistoryItemUiState) = oldItem == newItem } } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryItemUiState.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryItemUiState.kt new file mode 100644 index 000000000..1cd2dc81a --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryItemUiState.kt @@ -0,0 +1,29 @@ +package com.festago.festago.presentation.ui.tickethistory + +import com.festago.festago.model.Stage +import com.festago.festago.model.Ticket +import java.time.LocalDateTime + +data class TicketHistoryItemUiState( + val id: Long, + val number: Int, + val entryTime: LocalDateTime, + val reserveAt: LocalDateTime, + val stage: Stage, + val festivalId: Int, + val festivalName: String, + val festivalThumbnail: String, +) { + companion object { + fun from(ticket: Ticket) = TicketHistoryItemUiState( + id = ticket.id, + number = ticket.number, + entryTime = ticket.entryTime, + reserveAt = ticket.reserveAt, + stage = ticket.stage, + festivalId = ticket.festivalTicket.id, + festivalName = ticket.festivalTicket.name, + festivalThumbnail = ticket.festivalTicket.thumbnail, + ) + } +} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryUiState.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryUiState.kt index 79908db9b..e8c0d8666 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryUiState.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryUiState.kt @@ -1,11 +1,9 @@ package com.festago.festago.presentation.ui.tickethistory -import com.festago.festago.presentation.model.TicketUiModel - sealed interface TicketHistoryUiState { object Loading : TicketHistoryUiState - data class Success(val tickets: List) : TicketHistoryUiState { + data class Success(val tickets: List) : TicketHistoryUiState { val hasTicket get() = tickets.isNotEmpty() val hasNotTicket get() = tickets.isEmpty() } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryViewHolder.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryViewHolder.kt index 1e4cff371..0e4c66658 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryViewHolder.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryViewHolder.kt @@ -4,13 +4,12 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.festago.festago.databinding.ItemTicketHistoryBinding -import com.festago.festago.presentation.model.TicketUiModel class TicketHistoryViewHolder( val binding: ItemTicketHistoryBinding, ) : RecyclerView.ViewHolder(binding.root) { - fun bind(item: TicketUiModel) { + fun bind(item: TicketHistoryItemUiState) { binding.ticket = item } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryViewModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryViewModel.kt index f30406ab0..868440399 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryViewModel.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/tickethistory/TicketHistoryViewModel.kt @@ -6,7 +6,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.festago.festago.analytics.AnalyticsHelper import com.festago.festago.analytics.logNetworkFailure -import com.festago.festago.presentation.mapper.toPresentation import com.festago.festago.repository.TicketRepository import kotlinx.coroutines.launch @@ -25,7 +24,9 @@ class TicketHistoryViewModel( _uiState.value = TicketHistoryUiState.Loading ticketRepository.loadHistoryTickets(size) .onSuccess { tickets -> - _uiState.value = TicketHistoryUiState.Success(tickets.toPresentation()) + _uiState.value = TicketHistoryUiState.Success( + tickets.map { TicketHistoryItemUiState.from(it) }, + ) }.onFailure { _uiState.value = TicketHistoryUiState.Error analyticsHelper.logNetworkFailure( diff --git a/android/festago/app/src/main/res/layout/fragment_my_page.xml b/android/festago/app/src/main/res/layout/fragment_my_page.xml index 3a52b5fda..ebce9c7df 100644 --- a/android/festago/app/src/main/res/layout/fragment_my_page.xml +++ b/android/festago/app/src/main/res/layout/fragment_my_page.xml @@ -160,13 +160,158 @@ android:layout_height="wrap_content" android:padding="16dp"> - + android:layout_height="wrap_content" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/clTicketHistory" /> diff --git a/android/festago/app/src/main/res/layout/item_ticket_history.xml b/android/festago/app/src/main/res/layout/item_ticket_history.xml index 33cfae275..5b0c6b077 100644 --- a/android/festago/app/src/main/res/layout/item_ticket_history.xml +++ b/android/festago/app/src/main/res/layout/item_ticket_history.xml @@ -7,13 +7,9 @@ - - + type="com.festago.festago.presentation.ui.tickethistory.TicketHistoryItemUiState" /> Date: Fri, 1 Sep 2023 20:20:08 +0900 Subject: [PATCH 11/74] =?UTF-8?q?[AN/USER]=20refactor:=20TicketReserve=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20presentation=20=EB=AA=A8=EB=8D=B8=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0(#418)=20(#419)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 예매티켓 전달을 위한 Arg 클래스 추가 * refactor: ReservationTicketUiModel 사용하지 않도록 리팩터링 * refactor: BottomSheetReservationTicketArg로 클래스명 변경 --- .../ui/ticketreserve/TicketReserveActivity.kt | 16 ++++++++++++---- .../ui/ticketreserve/TicketReserveEvent.kt | 4 ++-- .../ui/ticketreserve/TicketReserveItemUiState.kt | 9 +++------ .../ui/ticketreserve/TicketReserveViewModel.kt | 5 ++--- .../BottomSheetReservationTicketArg.kt | 12 ++++++++++++ .../bottomsheet/TicketReserveBottomItem.kt | 4 +--- .../TicketReserveBottomSheetFragment.kt | 5 ++--- .../ticketreserve/TicketReserveViewModelTest.kt | 3 +-- 8 files changed, 35 insertions(+), 23 deletions(-) create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/BottomSheetReservationTicketArg.kt diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveActivity.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveActivity.kt index 8f1895907..a7f4b46cf 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveActivity.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveActivity.kt @@ -8,8 +8,8 @@ import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.ConcatAdapter import com.festago.festago.R import com.festago.festago.databinding.ActivityTicketReserveBinding +import com.festago.festago.model.ReservationTicket import com.festago.festago.model.ReservedTicket -import com.festago.festago.presentation.model.ReservationTicketUiModel import com.festago.festago.presentation.ui.FestagoViewModelFactory import com.festago.festago.presentation.ui.customview.OkDialogFragment import com.festago.festago.presentation.ui.reservationcomplete.ReservationCompleteActivity @@ -21,6 +21,7 @@ import com.festago.festago.presentation.ui.ticketreserve.TicketReserveEvent.Show import com.festago.festago.presentation.ui.ticketreserve.TicketReserveEvent.ShowTicketTypes import com.festago.festago.presentation.ui.ticketreserve.adapter.TicketReserveAdapter import com.festago.festago.presentation.ui.ticketreserve.adapter.TicketReserveHeaderAdapter +import com.festago.festago.presentation.ui.ticketreserve.bottomsheet.BottomSheetReservationTicketArg import com.festago.festago.presentation.ui.ticketreserve.bottomsheet.TicketReserveBottomSheetFragment import java.time.LocalDateTime import java.time.format.DateTimeFormatter @@ -63,7 +64,7 @@ class TicketReserveActivity : AppCompatActivity() { private fun handleEvent(event: TicketReserveEvent) = when (event) { is ShowTicketTypes -> handleShowTicketTypes( stageStartTime = event.stageStartTime, - tickets = event.tickets, + reservationTickets = event.tickets, ) is ReserveTicketSuccess -> handleReserveTicketSuccess(event.reservedTicket) @@ -73,7 +74,7 @@ class TicketReserveActivity : AppCompatActivity() { private fun handleShowTicketTypes( stageStartTime: LocalDateTime, - tickets: List, + reservationTickets: List, ) { TicketReserveBottomSheetFragment.newInstance( stageStartTime.format( @@ -82,7 +83,14 @@ class TicketReserveActivity : AppCompatActivity() { Locale.KOREA, ), ), - tickets, + reservationTickets.map { + BottomSheetReservationTicketArg( + id = it.id, + remainAmount = it.remainAmount, + ticketType = it.ticketType, + totalAmount = it.totalAmount + ) + }, ).show(supportFragmentManager, TicketReserveBottomSheetFragment::class.java.name) } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveEvent.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveEvent.kt index 04ef9faf5..5cc0f3cc7 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveEvent.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveEvent.kt @@ -1,13 +1,13 @@ package com.festago.festago.presentation.ui.ticketreserve +import com.festago.festago.model.ReservationTicket import com.festago.festago.model.ReservedTicket -import com.festago.festago.presentation.model.ReservationTicketUiModel import java.time.LocalDateTime sealed interface TicketReserveEvent { class ShowTicketTypes( val stageStartTime: LocalDateTime, - val tickets: List, + val tickets: List, ) : TicketReserveEvent class ReserveTicketSuccess(val reservedTicket: ReservedTicket) : TicketReserveEvent diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveItemUiState.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveItemUiState.kt index f3da26b8e..d199c7a15 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveItemUiState.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveItemUiState.kt @@ -1,18 +1,15 @@ package com.festago.festago.presentation.ui.ticketreserve -import android.os.Parcelable -import com.festago.festago.presentation.model.ReservationTicketUiModel -import kotlinx.parcelize.Parcelize +import com.festago.festago.model.ReservationTicket import java.time.LocalDateTime -@Parcelize data class TicketReserveItemUiState( val id: Int, val lineUp: String, val startTime: LocalDateTime, val ticketOpenTime: LocalDateTime, - val reservationTickets: List, + val reservationTickets: List, val canReserve: Boolean, val isSigned: Boolean, val onShowStageTickets: (stageId: Int, stageStartTime: LocalDateTime) -> Unit, -) : Parcelable +) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveViewModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveViewModel.kt index 110270e00..0a22913d7 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveViewModel.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveViewModel.kt @@ -7,7 +7,6 @@ import androidx.lifecycle.viewModelScope import com.festago.festago.analytics.AnalyticsHelper import com.festago.festago.analytics.logNetworkFailure import com.festago.festago.model.ReservationStage -import com.festago.festago.presentation.mapper.toPresentation import com.festago.festago.presentation.util.MutableSingleLiveData import com.festago.festago.presentation.util.SingleLiveData import com.festago.festago.repository.AuthRepository @@ -65,7 +64,7 @@ class TicketReserveViewModel( _event.setValue( TicketReserveEvent.ShowTicketTypes( stageStartTime, - tickets.map { it.toPresentation() }, + tickets, ), ) }.onFailure { @@ -93,7 +92,7 @@ class TicketReserveViewModel( lineUp = lineUp, startTime = startTime, ticketOpenTime = ticketOpenTime, - reservationTickets = reservationTickets.map { it.toPresentation() }, + reservationTickets = reservationTickets, canReserve = LocalDateTime.now().isAfter(ticketOpenTime), isSigned = authRepository.isSigned, onShowStageTickets = ::showTicketTypes, diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/BottomSheetReservationTicketArg.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/BottomSheetReservationTicketArg.kt new file mode 100644 index 000000000..477935430 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/BottomSheetReservationTicketArg.kt @@ -0,0 +1,12 @@ +package com.festago.festago.presentation.ui.ticketreserve.bottomsheet + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class BottomSheetReservationTicketArg( + val id: Int, + val remainAmount: Int, + val ticketType: String, + val totalAmount: Int, +) : Parcelable diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomItem.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomItem.kt index b52495f5b..745447aa5 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomItem.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomItem.kt @@ -1,8 +1,6 @@ package com.festago.festago.presentation.ui.ticketreserve.bottomsheet -import com.festago.festago.presentation.model.ReservationTicketUiModel - data class TicketReserveBottomItem( - val ticket: ReservationTicketUiModel, + val ticket: BottomSheetReservationTicketArg, val isSelected: Boolean = false, ) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomSheetFragment.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomSheetFragment.kt index 810924c90..7e632bbf0 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomSheetFragment.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomSheetFragment.kt @@ -6,7 +6,6 @@ import android.view.View import android.view.ViewGroup import androidx.lifecycle.ViewModelProvider import com.festago.festago.databinding.FragmentTicketReserveBottomSheetBinding -import com.festago.festago.presentation.model.ReservationTicketUiModel import com.festago.festago.presentation.ui.ticketreserve.TicketReserveViewModel import com.festago.festago.presentation.util.getParcelableArrayListCompat import com.google.android.material.bottomsheet.BottomSheetDialogFragment @@ -44,7 +43,7 @@ class TicketReserveBottomSheetFragment : BottomSheetDialogFragment() { getString(KEY_STAGE_START_TIME)?.let { startTime -> binding.stageStartTime = startTime } - getParcelableArrayListCompat(KEY_ITEMS)?.let { + getParcelableArrayListCompat(KEY_ITEMS)?.let { ticketTypeAdapter.submitList(it.map(::TicketReserveBottomItem)) } } @@ -69,7 +68,7 @@ class TicketReserveBottomSheetFragment : BottomSheetDialogFragment() { fun newInstance( stageStartTime: String, - items: List, + items: List, ) = TicketReserveBottomSheetFragment().apply { arguments = Bundle().apply { putString(KEY_STAGE_START_TIME, stageStartTime) diff --git a/android/festago/app/src/test/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveViewModelTest.kt b/android/festago/app/src/test/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveViewModelTest.kt index d1ac9905f..a013a2485 100644 --- a/android/festago/app/src/test/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveViewModelTest.kt +++ b/android/festago/app/src/test/java/com/festago/festago/presentation/ui/ticketreserve/TicketReserveViewModelTest.kt @@ -6,7 +6,6 @@ import com.festago.festago.model.Reservation import com.festago.festago.model.ReservationStage import com.festago.festago.model.ReservationTicket import com.festago.festago.model.ReservedTicket -import com.festago.festago.presentation.mapper.toPresentation import com.festago.festago.repository.AuthRepository import com.festago.festago.repository.FestivalRepository import com.festago.festago.repository.ReservationTicketRepository @@ -166,7 +165,7 @@ class TicketReserveViewModelTest { // and val event = vm.event.getValue() as TicketReserveEvent.ShowTicketTypes - assertThat(event.tickets).isEqualTo(fakeReservationTickets.map { it.toPresentation() }) + assertThat(event.tickets).isEqualTo(fakeReservationTickets) } @Test From 0b739415c4b435ef67d556a363ec3b8029dabda8 Mon Sep 17 00:00:00 2001 From: SeongHoonC <108349655+SeongHoonC@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:30:26 +0900 Subject: [PATCH 12/74] =?UTF-8?q?[AN/USER]=20refactor:=20=ED=8B=B0?= =?UTF-8?q?=EC=BC=93=20=EB=AA=A9=EB=A1=9D=20=ED=99=94=EB=A9=B4=20presentat?= =?UTF-8?q?ion=20model=20=EC=9D=84=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80?= =?UTF-8?q?=20=EC=95=8A=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=20(#420)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 티켓 아이템 UiState 팩토리 메서드 생성 * refactor: TicketListItemUiState 변경 사항 화면에 반영 --- .../home/ticketlist/TicketListItemUiState.kt | 41 +++++++++++++------ .../ticketlist/TicketListItemViewHolder.kt | 12 +++++- .../ui/home/ticketlist/TicketListViewModel.kt | 21 ++-------- .../src/main/res/layout/item_ticket_list.xml | 3 +- .../ticketlist/TicketListViewModelTest.kt | 21 ++-------- 5 files changed, 47 insertions(+), 51 deletions(-) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListItemUiState.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListItemUiState.kt index d5c03ca6e..01cd67ecd 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListItemUiState.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListItemUiState.kt @@ -1,19 +1,36 @@ package com.festago.festago.presentation.ui.home.ticketlist -import com.festago.festago.presentation.model.StageUiModel -import com.festago.festago.presentation.model.TicketConditionUiModel +import com.festago.festago.model.Stage +import com.festago.festago.model.Ticket +import com.festago.festago.model.TicketCondition import java.time.LocalDateTime data class TicketListItemUiState( - val id: Long = -1, - val number: Int = -1, - val entryTime: LocalDateTime = LocalDateTime.MIN, - val reserveAt: LocalDateTime = LocalDateTime.MIN, - val condition: TicketConditionUiModel = TicketConditionUiModel.BEFORE_ENTRY, - val stage: StageUiModel = StageUiModel(), - val festivalId: Int = -1, - val festivalName: String = "", - val festivalThumbnail: String = "", + val id: Long, + val number: Int, + val entryTime: LocalDateTime, + val reserveAt: LocalDateTime, + val condition: TicketCondition, + val stage: Stage, + val festivalId: Int, + val festivalName: String, + val festivalThumbnail: String, val canEntry: Boolean, val onTicketEntry: (ticketId: Long) -> Unit, -) +) { + companion object { + fun of(ticket: Ticket, onTicketEntry: (ticketId: Long) -> Unit) = TicketListItemUiState( + id = ticket.id, + number = ticket.number, + entryTime = ticket.entryTime, + reserveAt = ticket.reserveAt, + condition = ticket.condition, + stage = ticket.stage, + festivalId = ticket.festivalTicket.id, + festivalName = ticket.festivalTicket.name, + festivalThumbnail = ticket.festivalTicket.thumbnail, + canEntry = LocalDateTime.now().isAfter(ticket.entryTime), + onTicketEntry = onTicketEntry, + ) + } +} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListItemViewHolder.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListItemViewHolder.kt index 26f34bd45..ebd8045c4 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListItemViewHolder.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListItemViewHolder.kt @@ -6,6 +6,7 @@ import android.widget.Button import androidx.recyclerview.widget.RecyclerView import com.festago.festago.R import com.festago.festago.databinding.ItemTicketListBinding +import com.festago.festago.model.TicketCondition import java.time.format.DateTimeFormatter class TicketListItemViewHolder( @@ -14,13 +15,22 @@ class TicketListItemViewHolder( fun bind(item: TicketListItemUiState) { binding.ticket = item + setTicketConditionText(item) setTicketEntryBtn(item) } + private fun setTicketConditionText(item: TicketListItemUiState) { + val ticketConditionResId = when (item.condition) { + TicketCondition.BEFORE_ENTRY -> R.string.all_ticket_state_before_entry + TicketCondition.AFTER_ENTRY -> R.string.all_ticket_state_after_entry + TicketCondition.AWAY -> R.string.all_ticket_state_away + } + binding.tvTicketCondition.setText(ticketConditionResId) + } + private fun setTicketEntryBtn(item: TicketListItemUiState) { val btn = binding.btnTicketEntry btn.isEnabled = item.canEntry - setTicketEntryBtnText(isAfterEntryTime = item.canEntry, btn = btn, ticket = item) } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListViewModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListViewModel.kt index 8a7788194..c777d84be 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListViewModel.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/ticketlist/TicketListViewModel.kt @@ -6,13 +6,10 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.festago.festago.analytics.AnalyticsHelper import com.festago.festago.analytics.logNetworkFailure -import com.festago.festago.model.Ticket -import com.festago.festago.presentation.mapper.toPresentation import com.festago.festago.presentation.util.MutableSingleLiveData import com.festago.festago.presentation.util.SingleLiveData import com.festago.festago.repository.TicketRepository import kotlinx.coroutines.launch -import java.time.LocalDateTime class TicketListViewModel( private val ticketRepository: TicketRepository, @@ -29,7 +26,9 @@ class TicketListViewModel( viewModelScope.launch { ticketRepository.loadCurrentTickets() .onSuccess { tickets -> - _uiState.value = TicketListUiState.Success(tickets.map { it.toUiState() }) + _uiState.value = TicketListUiState.Success( + tickets.map { TicketListItemUiState.of(it, ::showTicketEntry) }, + ) }.onFailure { _uiState.value = TicketListUiState.Error analyticsHelper.logNetworkFailure(KEY_LOAD_TICKETS_LOG, it.message.toString()) @@ -41,20 +40,6 @@ class TicketListViewModel( _event.setValue(TicketListEvent.ShowTicketEntry(ticketId)) } - private fun Ticket.toUiState() = TicketListItemUiState( - id = id, - number = number, - entryTime = entryTime, - reserveAt = reserveAt, - condition = condition.toPresentation(), - stage = stage.toPresentation(), - festivalId = festivalTicket.id, - festivalName = festivalTicket.name, - festivalThumbnail = festivalTicket.thumbnail, - canEntry = LocalDateTime.now().isAfter(entryTime), - onTicketEntry = ::showTicketEntry, - ) - companion object { private const val KEY_LOAD_TICKETS_LOG = "load_tickets" } diff --git a/android/festago/app/src/main/res/layout/item_ticket_list.xml b/android/festago/app/src/main/res/layout/item_ticket_list.xml index 23bc103f1..eb8335a0a 100644 --- a/android/festago/app/src/main/res/layout/item_ticket_list.xml +++ b/android/festago/app/src/main/res/layout/item_ticket_list.xml @@ -90,11 +90,10 @@ tools:text="100번" /> Date: Mon, 4 Sep 2023 14:17:40 +0900 Subject: [PATCH 13/74] =?UTF-8?q?[AN/USER]=20=EC=98=88=EB=A7=A4=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=EC=9D=84=20=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EC=9C=BC=EB=A9=B4=20=EB=B2=84=ED=8A=BC=EC=9D=B4=20=EB=B9=84?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94=20=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#423)=20(#424)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bottomsheet/TicketReserveBottomSheetFragment.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomSheetFragment.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomSheetFragment.kt index 7e632bbf0..fab58b27c 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomSheetFragment.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketreserve/bottomsheet/TicketReserveBottomSheetFragment.kt @@ -19,6 +19,7 @@ class TicketReserveBottomSheetFragment : BottomSheetDialogFragment() { private val ticketTypeAdapter = TicketReserveBottomSheetAdapter { ticketId -> binding.selectedTicketTypeId = ticketId + binding.btnReserveTicket.isEnabled = true } override fun onCreate(savedInstanceState: Bundle?) { @@ -55,6 +56,7 @@ class TicketReserveBottomSheetFragment : BottomSheetDialogFragment() { binding.rvTicketTypes.adapter = ticketTypeAdapter val onReserve: (Int) -> Unit = { id -> vm.reserveTicket(id) } binding.onReserve = onReserve + binding.btnReserveTicket.isEnabled = false } override fun onDestroyView() { From eee3d2882426d4692bfe4a58d28925b672ffcbba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=84=ED=81=AC?= <37167652+re4rk@users.noreply.github.com> Date: Mon, 4 Sep 2023 14:18:44 +0900 Subject: [PATCH 14/74] =?UTF-8?q?[AN/USER]=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20=ED=9B=84=20=EB=82=A8=EC=95=84=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?ui=20model=20=EB=AA=A8=EB=91=90=20=EC=A0=9C=EA=B1=B0=20(#421)?= =?UTF-8?q?=20(#422)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 티켓 코드 uiModel 제거 * refactor: 티켓 ui model 제거 * refactor: 유저 정보 ui model 제거 * refactor: 스테이지 ui model 제거 * refactor: 예약 ui model 제거 --- .../presentation/mapper/ReservationMapper.kt | 0 .../mapper/ReservationTicketMapper.kt | 18 ------------------ .../presentation/mapper/StageMapper.kt | 14 -------------- .../presentation/mapper/TicketCodeMapper.kt | 8 -------- .../presentation/mapper/TicketMapper.kt | 19 ------------------- .../presentation/mapper/TicketStateMapper.kt | 18 ------------------ .../presentation/mapper/UserProfileMapper.kt | 10 ---------- .../model/ReservationTicketUiModel.kt | 12 ------------ .../presentation/model/StageUiModel.kt | 8 -------- .../presentation/model/TicketCodeUiModel.kt | 10 ---------- .../model/TicketConditionUiModel.kt | 11 ----------- .../presentation/model/TicketUiModel.kt | 15 --------------- .../presentation/model/UserProfileUiModel.kt | 7 ------- .../ui/ticketentry/TicketEntryActivity.kt | 3 +-- 14 files changed, 1 insertion(+), 152 deletions(-) delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationMapper.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationTicketMapper.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/mapper/StageMapper.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketCodeMapper.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketMapper.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketStateMapper.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/mapper/UserProfileMapper.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservationTicketUiModel.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/model/StageUiModel.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketCodeUiModel.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketConditionUiModel.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketUiModel.kt delete mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/model/UserProfileUiModel.kt diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationMapper.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationMapper.kt deleted file mode 100644 index e69de29bb..000000000 diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationTicketMapper.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationTicketMapper.kt deleted file mode 100644 index 4f17bb0f2..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/ReservationTicketMapper.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.festago.festago.presentation.mapper - -import com.festago.festago.model.ReservationTicket -import com.festago.festago.presentation.model.ReservationTicketUiModel - -fun ReservationTicket.toPresentation() = ReservationTicketUiModel( - id = id, - remainAmount = remainAmount, - ticketType = ticketType, - totalAmount = totalAmount, -) - -fun ReservationTicketUiModel.toDomain() = ReservationTicket( - id = id, - remainAmount = remainAmount, - ticketType = ticketType, - totalAmount = totalAmount, -) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/StageMapper.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/StageMapper.kt deleted file mode 100644 index f6ca17e9b..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/StageMapper.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.festago.festago.presentation.mapper - -import com.festago.festago.model.Stage -import com.festago.festago.presentation.model.StageUiModel - -fun Stage.toPresentation() = StageUiModel( - id = id, - startTime = startTime, -) - -fun StageUiModel.toDomain() = Stage( - id = id, - startTime = startTime, -) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketCodeMapper.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketCodeMapper.kt deleted file mode 100644 index 56117dafd..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketCodeMapper.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.festago.festago.presentation.mapper - -import com.festago.festago.model.TicketCode -import com.festago.festago.presentation.model.TicketCodeUiModel - -fun TicketCode.toPresentation(): TicketCodeUiModel = TicketCodeUiModel(code = code, period = period) - -fun TicketCodeUiModel.toDomain(): TicketCode = TicketCode(code = code, period = period) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketMapper.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketMapper.kt deleted file mode 100644 index 9c8506a44..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketMapper.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.festago.festago.presentation.mapper - -import com.festago.festago.model.Ticket -import com.festago.festago.presentation.model.TicketUiModel - -fun Ticket.toPresentation(): TicketUiModel = TicketUiModel( - id = id, - number = number, - entryTime = entryTime, - condition = condition.toPresentation(), - stage = stage.toPresentation(), - reserveAt = reserveAt, - festivalId = festivalTicket.id, - festivalName = festivalTicket.name, - festivalThumbnail = festivalTicket.thumbnail, -) - -fun List.toPresentation(): List = - this.map { ticket -> ticket.toPresentation() } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketStateMapper.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketStateMapper.kt deleted file mode 100644 index c74b34fd7..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/TicketStateMapper.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.festago.festago.presentation.mapper - -import com.festago.festago.model.TicketCondition -import com.festago.festago.presentation.model.TicketConditionUiModel - -fun TicketCondition.toPresentation(): TicketConditionUiModel = - when (this) { - TicketCondition.BEFORE_ENTRY -> TicketConditionUiModel.BEFORE_ENTRY - TicketCondition.AFTER_ENTRY -> TicketConditionUiModel.AFTER_ENTRY - TicketCondition.AWAY -> TicketConditionUiModel.AWAY - } - -fun TicketConditionUiModel.toDomain(): TicketCondition = - when (this) { - TicketConditionUiModel.BEFORE_ENTRY -> TicketCondition.BEFORE_ENTRY - TicketConditionUiModel.AFTER_ENTRY -> TicketCondition.AFTER_ENTRY - TicketConditionUiModel.AWAY -> TicketCondition.AWAY - } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/UserProfileMapper.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/UserProfileMapper.kt deleted file mode 100644 index a959a0af5..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/mapper/UserProfileMapper.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.festago.festago.presentation.mapper - -import com.festago.festago.model.UserProfile -import com.festago.festago.presentation.model.UserProfileUiModel - -fun UserProfile.toPresentation(): UserProfileUiModel = UserProfileUiModel( - memberId = memberId, - nickName = nickName, - profileImage = profileImage, -) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservationTicketUiModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservationTicketUiModel.kt deleted file mode 100644 index add00010f..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/model/ReservationTicketUiModel.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.festago.festago.presentation.model - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -@Parcelize -data class ReservationTicketUiModel( - val id: Int, - val remainAmount: Int, - val ticketType: String, - val totalAmount: Int, -) : Parcelable diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/model/StageUiModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/model/StageUiModel.kt deleted file mode 100644 index 7ab8bc6e4..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/model/StageUiModel.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.festago.festago.presentation.model - -import java.time.LocalDateTime - -data class StageUiModel( - val id: Int = -1, - val startTime: LocalDateTime = LocalDateTime.MIN, -) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketCodeUiModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketCodeUiModel.kt deleted file mode 100644 index 6c7d699b1..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketCodeUiModel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.festago.festago.presentation.model - -data class TicketCodeUiModel( - val code: String, - val period: Int, -) { - companion object { - val EMPTY = TicketCodeUiModel(code = "code", period = 0) - } -} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketConditionUiModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketConditionUiModel.kt deleted file mode 100644 index 53fabaa82..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketConditionUiModel.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.festago.festago.presentation.model - -import androidx.annotation.StringRes -import com.festago.festago.R - -enum class TicketConditionUiModel(@StringRes val stateName: Int) { - - BEFORE_ENTRY(R.string.all_ticket_state_before_entry), - AFTER_ENTRY(R.string.all_ticket_state_after_entry), - AWAY(R.string.all_ticket_state_away), -} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketUiModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketUiModel.kt deleted file mode 100644 index 432bf2ae6..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/model/TicketUiModel.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.festago.festago.presentation.model - -import java.time.LocalDateTime - -data class TicketUiModel( - val id: Long = -1, - val number: Int = -1, - val entryTime: LocalDateTime = LocalDateTime.MIN, - val reserveAt: LocalDateTime = LocalDateTime.MIN, - val condition: TicketConditionUiModel = TicketConditionUiModel.BEFORE_ENTRY, - val stage: StageUiModel = StageUiModel(), - val festivalId: Int = -1, - val festivalName: String = "", - val festivalThumbnail: String = "", -) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/model/UserProfileUiModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/model/UserProfileUiModel.kt deleted file mode 100644 index 223f24371..000000000 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/model/UserProfileUiModel.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.festago.festago.presentation.model - -data class UserProfileUiModel( - val memberId: Long = -1, - val nickName: String = "", - val profileImage: String = "", -) diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryActivity.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryActivity.kt index 6d7a3184f..ec654e3d0 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryActivity.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ticketentry/TicketEntryActivity.kt @@ -8,7 +8,6 @@ import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.core.content.res.ResourcesCompat import com.festago.festago.databinding.ActivityTicketEntryBinding -import com.festago.festago.presentation.mapper.toPresentation import com.festago.festago.presentation.ui.FestagoViewModelFactory import com.google.zxing.BarcodeFormat import com.journeyapps.barcodescanner.BarcodeEncoder @@ -66,7 +65,7 @@ class TicketEntryActivity : AppCompatActivity() { private fun handleSuccess(uiState: TicketEntryUiState.Success) { binding.successState = uiState - val ticketCode = uiState.ticketCode.toPresentation() + val ticketCode = uiState.ticketCode val bitmap = BarcodeEncoder().encodeBitmap( ticketCode.code, From c6795605f0d8755f92f4a4aa8bfa730d8f252790 Mon Sep 17 00:00:00 2001 From: seokjin8678 Date: Mon, 11 Sep 2023 17:25:44 +0900 Subject: [PATCH 15/74] =?UTF-8?q?[BE]=20feat:=20Flyway=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20(#246)=20(#334)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: Flyway 의존성 추가 * chore: Flyway 설정 추가 * chore: 서브모듈 업데이트 * chore: h2 설정 제거 * feat: 최신 브랜치 반영 * feat: Admin 테이블 추가 * feat: 최신 엔티티 DDL 설정 * feat: submodule 업데이트 --- backend/build.gradle | 4 + backend/docker/docker-compose.yml | 15 ++ .../java/com/festago/auth/domain/Admin.java | 3 +- .../main/java/com/festago/domain/School.java | 2 +- .../main/java/com/festago/domain/Student.java | 2 +- .../src/main/resources/application-local.yml | 16 +- .../main/resources/db/migration/V1__init.sql | 195 ++++++++++++++++++ backend/src/main/resources/festago-config | 2 +- .../src/test/resources/application-test.yml | 2 + 9 files changed, 230 insertions(+), 11 deletions(-) create mode 100644 backend/docker/docker-compose.yml create mode 100644 backend/src/main/resources/db/migration/V1__init.sql diff --git a/backend/build.gradle b/backend/build.gradle index d28b12bcd..d36481f4e 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -43,6 +43,10 @@ dependencies { // Mockito testImplementation 'org.mockito:mockito-inline' + + // Flyway + implementation 'org.flywaydb:flyway-core' + implementation 'org.flywaydb:flyway-mysql' } tasks.named('test') { diff --git a/backend/docker/docker-compose.yml b/backend/docker/docker-compose.yml new file mode 100644 index 000000000..03d6579cf --- /dev/null +++ b/backend/docker/docker-compose.yml @@ -0,0 +1,15 @@ +version: "3.8" +services: + db: + image: mysql:8.0.33 + container_name: festago-local-db + restart: always + ports: + - "13306:3306" + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: festago + MYSQL_USER: festago + MYSQL_PASSWORD: festago + TZ: Asia/Seoul + command: [ "mysqld", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_general_ci" ] diff --git a/backend/src/main/java/com/festago/auth/domain/Admin.java b/backend/src/main/java/com/festago/auth/domain/Admin.java index abf4530c5..60aec0c40 100644 --- a/backend/src/main/java/com/festago/auth/domain/Admin.java +++ b/backend/src/main/java/com/festago/auth/domain/Admin.java @@ -1,12 +1,13 @@ package com.festago.auth.domain; +import com.festago.domain.BaseTimeEntity; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @Entity -public class Admin { +public class Admin extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/backend/src/main/java/com/festago/domain/School.java b/backend/src/main/java/com/festago/domain/School.java index 6e701a961..993fc98ce 100644 --- a/backend/src/main/java/com/festago/domain/School.java +++ b/backend/src/main/java/com/festago/domain/School.java @@ -10,7 +10,7 @@ import jakarta.validation.constraints.Size; @Entity -public class School { +public class School extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/backend/src/main/java/com/festago/domain/Student.java b/backend/src/main/java/com/festago/domain/Student.java index 768b0e462..69b10ff53 100644 --- a/backend/src/main/java/com/festago/domain/Student.java +++ b/backend/src/main/java/com/festago/domain/Student.java @@ -13,7 +13,7 @@ import jakarta.validation.constraints.Size; @Entity -public class Student { +public class Student extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/backend/src/main/resources/application-local.yml b/backend/src/main/resources/application-local.yml index e5c6d52bd..ddf517560 100644 --- a/backend/src/main/resources/application-local.yml +++ b/backend/src/main/resources/application-local.yml @@ -1,19 +1,21 @@ spring: datasource: - hikari: - jdbc-url: jdbc:h2:~/festago;MODE=MYSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE - username: sa + url: jdbc:mysql://localhost:13306/festago + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver jpa: properties: hibernate: format_sql: true show-sql: true hibernate: - ddl-auto: create + ddl-auto: validate open-in-view: false - h2: - console: - enabled: true + flyway: + enabled: true + baseline-on-migrate: true + baseline-version: 1 logging: file: diff --git a/backend/src/main/resources/db/migration/V1__init.sql b/backend/src/main/resources/db/migration/V1__init.sql new file mode 100644 index 000000000..3622ca577 --- /dev/null +++ b/backend/src/main/resources/db/migration/V1__init.sql @@ -0,0 +1,195 @@ +create table if not exists festival +( + id bigint not null auto_increment, + created_at datetime(6), + updated_at datetime(6), + end_date date, + name varchar(255), + start_date date, + thumbnail varchar(255), + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +create table if not exists member +( + id bigint not null auto_increment, + created_at datetime(6), + updated_at datetime(6), + deleted_at datetime(6), + nickname varchar(255), + profile_image varchar(255), + social_id varchar(255), + social_type varchar(255), + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +create table if not exists member_ticket +( + id bigint not null auto_increment, + created_at datetime(6), + updated_at datetime(6), + entry_state varchar(255), + entry_time datetime(6), + number integer not null, + ticket_type varchar(255), + owner_id bigint, + stage_id bigint, + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +create table if not exists stage +( + id bigint not null auto_increment, + created_at datetime(6), + updated_at datetime(6), + line_up varchar(255), + start_time datetime(6) not null, + ticket_open_time datetime(6), + festival_id bigint, + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +create table if not exists ticket +( + id bigint not null auto_increment, + created_at datetime(6), + updated_at datetime(6), + ticket_type varchar(255), + stage_id bigint, + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +create table if not exists ticket_amount +( + ticket_id bigint not null, + created_at datetime(6), + updated_at datetime(6), + reserved_amount integer not null, + total_amount integer not null, + primary key (ticket_id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +create table if not exists ticket_entry_time +( + id bigint not null auto_increment, + created_at datetime(6), + updated_at datetime(6), + amount integer, + entry_time datetime(6), + ticket_id bigint, + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +create table if not exists school +( + id bigint not null auto_increment, + created_at datetime null, + updated_at datetime null, + domain varchar(50) not null, + name varchar(255) not null, + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +create table if not exists student +( + id bigint not null auto_increment, + created_at datetime null, + updated_at datetime null, + username varchar(255) not null, + member_id bigint not null, + school_id bigint not null, + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +create table if not exists student_code +( + id bigint auto_increment not null, + created_at datetime null, + updated_at datetime null, + school_id bigint null, + member_id bigint null, + code varchar(255) null, + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +create table if not exists admin +( + id bigint auto_increment not null, + created_at datetime null, + updated_at datetime null, + username varchar(255) null, + password varchar(255) null, + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +alter table member_ticket + add constraint fk_member_ticket__member + foreign key (owner_id) + references member (id); + +alter table member_ticket + add constraint fk_member_ticket__stage + foreign key (stage_id) + references stage (id); + +alter table stage + add constraint fk_stage__festival + foreign key (festival_id) + references festival (id); + +alter table ticket + add constraint fk_ticket__stage + foreign key (stage_id) + references stage (id); + +alter table ticket_amount + add constraint fk_ticket_amount__ticket + foreign key (ticket_id) + references ticket (id); + +alter table ticket_entry_time + add constraint fk_ticket_entry_time__ticket + foreign key (ticket_id) + references ticket (id); + +alter table student + add constraint fk_student__member + foreign key (member_id) + references member (id); + +alter table student + add constraint fk_student__school + foreign key (school_id) + references school (id); + +alter table student_code + add constraint fk_student_code__member + foreign key (member_id) + references member (id); + +alter table student_code + add constraint fk_student_code__school + foreign key (school_id) + references school (id); diff --git a/backend/src/main/resources/festago-config b/backend/src/main/resources/festago-config index c62207dbc..9c3dddc6a 160000 --- a/backend/src/main/resources/festago-config +++ b/backend/src/main/resources/festago-config @@ -1 +1 @@ -Subproject commit c62207dbc32365bd0b0f6944a355f4f879073bc2 +Subproject commit 9c3dddc6a3c67db85357d819dfb3fc95e8a030aa diff --git a/backend/src/test/resources/application-test.yml b/backend/src/test/resources/application-test.yml index 30dbbd26a..44d7f0166 100644 --- a/backend/src/test/resources/application-test.yml +++ b/backend/src/test/resources/application-test.yml @@ -9,6 +9,8 @@ spring: hibernate: ddl-auto: create open-in-view: false + flyway: + enabled: false logging: file: From 8d69c94c698527679df2983ab2440b6af4e56594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hyun-Seo=20Oh=20/=20=EC=98=A4=ED=98=84=EC=84=9C?= <100915276+carsago@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:42:20 +0900 Subject: [PATCH 16/74] =?UTF-8?q?[BE]=20feat:=20=EC=9D=B4=EB=A9=94?= =?UTF-8?q?=EC=9D=BC=20=EC=BD=94=EB=93=9C=EB=A5=BC=20=ED=86=B5=ED=95=9C=20?= =?UTF-8?q?=ED=95=99=EC=83=9D=20=EC=9D=B8=EC=A6=9D=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=9D=84=20=EC=B6=94=EA=B0=80=20(#430)=20(#434)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 학생 인증 기능 추가 * refactor: 인증 코드 입력시 회원 검증 하도록 변경 * feat: flyway 반영 * fix: submodule 버전 수정 --------- Co-authored-by: seokjin8678 --- .../festago/application/StudentService.java | 13 +++- .../main/java/com/festago/domain/School.java | 4 + .../main/java/com/festago/domain/Student.java | 4 + .../java/com/festago/domain/StudentCode.java | 29 ++++++- .../festago/domain/StudentCodeRepository.java | 3 + .../festago/dto/StudentVerificateRequest.java | 5 ++ .../java/com/festago/exception/ErrorCode.java | 1 + .../presentation/StudentController.java | 10 +++ .../V2__student_code_add_username.sql | 2 + .../application/StudentServiceTest.java | 59 ++++++++++++++ .../presentation/StudentControllerTest.java | 76 ++++++++++++++----- 11 files changed, 181 insertions(+), 25 deletions(-) create mode 100644 backend/src/main/java/com/festago/dto/StudentVerificateRequest.java create mode 100644 backend/src/main/resources/db/migration/V2__student_code_add_username.sql diff --git a/backend/src/main/java/com/festago/application/StudentService.java b/backend/src/main/java/com/festago/application/StudentService.java index 77e320730..ea52de469 100644 --- a/backend/src/main/java/com/festago/application/StudentService.java +++ b/backend/src/main/java/com/festago/application/StudentService.java @@ -5,6 +5,7 @@ import com.festago.domain.MemberRepository; import com.festago.domain.School; import com.festago.domain.SchoolRepository; +import com.festago.domain.Student; import com.festago.domain.StudentCode; import com.festago.domain.StudentCodeRepository; import com.festago.domain.StudentRepository; @@ -12,6 +13,7 @@ import com.festago.domain.VerificationCodeProvider; import com.festago.domain.VerificationMailPayload; import com.festago.dto.StudentSendMailRequest; +import com.festago.dto.StudentVerificateRequest; import com.festago.exception.BadRequestException; import com.festago.exception.ErrorCode; import com.festago.exception.NotFoundException; @@ -47,7 +49,7 @@ public void sendVerificationMail(Long memberId, StudentSendMailRequest request) School school = findSchool(request.schoolId()); VerificationCode code = codeProvider.provide(); studentCodeRepository.deleteByMember(member); - studentCodeRepository.save(new StudentCode(code, member, school)); + studentCodeRepository.save(new StudentCode(code, school, member, request.username())); mailClient.send(new VerificationMailPayload(code, request.username(), school.getDomain())); } @@ -72,4 +74,13 @@ private School findSchool(Long schoolId) { return schoolRepository.findById(schoolId) .orElseThrow(() -> new NotFoundException(ErrorCode.SCHOOL_NOT_FOUND)); } + + public void verificate(Long memberId, StudentVerificateRequest request) { + validateStudent(memberId); + Member member = findMember(memberId); + StudentCode studentCode = studentCodeRepository.findByCodeAndMember(new VerificationCode(request.code()), member) + .orElseThrow(() -> new BadRequestException(ErrorCode.INVALID_STUDENT_VERIFICATION_CODE)); + studentRepository.save(new Student(member, studentCode.getSchool(), studentCode.getUsername())); + studentCodeRepository.deleteByMember(member); + } } diff --git a/backend/src/main/java/com/festago/domain/School.java b/backend/src/main/java/com/festago/domain/School.java index 993fc98ce..2275386c3 100644 --- a/backend/src/main/java/com/festago/domain/School.java +++ b/backend/src/main/java/com/festago/domain/School.java @@ -27,6 +27,10 @@ public class School extends BaseTimeEntity { protected School() { } + public School(String domain, String name) { + this(null, domain, name); + } + public School(Long id, String domain, String name) { validate(domain, name); this.id = id; diff --git a/backend/src/main/java/com/festago/domain/Student.java b/backend/src/main/java/com/festago/domain/Student.java index 69b10ff53..9e09ad219 100644 --- a/backend/src/main/java/com/festago/domain/Student.java +++ b/backend/src/main/java/com/festago/domain/Student.java @@ -34,6 +34,10 @@ public class Student extends BaseTimeEntity { protected Student() { } + public Student(Member member, School school, String username) { + this(null, member, school, username); + } + public Student(Long id, Member member, School school, String username) { validate(member, school, username); this.id = id; diff --git a/backend/src/main/java/com/festago/domain/StudentCode.java b/backend/src/main/java/com/festago/domain/StudentCode.java index 2d00b2647..935f500a2 100644 --- a/backend/src/main/java/com/festago/domain/StudentCode.java +++ b/backend/src/main/java/com/festago/domain/StudentCode.java @@ -1,5 +1,7 @@ package com.festago.domain; +import com.festago.exception.ErrorCode; +import com.festago.exception.InternalServerException; import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -8,6 +10,7 @@ import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToOne; +import org.springframework.util.StringUtils; @Entity public class StudentCode extends BaseTimeEntity { @@ -25,18 +28,32 @@ public class StudentCode extends BaseTimeEntity { @OneToOne(fetch = FetchType.LAZY) private Member member; + private String username; + protected StudentCode() { } - public StudentCode(VerificationCode code, Member member, School school) { - this(null, code, member, school); + public StudentCode(VerificationCode code, School school, Member member, String username) { + this(null, code, school, member, username); } - public StudentCode(Long id, VerificationCode code, Member member, School school) { + public StudentCode(Long id, VerificationCode code, School school, Member member, String username) { + validate(username); this.id = id; this.code = code; - this.member = member; this.school = school; + this.member = member; + this.username = username; + } + + private void validate(String username) { + if (!StringUtils.hasText(username)) { + throw new InternalServerException(ErrorCode.INTERNAL_SERVER_ERROR); + } + + if (username.length() > 255) { + throw new InternalServerException(ErrorCode.INTERNAL_SERVER_ERROR); + } } public Long getId() { @@ -54,4 +71,8 @@ public School getSchool() { public Member getMember() { return member; } + + public String getUsername() { + return username; + } } diff --git a/backend/src/main/java/com/festago/domain/StudentCodeRepository.java b/backend/src/main/java/com/festago/domain/StudentCodeRepository.java index 312b93f6d..54c627b1f 100644 --- a/backend/src/main/java/com/festago/domain/StudentCodeRepository.java +++ b/backend/src/main/java/com/festago/domain/StudentCodeRepository.java @@ -1,8 +1,11 @@ package com.festago.domain; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface StudentCodeRepository extends JpaRepository { void deleteByMember(Member member); + + Optional findByCodeAndMember(VerificationCode code, Member member); } diff --git a/backend/src/main/java/com/festago/dto/StudentVerificateRequest.java b/backend/src/main/java/com/festago/dto/StudentVerificateRequest.java new file mode 100644 index 000000000..2c22c8ecb --- /dev/null +++ b/backend/src/main/java/com/festago/dto/StudentVerificateRequest.java @@ -0,0 +1,5 @@ +package com.festago.dto; + +public record StudentVerificateRequest(String code) { + +} diff --git a/backend/src/main/java/com/festago/exception/ErrorCode.java b/backend/src/main/java/com/festago/exception/ErrorCode.java index 0de87ad2a..368ab503d 100644 --- a/backend/src/main/java/com/festago/exception/ErrorCode.java +++ b/backend/src/main/java/com/festago/exception/ErrorCode.java @@ -22,6 +22,7 @@ public enum ErrorCode { ALREADY_STUDENT_VERIFIED("이미 학교 인증이 완료된 사용자입니다."), DUPLICATE_STUDENT_EMAIL("이미 인증된 이메일입니다."), TICKET_CANNOT_RESERVE_STAGE_START("공연의 시작 시간 이후로 예매할 수 없습니다."), + INVALID_STUDENT_VERIFICATION_CODE("올바르지 않은 학생 인증 코드입니다."), // 401 EXPIRED_AUTH_TOKEN("만료된 로그인 토큰입니다."), diff --git a/backend/src/main/java/com/festago/presentation/StudentController.java b/backend/src/main/java/com/festago/presentation/StudentController.java index ff04ea373..7f0c1270a 100644 --- a/backend/src/main/java/com/festago/presentation/StudentController.java +++ b/backend/src/main/java/com/festago/presentation/StudentController.java @@ -3,6 +3,7 @@ import com.festago.application.StudentService; import com.festago.auth.annotation.Member; import com.festago.dto.StudentSendMailRequest; +import com.festago.dto.StudentVerificateRequest; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; @@ -30,4 +31,13 @@ public ResponseEntity sendEmail(@Member Long memberId, return ResponseEntity.ok() .build(); } + + @PostMapping("/verification") + @Operation(description = "학교 인증을 수행한다.", summary = "학생 인증 수행") + public ResponseEntity verificate(@Member Long memberId, + @RequestBody StudentVerificateRequest request) { + studentService.verificate(memberId, request); + return ResponseEntity.ok() + .build(); + } } diff --git a/backend/src/main/resources/db/migration/V2__student_code_add_username.sql b/backend/src/main/resources/db/migration/V2__student_code_add_username.sql new file mode 100644 index 000000000..8873d57cd --- /dev/null +++ b/backend/src/main/resources/db/migration/V2__student_code_add_username.sql @@ -0,0 +1,2 @@ +alter table student_code + add column username varchar(255); diff --git a/backend/src/test/java/com/festago/application/StudentServiceTest.java b/backend/src/test/java/com/festago/application/StudentServiceTest.java index b120fe6be..9f5896b20 100644 --- a/backend/src/test/java/com/festago/application/StudentServiceTest.java +++ b/backend/src/test/java/com/festago/application/StudentServiceTest.java @@ -2,6 +2,8 @@ import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; import com.festago.domain.MailClient; @@ -9,11 +11,13 @@ import com.festago.domain.MemberRepository; import com.festago.domain.School; import com.festago.domain.SchoolRepository; +import com.festago.domain.StudentCode; import com.festago.domain.StudentCodeRepository; import com.festago.domain.StudentRepository; import com.festago.domain.VerificationCode; import com.festago.domain.VerificationCodeProvider; import com.festago.dto.StudentSendMailRequest; +import com.festago.dto.StudentVerificateRequest; import com.festago.exception.BadRequestException; import com.festago.exception.NotFoundException; import com.festago.support.MemberFixture; @@ -168,4 +172,59 @@ class 인증_메일_전송 { .isThrownBy(() -> studentService.sendVerificationMail(memberId, request)); } } + + @Nested + class 학생_인증 { + + @Test + void 이미_학생인증정보가_존재하면_예외() { + // given + Long memberId = 1L; + StudentVerificateRequest request = new StudentVerificateRequest("123456"); + given(studentRepository.existsByMemberId(memberId)) + .willReturn(true); + + // when & then + assertThatThrownBy(() -> studentService.verificate(memberId, request)) + .isInstanceOf(BadRequestException.class) + .hasMessage("이미 학교 인증이 완료된 사용자입니다."); + } + + @Test + void 인증_코드가_존재하지_않으면_예외() { + // given + Long memberId = 1L; + StudentVerificateRequest request = new StudentVerificateRequest("123456"); + given(memberRepository.findById(anyLong())) + .willReturn(Optional.of(MemberFixture.member().build())); + given(studentCodeRepository.findByCodeAndMember(any(), any())) + .willReturn(Optional.empty()); + + // when & then + assertThatThrownBy(() -> studentService.verificate(memberId, request)) + .isInstanceOf(BadRequestException.class) + .hasMessage("올바르지 않은 학생 인증 코드입니다."); + } + + @Test + void 성공() { + // given + Long memberId = 1L; + StudentVerificateRequest request = new StudentVerificateRequest("123456"); + Member member = MemberFixture.member().build(); + given(memberRepository.findById(anyLong())) + .willReturn(Optional.of(member)); + given(studentCodeRepository.findByCodeAndMember(any(), any())) + .willReturn(Optional.of(new StudentCode( + new VerificationCode("123456"), + new School("snu.ac.kr", "서울대학교"), + member, + "ohs" + ))); + + // when & then + assertThatNoException() + .isThrownBy(() -> studentService.verificate(memberId, request)); + } + } } diff --git a/backend/src/test/java/com/festago/presentation/StudentControllerTest.java b/backend/src/test/java/com/festago/presentation/StudentControllerTest.java index 525b3c3cd..19322565d 100644 --- a/backend/src/test/java/com/festago/presentation/StudentControllerTest.java +++ b/backend/src/test/java/com/festago/presentation/StudentControllerTest.java @@ -6,10 +6,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.festago.application.StudentService; import com.festago.dto.StudentSendMailRequest; +import com.festago.dto.StudentVerificateRequest; import com.festago.support.CustomWebMvcTest; import com.festago.support.WithMockAuth; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; @@ -31,30 +33,64 @@ class StudentControllerTest { @MockBean StudentService studentService; - @Test - void 인증이_되지_않으면_401() throws Exception { - // given - StudentSendMailRequest request = new StudentSendMailRequest("user", 1L); + @Nested + class 학생_인증_메일_전송 { - // when & then - mockMvc.perform(post("/students/send-verification") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request))) - .andExpect(status().isUnauthorized()); + @Test + void 인증이_되지_않으면_401() throws Exception { + // given + StudentSendMailRequest request = new StudentSendMailRequest("user", 1L); + + // when & then + mockMvc.perform(post("/students/send-verification") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockAuth + void 학교_인증_요청() throws Exception { + // given + StudentSendMailRequest request = new StudentSendMailRequest("user", 1L); + + // when & then + mockMvc.perform(post("/students/send-verification") + .contentType(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer token") + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()); + + } } - @Test - @WithMockAuth - void 학교_인증_요청() throws Exception { - // given - StudentSendMailRequest request = new StudentSendMailRequest("user", 1L); + @Nested + class 학생_인증 { + + @Test + void 인증이_되지_않으면_401() throws Exception { + // given + StudentVerificateRequest request = new StudentVerificateRequest("123456"); + + // when & then + mockMvc.perform(post("/students/verification") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isUnauthorized()); + } - // when & then - mockMvc.perform(post("/students/send-verification") - .contentType(MediaType.APPLICATION_JSON) - .header(HttpHeaders.AUTHORIZATION, "Bearer token") - .content(objectMapper.writeValueAsString(request))) - .andExpect(status().isOk()); + @Test + @WithMockAuth + void 학교_인증_요청() throws Exception { + // given + StudentVerificateRequest request = new StudentVerificateRequest("123456"); + // when & then + mockMvc.perform(post("/students/verification") + .contentType(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer token") + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()); + } } } From 62c4644bfe8e7e70eb573ad40cff8baf3f81a193 Mon Sep 17 00:00:00 2001 From: xxeol2 Date: Mon, 11 Sep 2023 17:42:39 +0900 Subject: [PATCH 17/74] =?UTF-8?q?[BE]=20feat:=20DTO=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=BB=A8=EB=B2=A4=EC=85=98=20=EC=A0=81=EC=9A=A9=20(#148)=20?= =?UTF-8?q?(#433)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * style: 응답용 DTO 코드 컨벤션 적용 * style: 요청 DTO 코드 컨벤션 적용 --- .../java/com/festago/dto/EntryCodeResponse.java | 8 ++++++-- .../main/java/com/festago/dto/ErrorResponse.java | 4 +++- .../com/festago/dto/FestivalCreateRequest.java | 6 +++++- .../com/festago/dto/FestivalDetailResponse.java | 13 +++++++------ .../festago/dto/FestivalDetailStageResponse.java | 11 ++++++----- .../festago/dto/FestivalDetailTicketResponse.java | 9 +++++---- .../java/com/festago/dto/FestivalResponse.java | 7 ++++++- .../java/com/festago/dto/FestivalsResponse.java | 3 ++- .../festago/dto/MemberTicketFestivalResponse.java | 10 ++++++++-- .../com/festago/dto/MemberTicketResponse.java | 15 ++++++++------- .../com/festago/dto/MemberTicketsResponse.java | 3 ++- .../java/com/festago/dto/StageCreateRequest.java | 9 +++++---- .../main/java/com/festago/dto/StageResponse.java | 4 +++- .../java/com/festago/dto/StageTicketResponse.java | 9 +++++---- .../com/festago/dto/StageTicketsResponse.java | 3 ++- .../java/com/festago/dto/TicketCreateRequest.java | 6 +++++- .../com/festago/dto/TicketCreateResponse.java | 3 ++- .../com/festago/dto/TicketValidationRequest.java | 3 ++- .../com/festago/dto/TicketValidationResponse.java | 3 ++- .../java/com/festago/dto/TicketingRequest.java | 3 ++- .../java/com/festago/dto/TicketingResponse.java | 7 ++++--- 21 files changed, 90 insertions(+), 49 deletions(-) diff --git a/backend/src/main/java/com/festago/dto/EntryCodeResponse.java b/backend/src/main/java/com/festago/dto/EntryCodeResponse.java index c2a21517b..d6ff2d14f 100644 --- a/backend/src/main/java/com/festago/dto/EntryCodeResponse.java +++ b/backend/src/main/java/com/festago/dto/EntryCodeResponse.java @@ -2,9 +2,13 @@ import com.festago.domain.EntryCode; -public record EntryCodeResponse(String code, Long period) { +public record EntryCodeResponse( + String code, + Long period) { public static EntryCodeResponse of(EntryCode entryCode) { - return new EntryCodeResponse(entryCode.getCode(), entryCode.getPeriod()); + return new EntryCodeResponse( + entryCode.getCode(), + entryCode.getPeriod()); } } diff --git a/backend/src/main/java/com/festago/dto/ErrorResponse.java b/backend/src/main/java/com/festago/dto/ErrorResponse.java index 6d2e36e4f..b45ebff80 100644 --- a/backend/src/main/java/com/festago/dto/ErrorResponse.java +++ b/backend/src/main/java/com/festago/dto/ErrorResponse.java @@ -3,7 +3,9 @@ import com.festago.exception.ErrorCode; import com.festago.exception.FestaGoException; -public record ErrorResponse(ErrorCode errorCode, String message) { +public record ErrorResponse( + ErrorCode errorCode, + String message) { public static ErrorResponse from(FestaGoException festaGoException) { return ErrorResponse.from(festaGoException.getErrorCode()); diff --git a/backend/src/main/java/com/festago/dto/FestivalCreateRequest.java b/backend/src/main/java/com/festago/dto/FestivalCreateRequest.java index f214aec6b..ec10a7c21 100644 --- a/backend/src/main/java/com/festago/dto/FestivalCreateRequest.java +++ b/backend/src/main/java/com/festago/dto/FestivalCreateRequest.java @@ -4,7 +4,11 @@ import java.time.LocalDate; import java.util.Objects; -public record FestivalCreateRequest(String name, LocalDate startDate, LocalDate endDate, String thumbnail) { +public record FestivalCreateRequest( + String name, + LocalDate startDate, + LocalDate endDate, + String thumbnail) { public Festival toEntity() { if (Objects.isNull(thumbnail) || thumbnail.isBlank()) { diff --git a/backend/src/main/java/com/festago/dto/FestivalDetailResponse.java b/backend/src/main/java/com/festago/dto/FestivalDetailResponse.java index 7f283ac99..d9910e4f4 100644 --- a/backend/src/main/java/com/festago/dto/FestivalDetailResponse.java +++ b/backend/src/main/java/com/festago/dto/FestivalDetailResponse.java @@ -5,12 +5,13 @@ import java.time.LocalDate; import java.util.List; -public record FestivalDetailResponse(Long id, - String name, - LocalDate startDate, - LocalDate endDate, - String thumbnail, - List stages) { +public record FestivalDetailResponse( + Long id, + String name, + LocalDate startDate, + LocalDate endDate, + String thumbnail, + List stages) { public static FestivalDetailResponse of(Festival festival, List stages) { List stageResponses = stages.stream() diff --git a/backend/src/main/java/com/festago/dto/FestivalDetailStageResponse.java b/backend/src/main/java/com/festago/dto/FestivalDetailStageResponse.java index 04bf9a9ec..c25aeecbe 100644 --- a/backend/src/main/java/com/festago/dto/FestivalDetailStageResponse.java +++ b/backend/src/main/java/com/festago/dto/FestivalDetailStageResponse.java @@ -4,11 +4,12 @@ import java.time.LocalDateTime; import java.util.List; -public record FestivalDetailStageResponse(Long id, - LocalDateTime startTime, - LocalDateTime ticketOpenTime, - String lineUp, - List tickets) { +public record FestivalDetailStageResponse( + Long id, + LocalDateTime startTime, + LocalDateTime ticketOpenTime, + String lineUp, + List tickets) { public static FestivalDetailStageResponse from(Stage stage) { List tickets = stage.getTickets().stream() diff --git a/backend/src/main/java/com/festago/dto/FestivalDetailTicketResponse.java b/backend/src/main/java/com/festago/dto/FestivalDetailTicketResponse.java index f197d22f7..848ccc865 100644 --- a/backend/src/main/java/com/festago/dto/FestivalDetailTicketResponse.java +++ b/backend/src/main/java/com/festago/dto/FestivalDetailTicketResponse.java @@ -4,10 +4,11 @@ import com.festago.domain.TicketAmount; import com.festago.domain.TicketType; -public record FestivalDetailTicketResponse(Long id, - TicketType ticketType, - Integer totalAmount, - Integer remainAmount) { +public record FestivalDetailTicketResponse( + Long id, + TicketType ticketType, + Integer totalAmount, + Integer remainAmount) { public static FestivalDetailTicketResponse from(Ticket ticket) { TicketAmount ticketAmount = ticket.getTicketAmount(); diff --git a/backend/src/main/java/com/festago/dto/FestivalResponse.java b/backend/src/main/java/com/festago/dto/FestivalResponse.java index 5ff54e98e..17655e7b7 100644 --- a/backend/src/main/java/com/festago/dto/FestivalResponse.java +++ b/backend/src/main/java/com/festago/dto/FestivalResponse.java @@ -3,7 +3,12 @@ import com.festago.domain.Festival; import java.time.LocalDate; -public record FestivalResponse(Long id, String name, LocalDate startDate, LocalDate endDate, String thumbnail) { +public record FestivalResponse( + Long id, + String name, + LocalDate startDate, + LocalDate endDate, + String thumbnail) { public static FestivalResponse from(Festival festival) { return new FestivalResponse( diff --git a/backend/src/main/java/com/festago/dto/FestivalsResponse.java b/backend/src/main/java/com/festago/dto/FestivalsResponse.java index a6c556648..37ddd27bf 100644 --- a/backend/src/main/java/com/festago/dto/FestivalsResponse.java +++ b/backend/src/main/java/com/festago/dto/FestivalsResponse.java @@ -6,7 +6,8 @@ import com.festago.domain.Festival; import java.util.List; -public record FestivalsResponse(List festivals) { +public record FestivalsResponse( + List festivals) { public static FestivalsResponse from(List festivals) { return festivals.stream() diff --git a/backend/src/main/java/com/festago/dto/MemberTicketFestivalResponse.java b/backend/src/main/java/com/festago/dto/MemberTicketFestivalResponse.java index e4cdb01bc..45cdbf0b7 100644 --- a/backend/src/main/java/com/festago/dto/MemberTicketFestivalResponse.java +++ b/backend/src/main/java/com/festago/dto/MemberTicketFestivalResponse.java @@ -2,9 +2,15 @@ import com.festago.domain.Festival; -public record MemberTicketFestivalResponse(Long id, String name, String thumbnail) { +public record MemberTicketFestivalResponse( + Long id, + String name, + String thumbnail) { public static MemberTicketFestivalResponse from(Festival festival) { - return new MemberTicketFestivalResponse(festival.getId(), festival.getName(), festival.getThumbnail()); + return new MemberTicketFestivalResponse( + festival.getId(), + festival.getName(), + festival.getThumbnail()); } } diff --git a/backend/src/main/java/com/festago/dto/MemberTicketResponse.java b/backend/src/main/java/com/festago/dto/MemberTicketResponse.java index 4c6772dcd..f90a1004e 100644 --- a/backend/src/main/java/com/festago/dto/MemberTicketResponse.java +++ b/backend/src/main/java/com/festago/dto/MemberTicketResponse.java @@ -5,13 +5,14 @@ import com.festago.domain.Stage; import java.time.LocalDateTime; -public record MemberTicketResponse(Long id, - Integer number, - LocalDateTime entryTime, - EntryState state, - LocalDateTime reservedAt, - StageResponse stage, - MemberTicketFestivalResponse festival) { +public record MemberTicketResponse( + Long id, + Integer number, + LocalDateTime entryTime, + EntryState state, + LocalDateTime reservedAt, + StageResponse stage, + MemberTicketFestivalResponse festival) { private static final MemberTicketResponse EMPTY = new MemberTicketResponse(-1L, null, null, null, null, null, null); diff --git a/backend/src/main/java/com/festago/dto/MemberTicketsResponse.java b/backend/src/main/java/com/festago/dto/MemberTicketsResponse.java index fb3938c1b..90cd91f58 100644 --- a/backend/src/main/java/com/festago/dto/MemberTicketsResponse.java +++ b/backend/src/main/java/com/festago/dto/MemberTicketsResponse.java @@ -6,7 +6,8 @@ import com.festago.domain.MemberTicket; import java.util.List; -public record MemberTicketsResponse(List memberTickets) { +public record MemberTicketsResponse( + List memberTickets) { public static MemberTicketsResponse from(List memberTickets) { return memberTickets.stream() diff --git a/backend/src/main/java/com/festago/dto/StageCreateRequest.java b/backend/src/main/java/com/festago/dto/StageCreateRequest.java index fb8d94a40..8f46f1afe 100644 --- a/backend/src/main/java/com/festago/dto/StageCreateRequest.java +++ b/backend/src/main/java/com/festago/dto/StageCreateRequest.java @@ -2,9 +2,10 @@ import java.time.LocalDateTime; -public record StageCreateRequest(LocalDateTime startTime, - String lineUp, - LocalDateTime ticketOpenTime, - Long festivalId) { +public record StageCreateRequest( + LocalDateTime startTime, + String lineUp, + LocalDateTime ticketOpenTime, + Long festivalId) { } diff --git a/backend/src/main/java/com/festago/dto/StageResponse.java b/backend/src/main/java/com/festago/dto/StageResponse.java index f4a0bc876..a2d049e99 100644 --- a/backend/src/main/java/com/festago/dto/StageResponse.java +++ b/backend/src/main/java/com/festago/dto/StageResponse.java @@ -3,7 +3,9 @@ import com.festago.domain.Stage; import java.time.LocalDateTime; -public record StageResponse(Long id, LocalDateTime startTime) { +public record StageResponse( + Long id, + LocalDateTime startTime) { public static StageResponse from(Stage stage) { return new StageResponse(stage.getId(), stage.getStartTime()); diff --git a/backend/src/main/java/com/festago/dto/StageTicketResponse.java b/backend/src/main/java/com/festago/dto/StageTicketResponse.java index 51255b276..b525f9a08 100644 --- a/backend/src/main/java/com/festago/dto/StageTicketResponse.java +++ b/backend/src/main/java/com/festago/dto/StageTicketResponse.java @@ -4,10 +4,11 @@ import com.festago.domain.TicketAmount; import com.festago.domain.TicketType; -public record StageTicketResponse(Long id, - TicketType ticketType, - Integer totalAmount, - Integer remainAmount) { +public record StageTicketResponse( + Long id, + TicketType ticketType, + Integer totalAmount, + Integer remainAmount) { public static StageTicketResponse from(Ticket ticket) { TicketAmount ticketAmount = ticket.getTicketAmount(); diff --git a/backend/src/main/java/com/festago/dto/StageTicketsResponse.java b/backend/src/main/java/com/festago/dto/StageTicketsResponse.java index 19814922e..7a184ed02 100644 --- a/backend/src/main/java/com/festago/dto/StageTicketsResponse.java +++ b/backend/src/main/java/com/festago/dto/StageTicketsResponse.java @@ -6,7 +6,8 @@ import com.festago.domain.Ticket; import java.util.List; -public record StageTicketsResponse(List tickets) { +public record StageTicketsResponse( + List tickets) { public static StageTicketsResponse from(List tickets) { return tickets.stream() diff --git a/backend/src/main/java/com/festago/dto/TicketCreateRequest.java b/backend/src/main/java/com/festago/dto/TicketCreateRequest.java index 37f6fb9e0..4a618e6e7 100644 --- a/backend/src/main/java/com/festago/dto/TicketCreateRequest.java +++ b/backend/src/main/java/com/festago/dto/TicketCreateRequest.java @@ -3,6 +3,10 @@ import com.festago.domain.TicketType; import java.time.LocalDateTime; -public record TicketCreateRequest(Long stageId, TicketType ticketType, Integer amount, LocalDateTime entryTime) { +public record TicketCreateRequest( + Long stageId, + TicketType ticketType, + Integer amount, + LocalDateTime entryTime) { } diff --git a/backend/src/main/java/com/festago/dto/TicketCreateResponse.java b/backend/src/main/java/com/festago/dto/TicketCreateResponse.java index ec4cfbc5d..fc06a4450 100644 --- a/backend/src/main/java/com/festago/dto/TicketCreateResponse.java +++ b/backend/src/main/java/com/festago/dto/TicketCreateResponse.java @@ -2,7 +2,8 @@ import com.festago.domain.Ticket; -public record TicketCreateResponse(Long id) { +public record TicketCreateResponse( + Long id) { public static TicketCreateResponse from(Ticket ticket) { return new TicketCreateResponse(ticket.getId()); diff --git a/backend/src/main/java/com/festago/dto/TicketValidationRequest.java b/backend/src/main/java/com/festago/dto/TicketValidationRequest.java index f98f8de2e..34d6a1514 100644 --- a/backend/src/main/java/com/festago/dto/TicketValidationRequest.java +++ b/backend/src/main/java/com/festago/dto/TicketValidationRequest.java @@ -1,5 +1,6 @@ package com.festago.dto; -public record TicketValidationRequest(String code) { +public record TicketValidationRequest( + String code) { } diff --git a/backend/src/main/java/com/festago/dto/TicketValidationResponse.java b/backend/src/main/java/com/festago/dto/TicketValidationResponse.java index 7e5a5422c..5ce421d09 100644 --- a/backend/src/main/java/com/festago/dto/TicketValidationResponse.java +++ b/backend/src/main/java/com/festago/dto/TicketValidationResponse.java @@ -3,7 +3,8 @@ import com.festago.domain.EntryState; import com.festago.domain.MemberTicket; -public record TicketValidationResponse(EntryState updatedState) { +public record TicketValidationResponse( + EntryState updatedState) { public static TicketValidationResponse from(MemberTicket memberTicket) { return new TicketValidationResponse(memberTicket.getEntryState()); diff --git a/backend/src/main/java/com/festago/dto/TicketingRequest.java b/backend/src/main/java/com/festago/dto/TicketingRequest.java index 048039f0f..faae025fd 100644 --- a/backend/src/main/java/com/festago/dto/TicketingRequest.java +++ b/backend/src/main/java/com/festago/dto/TicketingRequest.java @@ -1,5 +1,6 @@ package com.festago.dto; -public record TicketingRequest(Long ticketId) { +public record TicketingRequest( + Long ticketId) { } diff --git a/backend/src/main/java/com/festago/dto/TicketingResponse.java b/backend/src/main/java/com/festago/dto/TicketingResponse.java index d0e395c6e..0dd10b058 100644 --- a/backend/src/main/java/com/festago/dto/TicketingResponse.java +++ b/backend/src/main/java/com/festago/dto/TicketingResponse.java @@ -3,9 +3,10 @@ import com.festago.domain.MemberTicket; import java.time.LocalDateTime; -public record TicketingResponse(Long id, - Integer number, - LocalDateTime entryTime) { +public record TicketingResponse( + Long id, + Integer number, + LocalDateTime entryTime) { public static TicketingResponse from(MemberTicket memberTicket) { return new TicketingResponse( From ba9b4a9e167451751e6df3376c2a950325252def Mon Sep 17 00:00:00 2001 From: xxeol2 Date: Mon, 11 Sep 2023 17:43:07 +0900 Subject: [PATCH 18/74] =?UTF-8?q?[BE]=20feat:=20=ED=95=99=EA=B5=90=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#431)=20(#432)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: School 목록 조회 기능 구현 * feat: School 목록 조회 API 구현 * feat: Transactional(readonly=true) 적용 --- .../festago/application/SchoolService.java | 22 +++++++ .../java/com/festago/dto/SchoolResponse.java | 17 ++++++ .../java/com/festago/dto/SchoolsResponse.java | 17 ++++++ .../presentation/SchoolController.java | 24 ++++++++ .../presentation/SchoolControllerTest.java | 61 +++++++++++++++++++ 5 files changed, 141 insertions(+) create mode 100644 backend/src/main/java/com/festago/application/SchoolService.java create mode 100644 backend/src/main/java/com/festago/dto/SchoolResponse.java create mode 100644 backend/src/main/java/com/festago/dto/SchoolsResponse.java create mode 100644 backend/src/main/java/com/festago/presentation/SchoolController.java create mode 100644 backend/src/test/java/com/festago/presentation/SchoolControllerTest.java diff --git a/backend/src/main/java/com/festago/application/SchoolService.java b/backend/src/main/java/com/festago/application/SchoolService.java new file mode 100644 index 000000000..edb571b4a --- /dev/null +++ b/backend/src/main/java/com/festago/application/SchoolService.java @@ -0,0 +1,22 @@ +package com.festago.application; + +import com.festago.domain.SchoolRepository; +import com.festago.dto.SchoolsResponse; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class SchoolService { + + private final SchoolRepository schoolRepository; + + public SchoolService(SchoolRepository schoolRepository) { + this.schoolRepository = schoolRepository; + } + + @Transactional(readOnly = true) + public SchoolsResponse findAll() { + return SchoolsResponse.from(schoolRepository.findAll()); + } +} diff --git a/backend/src/main/java/com/festago/dto/SchoolResponse.java b/backend/src/main/java/com/festago/dto/SchoolResponse.java new file mode 100644 index 000000000..a33a104db --- /dev/null +++ b/backend/src/main/java/com/festago/dto/SchoolResponse.java @@ -0,0 +1,17 @@ +package com.festago.dto; + +import com.festago.domain.School; + +public record SchoolResponse( + Long id, + String domain, + String name) { + + public static SchoolResponse from(School school) { + return new SchoolResponse( + school.getId(), + school.getDomain(), + school.getName() + ); + } +} diff --git a/backend/src/main/java/com/festago/dto/SchoolsResponse.java b/backend/src/main/java/com/festago/dto/SchoolsResponse.java new file mode 100644 index 000000000..f92e33f9e --- /dev/null +++ b/backend/src/main/java/com/festago/dto/SchoolsResponse.java @@ -0,0 +1,17 @@ +package com.festago.dto; + +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.toList; + +import com.festago.domain.School; +import java.util.List; + +public record SchoolsResponse( + List schools) { + + public static SchoolsResponse from(List schools) { + return schools.stream() + .map(SchoolResponse::from) + .collect(collectingAndThen(toList(), SchoolsResponse::new)); + } +} diff --git a/backend/src/main/java/com/festago/presentation/SchoolController.java b/backend/src/main/java/com/festago/presentation/SchoolController.java new file mode 100644 index 000000000..4f942e162 --- /dev/null +++ b/backend/src/main/java/com/festago/presentation/SchoolController.java @@ -0,0 +1,24 @@ +package com.festago.presentation; + +import com.festago.application.SchoolService; +import com.festago.dto.SchoolsResponse; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/schools") +public class SchoolController { + + private final SchoolService schoolService; + + public SchoolController(SchoolService schoolService) { + this.schoolService = schoolService; + } + + @GetMapping + public ResponseEntity findAll() { + return ResponseEntity.ok(schoolService.findAll()); + } +} diff --git a/backend/src/test/java/com/festago/presentation/SchoolControllerTest.java b/backend/src/test/java/com/festago/presentation/SchoolControllerTest.java new file mode 100644 index 000000000..f9584d02c --- /dev/null +++ b/backend/src/test/java/com/festago/presentation/SchoolControllerTest.java @@ -0,0 +1,61 @@ +package com.festago.presentation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.festago.application.SchoolService; +import com.festago.dto.SchoolResponse; +import com.festago.dto.SchoolsResponse; +import com.festago.support.CustomWebMvcTest; +import java.nio.charset.StandardCharsets; +import java.util.List; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +@CustomWebMvcTest(SchoolController.class) +@DisplayNameGeneration(ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class SchoolControllerTest { + + @Autowired + MockMvc mockMvc; + + @Autowired + ObjectMapper objectMapper; + + @MockBean + SchoolService schoolService; + + @Test + void 모든_학교_정보_조회() throws Exception { + // given + SchoolsResponse expected = new SchoolsResponse( + List.of( + new SchoolResponse(1L, "pooh.ac.kr", "푸우대학"), + new SchoolResponse(2L, "ash.ac.kr", "애쉬대학") + )); + + given(schoolService.findAll()) + .willReturn(expected); + + // when & then + String content = mockMvc.perform(get("/schools") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andDo(print()) + .andReturn() + .getResponse() + .getContentAsString(StandardCharsets.UTF_8); + SchoolsResponse actual = objectMapper.readValue(content, SchoolsResponse.class); + assertThat(actual).isEqualTo(expected); + } +} From f0c7e76278a1f36c660a95247876b56303ec6862 Mon Sep 17 00:00:00 2001 From: xxeol2 Date: Mon, 11 Sep 2023 17:47:21 +0900 Subject: [PATCH 19/74] =?UTF-8?q?[BE]=20refactor:=20Oauth2=20=EB=84=A4?= =?UTF-8?q?=ED=8A=B8=EC=9B=8C=ED=81=AC=20=ED=86=B5=EC=8B=A0=EC=9D=84=20Tra?= =?UTF-8?q?nsaction=20=EB=B2=94=EC=9C=84=20=EB=B0=96=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20(#435)=20(#436)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Oauth2 네트워크 통신 트랜잭션 범위 밖으로 분리 * refactor: accessToken 생성 로직 Transaction 범위 밖으로 분리 * refactor: @Mock 어노테이션 활용 * refactor: Facade 패턴 적용 * refactor: DTO 정적 팩토리 메서드 정의 * refactor: LoginMemberDto에 Member객체가 아닌 필드를 담도록 수정 --- .../auth/application/AuthFacadeService.java | 46 ++++++++ .../festago/auth/application/AuthService.java | 31 +----- .../com/festago/auth/dto/LoginMemberDto.java | 18 +++ .../com/festago/auth/dto/LoginResponse.java | 8 +- .../auth/presentation/AuthController.java | 12 +- ...t.java => AdminAuthFacadeServiceTest.java} | 2 +- .../application/AuthFacadeServiceTest.java | 69 ++++++++++++ .../auth/application/AuthServiceTest.java | 104 ++++++++---------- ... => AuthFacadeServiceIntegrationTest.java} | 14 +-- .../auth/presentation/AuthControllerTest.java | 6 +- 10 files changed, 203 insertions(+), 107 deletions(-) create mode 100644 backend/src/main/java/com/festago/auth/application/AuthFacadeService.java create mode 100644 backend/src/main/java/com/festago/auth/dto/LoginMemberDto.java rename backend/src/test/java/com/festago/auth/application/{AdminAuthServiceTest.java => AdminAuthFacadeServiceTest.java} (99%) create mode 100644 backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java rename backend/src/test/java/com/festago/auth/application/integration/{AuthServiceIntegrationTest.java => AuthFacadeServiceIntegrationTest.java} (87%) diff --git a/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java b/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java new file mode 100644 index 000000000..7f9373f7f --- /dev/null +++ b/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java @@ -0,0 +1,46 @@ +package com.festago.auth.application; + +import com.festago.auth.domain.AuthPayload; +import com.festago.auth.domain.AuthProvider; +import com.festago.auth.domain.OAuth2Client; +import com.festago.auth.domain.OAuth2Clients; +import com.festago.auth.domain.Role; +import com.festago.auth.domain.UserInfo; +import com.festago.auth.dto.LoginMemberDto; +import com.festago.auth.dto.LoginRequest; +import com.festago.auth.dto.LoginResponse; +import org.springframework.stereotype.Service; + +@Service +public class AuthFacadeService { + + private final AuthService authService; + private final OAuth2Clients oAuth2Clients; + private final AuthProvider authProvider; + + public AuthFacadeService(AuthService authService, OAuth2Clients oAuth2Clients, + AuthProvider authProvider) { + this.authService = authService; + this.oAuth2Clients = oAuth2Clients; + this.authProvider = authProvider; + } + + public LoginResponse login(LoginRequest request) { + LoginMemberDto loginMember = authService.login(getUserInfo(request)); + String accessToken = getAccessToken(loginMember.memberId()); + return LoginResponse.of(accessToken, loginMember); + } + + private String getAccessToken(Long memberId) { + return authProvider.provide(new AuthPayload(memberId, Role.MEMBER)); + } + + private UserInfo getUserInfo(LoginRequest request) { + OAuth2Client oAuth2Client = oAuth2Clients.getClient(request.socialType()); + return oAuth2Client.getUserInfo(request.accessToken()); + } + + public void deleteMember(Long memberId) { + authService.deleteMember(memberId); + } +} diff --git a/backend/src/main/java/com/festago/auth/application/AuthService.java b/backend/src/main/java/com/festago/auth/application/AuthService.java index 8668782c8..7f6881a27 100644 --- a/backend/src/main/java/com/festago/auth/application/AuthService.java +++ b/backend/src/main/java/com/festago/auth/application/AuthService.java @@ -1,13 +1,7 @@ package com.festago.auth.application; -import com.festago.auth.domain.AuthPayload; -import com.festago.auth.domain.AuthProvider; -import com.festago.auth.domain.OAuth2Client; -import com.festago.auth.domain.OAuth2Clients; -import com.festago.auth.domain.Role; import com.festago.auth.domain.UserInfo; -import com.festago.auth.dto.LoginRequest; -import com.festago.auth.dto.LoginResponse; +import com.festago.auth.dto.LoginMemberDto; import com.festago.domain.Member; import com.festago.domain.MemberRepository; import com.festago.exception.ErrorCode; @@ -20,35 +14,20 @@ public class AuthService { private final MemberRepository memberRepository; - private final OAuth2Clients oAuth2Clients; - private final AuthProvider authProvider; - public AuthService(MemberRepository memberRepository, OAuth2Clients oAuth2Clients, - AuthProvider authProvider) { + public AuthService(MemberRepository memberRepository) { this.memberRepository = memberRepository; - this.oAuth2Clients = oAuth2Clients; - this.authProvider = authProvider; } - public LoginResponse login(LoginRequest request) { - UserInfo userInfo = getUserInfo(request); + public LoginMemberDto login(UserInfo userInfo) { return memberRepository.findBySocialIdAndSocialType(userInfo.socialId(), userInfo.socialType()) - .map(member -> LoginResponse.isExists(getAccessToken(member), member.getNickname())) + .map(LoginMemberDto::isExists) .orElseGet(() -> { Member member = signUp(userInfo); - return LoginResponse.isNew(getAccessToken(member), member.getNickname()); + return LoginMemberDto.isNew(member); }); } - private UserInfo getUserInfo(LoginRequest request) { - OAuth2Client oAuth2Client = oAuth2Clients.getClient(request.socialType()); - return oAuth2Client.getUserInfo(request.accessToken()); - } - - private String getAccessToken(Member member) { - return authProvider.provide(new AuthPayload(member.getId(), Role.MEMBER)); - } - private Member signUp(UserInfo userInfo) { return memberRepository.save(userInfo.toMember()); } diff --git a/backend/src/main/java/com/festago/auth/dto/LoginMemberDto.java b/backend/src/main/java/com/festago/auth/dto/LoginMemberDto.java new file mode 100644 index 000000000..f331449ab --- /dev/null +++ b/backend/src/main/java/com/festago/auth/dto/LoginMemberDto.java @@ -0,0 +1,18 @@ +package com.festago.auth.dto; + +import com.festago.domain.Member; + +public record LoginMemberDto( + boolean isNew, + Long memberId, + String nickname +) { + + public static LoginMemberDto isNew(Member member) { + return new LoginMemberDto(true, member.getId(), member.getNickname()); + } + + public static LoginMemberDto isExists(Member member) { + return new LoginMemberDto(false, member.getId(), member.getNickname()); + } +} diff --git a/backend/src/main/java/com/festago/auth/dto/LoginResponse.java b/backend/src/main/java/com/festago/auth/dto/LoginResponse.java index 00acc78cf..7ae5a060a 100644 --- a/backend/src/main/java/com/festago/auth/dto/LoginResponse.java +++ b/backend/src/main/java/com/festago/auth/dto/LoginResponse.java @@ -6,11 +6,7 @@ public record LoginResponse( boolean isNew ) { - public static LoginResponse isNew(String accessToken, String nickname) { - return new LoginResponse(accessToken, nickname, true); - } - - public static LoginResponse isExists(String accessToken, String nickname) { - return new LoginResponse(accessToken, nickname, false); + public static LoginResponse of(String accessToken, LoginMemberDto loginMember) { + return new LoginResponse(accessToken, loginMember.nickname(), loginMember.isNew()); } } diff --git a/backend/src/main/java/com/festago/auth/presentation/AuthController.java b/backend/src/main/java/com/festago/auth/presentation/AuthController.java index 65d81bb1a..e703f4197 100644 --- a/backend/src/main/java/com/festago/auth/presentation/AuthController.java +++ b/backend/src/main/java/com/festago/auth/presentation/AuthController.java @@ -1,7 +1,7 @@ package com.festago.auth.presentation; import com.festago.auth.annotation.Member; -import com.festago.auth.application.AuthService; +import com.festago.auth.application.AuthFacadeService; import com.festago.auth.dto.LoginRequest; import com.festago.auth.dto.LoginResponse; import io.swagger.v3.oas.annotations.Operation; @@ -19,16 +19,16 @@ @Tag(name = "로그인 관련 요청") public class AuthController { - private final AuthService authService; + private final AuthFacadeService authFacadeService; - public AuthController(AuthService authService) { - this.authService = authService; + public AuthController(AuthFacadeService authFacadeService) { + this.authFacadeService = authFacadeService; } @PostMapping("/oauth2") @Operation(description = "소셜 엑세스 토큰을 기반으로 로그인 요청을 보낸다.", summary = "OAuth2 로그인") public ResponseEntity login(@RequestBody LoginRequest request) { - LoginResponse response = authService.login(request); + LoginResponse response = authFacadeService.login(request); return ResponseEntity.ok() .body(response); } @@ -37,7 +37,7 @@ public ResponseEntity login(@RequestBody LoginRequest request) { @SecurityRequirement(name = "bearerAuth") @Operation(description = "회원 탈퇴 요청을 보낸다.", summary = "유저 회원 탈퇴") public ResponseEntity deleteMember(@Member Long memberId) { - authService.deleteMember(memberId); + authFacadeService.deleteMember(memberId); return ResponseEntity.ok() .build(); } diff --git a/backend/src/test/java/com/festago/auth/application/AdminAuthServiceTest.java b/backend/src/test/java/com/festago/auth/application/AdminAuthFacadeServiceTest.java similarity index 99% rename from backend/src/test/java/com/festago/auth/application/AdminAuthServiceTest.java rename to backend/src/test/java/com/festago/auth/application/AdminAuthFacadeServiceTest.java index 6bc83d7e1..99f798a1f 100644 --- a/backend/src/test/java/com/festago/auth/application/AdminAuthServiceTest.java +++ b/backend/src/test/java/com/festago/auth/application/AdminAuthFacadeServiceTest.java @@ -29,7 +29,7 @@ @DisplayNameGeneration(ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") @ExtendWith(MockitoExtension.class) -class AdminAuthServiceTest { +class AdminAuthFacadeServiceTest { @Mock AuthProvider authProvider; diff --git a/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java b/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java new file mode 100644 index 000000000..5c56d1322 --- /dev/null +++ b/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java @@ -0,0 +1,69 @@ +package com.festago.auth.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.mock; + +import com.festago.auth.domain.AuthPayload; +import com.festago.auth.domain.AuthProvider; +import com.festago.auth.domain.OAuth2Clients; +import com.festago.auth.domain.SocialType; +import com.festago.auth.domain.UserInfo; +import com.festago.auth.dto.LoginMemberDto; +import com.festago.auth.dto.LoginRequest; +import com.festago.auth.dto.LoginResponse; +import com.festago.auth.infrastructure.FestagoOAuth2Client; +import com.festago.domain.Member; +import com.festago.support.MemberFixture; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@DisplayNameGeneration(ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +@ExtendWith(MockitoExtension.class) +class AuthFacadeServiceTest { + + AuthFacadeService authFacadeService; + + AuthService authService; + + AuthProvider authProvider; + + @BeforeEach + void setUp() { + authService = mock(AuthService.class); + OAuth2Clients oAuth2Clients = OAuth2Clients.builder() + .add(new FestagoOAuth2Client()) + .build(); + authProvider = mock(AuthProvider.class); + + authFacadeService = new AuthFacadeService(authService, oAuth2Clients, authProvider); + } + + @Test + void 로그인() { + LoginRequest request = new LoginRequest(SocialType.FESTAGO, "1"); + + Member member = MemberFixture.member() + .id(1L) + .build(); + + given(authProvider.provide(any(AuthPayload.class))) + .willReturn("Bearer token"); + + given(authService.login(any(UserInfo.class))) + .willReturn(new LoginMemberDto(false, member.getId(), member.getNickname())); + + // when + LoginResponse response = authFacadeService.login(request); + + // then + assertThat(response) + .isNotNull(); + } +} diff --git a/backend/src/test/java/com/festago/auth/application/AuthServiceTest.java b/backend/src/test/java/com/festago/auth/application/AuthServiceTest.java index 09fb6f912..c6a0fedc3 100644 --- a/backend/src/test/java/com/festago/auth/application/AuthServiceTest.java +++ b/backend/src/test/java/com/festago/auth/application/AuthServiceTest.java @@ -6,26 +6,22 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.mock; -import com.festago.auth.domain.AuthPayload; -import com.festago.auth.domain.AuthProvider; -import com.festago.auth.domain.OAuth2Clients; import com.festago.auth.domain.SocialType; -import com.festago.auth.dto.LoginRequest; -import com.festago.auth.dto.LoginResponse; -import com.festago.auth.infrastructure.FestagoOAuth2Client; +import com.festago.auth.domain.UserInfo; +import com.festago.auth.dto.LoginMemberDto; import com.festago.domain.Member; import com.festago.domain.MemberRepository; import com.festago.exception.NotFoundException; import com.festago.support.MemberFixture; import java.util.Optional; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @DisplayNameGeneration(ReplaceUnderscores.class) @@ -33,62 +29,54 @@ @ExtendWith(MockitoExtension.class) class AuthServiceTest { + @Mock MemberRepository memberRepository; - AuthProvider authProvider; - + @InjectMocks AuthService authService; - @BeforeEach - void setUp() { - memberRepository = mock(MemberRepository.class); - OAuth2Clients oAuth2Clients = OAuth2Clients.builder() - .add(new FestagoOAuth2Client()) - .build(); - authProvider = mock(AuthProvider.class); - authService = new AuthService(memberRepository, oAuth2Clients, authProvider); - } + @Nested + class 로그인 { - @Test - void 신규_회원으로_로그인() { - // given - Member member = MemberFixture.member() - .id(1L) - .build(); - given(memberRepository.findBySocialIdAndSocialType(anyString(), any(SocialType.class))) - .willReturn(Optional.empty()); - given(memberRepository.save(any(Member.class))) - .willReturn(member); - given(authProvider.provide(any(AuthPayload.class))) - .willReturn("Bearer token"); - LoginRequest request = new LoginRequest(SocialType.FESTAGO, "1"); - - // when - LoginResponse response = authService.login(request); - - // then - assertThat(response.isNew()) - .isTrue(); - } + @Test + void 신규_회원으로_로그인() { + // given + Member member = MemberFixture.member() + .id(1L) + .build(); + given(memberRepository.findBySocialIdAndSocialType(anyString(), any(SocialType.class))) + .willReturn(Optional.empty()); + given(memberRepository.save(any(Member.class))) + .willReturn(member); + UserInfo userInfo = new UserInfo(member.getSocialId(), member.getSocialType(), member.getNickname(), + member.getProfileImage()); + + // when + LoginMemberDto response = authService.login(userInfo); + + // then + assertThat(response.isNew()) + .isTrue(); + } - @Test - void 기존_회원으로_로그인() { - // given - Member member = MemberFixture.member() - .id(1L) - .build(); - given(memberRepository.findBySocialIdAndSocialType(anyString(), any(SocialType.class))) - .willReturn(Optional.of(member)); - given(authProvider.provide(any(AuthPayload.class))) - .willReturn("Bearer token"); - LoginRequest request = new LoginRequest(SocialType.FESTAGO, "1"); - - // when - LoginResponse response = authService.login(request); - - // then - assertThat(response.isNew()) - .isFalse(); + @Test + void 기존_회원으로_로그인() { + // given + Member member = MemberFixture.member() + .id(1L) + .build(); + given(memberRepository.findBySocialIdAndSocialType(anyString(), any(SocialType.class))) + .willReturn(Optional.of(member)); + UserInfo userInfo = new UserInfo(member.getSocialId(), member.getSocialType(), member.getNickname(), + member.getProfileImage()); + + // when + LoginMemberDto response = authService.login(userInfo); + + // then + assertThat(response.isNew()) + .isFalse(); + } } @Nested diff --git a/backend/src/test/java/com/festago/auth/application/integration/AuthServiceIntegrationTest.java b/backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java similarity index 87% rename from backend/src/test/java/com/festago/auth/application/integration/AuthServiceIntegrationTest.java rename to backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java index 2511fb247..1be92b665 100644 --- a/backend/src/test/java/com/festago/auth/application/integration/AuthServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java @@ -4,7 +4,7 @@ import static org.assertj.core.api.SoftAssertions.assertSoftly; import com.festago.application.integration.ApplicationIntegrationTest; -import com.festago.auth.application.AuthService; +import com.festago.auth.application.AuthFacadeService; import com.festago.auth.domain.SocialType; import com.festago.auth.dto.LoginRequest; import com.festago.domain.Member; @@ -19,13 +19,13 @@ @DisplayNameGeneration(ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") -class AuthServiceIntegrationTest extends ApplicationIntegrationTest { +class AuthFacadeServiceIntegrationTest extends ApplicationIntegrationTest { @Autowired MemberRepository memberRepository; @Autowired - AuthService authService; + AuthFacadeService authFacadeService; @Autowired EntityManager entityManager; @@ -34,12 +34,12 @@ class AuthServiceIntegrationTest extends ApplicationIntegrationTest { void 회원이_탈퇴하고_재가입하면_새로운_계정으로_가입() { // given LoginRequest request = new LoginRequest(SocialType.FESTAGO, "1"); - authService.login(request); + authFacadeService.login(request); Member member = memberRepository.findBySocialIdAndSocialType("1", SocialType.FESTAGO).get(); // when memberRepository.delete(member); - authService.login(request); + authFacadeService.login(request); // then assertThat(memberRepository.count()).isEqualTo(1); @@ -51,7 +51,7 @@ class AuthServiceIntegrationTest extends ApplicationIntegrationTest { Member member = memberRepository.save(MemberFixture.member().build()); // when - authService.deleteMember(member.getId()); + authFacadeService.deleteMember(member.getId()); // then String sql = "SELECT * FROM member WHERE id = :memberId AND deleted_at IS NOT NULL"; @@ -75,7 +75,7 @@ class AuthServiceIntegrationTest extends ApplicationIntegrationTest { Member member = memberRepository.save(MemberFixture.member().build()); // when - authService.deleteMember(member.getId()); + authFacadeService.deleteMember(member.getId()); // then assertThat(memberRepository.findById(member.getId())).isEmpty(); diff --git a/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java b/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java index 738b648fb..663251e38 100644 --- a/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java +++ b/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java @@ -9,7 +9,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.auth.application.AuthService; +import com.festago.auth.application.AuthFacadeService; import com.festago.auth.domain.Role; import com.festago.auth.domain.SocialType; import com.festago.auth.dto.LoginRequest; @@ -36,13 +36,13 @@ class AuthControllerTest { ObjectMapper objectMapper; @MockBean - AuthService authService; + AuthFacadeService authFacadeService; @Test void OAuth2_로그인을_한다() throws Exception { // given LoginResponse expected = new LoginResponse("accesstoken", "nickname", true); - given(authService.login(any(LoginRequest.class))) + given(authFacadeService.login(any(LoginRequest.class))) .willReturn(expected); LoginRequest request = new LoginRequest(SocialType.FESTAGO, "code"); From 22c62971602db9d0e11e0a7c509188d20f9d6f88 Mon Sep 17 00:00:00 2001 From: seokjin8678 Date: Thu, 14 Sep 2023 10:53:24 +0900 Subject: [PATCH 20/74] =?UTF-8?q?[BE]=20refactor:=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=ED=98=95=EC=8B=9D=20Level=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=9D=BC=20=EA=B5=AC=EB=B6=84=20=EB=B0=8F=20Id?= =?UTF-8?q?=EC=99=80=20Role=20=EC=B6=94=EA=B0=80=20(#396)=20(#397)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 테스트용 info 에러 핸들러 추가 * refactor: ErrorLogger 의존성 주입 제거, Level에 따른 로그 구분 * refactor: ErrorLogger 삭제 * refactor: ErrorLogger Bean으로 등록 --- .../com/festago/aop/LogRequestBodyAspect.java | 22 ++++-- .../com/festago/auth/config/LoginConfig.java | 6 -- .../com/festago/config/ErrorLoggerConfig.java | 15 ++++ .../festago/presentation/AdminController.java | 8 +- .../com/festago/presentation/ErrorLogger.java | 33 -------- .../presentation/GlobalExceptionHandler.java | 75 +++++++++++++------ .../com/festago/support/CustomWebMvcTest.java | 3 +- 7 files changed, 91 insertions(+), 71 deletions(-) create mode 100644 backend/src/main/java/com/festago/config/ErrorLoggerConfig.java delete mode 100644 backend/src/main/java/com/festago/presentation/ErrorLogger.java diff --git a/backend/src/main/java/com/festago/aop/LogRequestBodyAspect.java b/backend/src/main/java/com/festago/aop/LogRequestBodyAspect.java index c596d21cd..ebb553e4c 100644 --- a/backend/src/main/java/com/festago/aop/LogRequestBodyAspect.java +++ b/backend/src/main/java/com/festago/aop/LogRequestBodyAspect.java @@ -3,15 +3,18 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.festago.exception.ErrorCode; import com.festago.exception.InternalServerException; -import com.festago.presentation.ErrorLogger; import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.lang.reflect.Method; +import java.util.EnumMap; +import java.util.Map; import java.util.Objects; +import java.util.function.BiConsumer; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; import org.slf4j.event.Level; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; @@ -24,14 +27,18 @@ public class LogRequestBodyAspect { private static final long MAX_CONTENT_LENGTH = 1024; - private static final String LOG_FORMAT = "[REQUEST BODY]\n{}"; + private static final String LOG_FORMAT = "\n[REQUEST BODY]\n{}"; - private final ErrorLogger errorLogger; + private final Map> loggerMap = new EnumMap<>(Level.class); private final ObjectMapper objectMapper; + private final Logger errorLogger; - public LogRequestBodyAspect(ErrorLogger errorLogger, ObjectMapper objectMapper) { - this.errorLogger = errorLogger; + public LogRequestBodyAspect(ObjectMapper objectMapper, Logger errorLogger) { this.objectMapper = objectMapper; + this.errorLogger = errorLogger; + loggerMap.put(Level.INFO, this.errorLogger::info); + loggerMap.put(Level.WARN, this.errorLogger::warn); + loggerMap.put(Level.ERROR, this.errorLogger::error); } @Around("@annotation(LogRequestBody)") @@ -69,8 +76,9 @@ private boolean validateRequest(HttpServletRequest request) { } private void log(Level level, HttpServletRequest request) { - errorLogger.get(level) - .log(LOG_FORMAT, getRequestPayload(request)); + loggerMap.getOrDefault(level, (ignore1, ignore2) -> { + }) + .accept(LOG_FORMAT, getRequestPayload(request)); } private String getRequestPayload(HttpServletRequest request) { diff --git a/backend/src/main/java/com/festago/auth/config/LoginConfig.java b/backend/src/main/java/com/festago/auth/config/LoginConfig.java index 2c29c060f..1c0c755be 100644 --- a/backend/src/main/java/com/festago/auth/config/LoginConfig.java +++ b/backend/src/main/java/com/festago/auth/config/LoginConfig.java @@ -7,7 +7,6 @@ import com.festago.auth.presentation.AuthInterceptor; import com.festago.auth.presentation.AuthenticateContext; import com.festago.auth.presentation.RoleArgumentResolver; -import com.festago.presentation.ErrorLogger; import java.util.List; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -61,9 +60,4 @@ public AuthInterceptor memberAuthInterceptor() { .role(Role.MEMBER) .build(); } - - @Bean - public ErrorLogger errorLogger() { - return new ErrorLogger(); - } } diff --git a/backend/src/main/java/com/festago/config/ErrorLoggerConfig.java b/backend/src/main/java/com/festago/config/ErrorLoggerConfig.java new file mode 100644 index 000000000..d0ec785df --- /dev/null +++ b/backend/src/main/java/com/festago/config/ErrorLoggerConfig.java @@ -0,0 +1,15 @@ +package com.festago.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ErrorLoggerConfig { + + @Bean + public Logger errorLogger() { + return LoggerFactory.getLogger("ErrorLogger"); + } +} diff --git a/backend/src/main/java/com/festago/presentation/AdminController.java b/backend/src/main/java/com/festago/presentation/AdminController.java index 1d58abbbf..801dc3062 100644 --- a/backend/src/main/java/com/festago/presentation/AdminController.java +++ b/backend/src/main/java/com/festago/presentation/AdminController.java @@ -17,10 +17,11 @@ import com.festago.dto.StageResponse; import com.festago.dto.TicketCreateRequest; import com.festago.dto.TicketCreateResponse; +import com.festago.exception.BadRequestException; import com.festago.exception.ErrorCode; import com.festago.exception.InternalServerException; -import io.swagger.v3.oas.annotations.Hidden; import com.festago.exception.UnauthorizedException; +import io.swagger.v3.oas.annotations.Hidden; import jakarta.servlet.http.HttpServletResponse; import java.time.LocalDateTime; import java.time.ZoneId; @@ -133,6 +134,11 @@ public ResponseEntity getWarn() { throw new InternalServerException(ErrorCode.FOR_TEST_ERROR); } + @GetMapping("/info") + public ResponseEntity getInfo() { + throw new BadRequestException(ErrorCode.FOR_TEST_ERROR); + } + @PostMapping("/initialize") public ResponseEntity initializeRootAdmin(@RequestBody RootAdminInitializeRequest request) { adminAuthService.initializeRootAdmin(request.password()); diff --git a/backend/src/main/java/com/festago/presentation/ErrorLogger.java b/backend/src/main/java/com/festago/presentation/ErrorLogger.java deleted file mode 100644 index cb7a285ea..000000000 --- a/backend/src/main/java/com/festago/presentation/ErrorLogger.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.festago.presentation; - -import java.util.EnumMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.event.Level; - -public class ErrorLogger { - - private static final Logger errorLogger = LoggerFactory.getLogger("ErrorLogger"); - - private final EnumMap logFunctions = new EnumMap<>(Level.class); - - public ErrorLogger() { - this.logFunctions.put(Level.INFO, errorLogger::info); - this.logFunctions.put(Level.WARN, errorLogger::warn); - this.logFunctions.put(Level.ERROR, errorLogger::error); - } - - public LogFunction get(Level level) { - return logFunctions.get(level); - } - - public boolean isEnabledForLevel(Level level) { - return errorLogger.isEnabledForLevel(level); - } - - @FunctionalInterface - public interface LogFunction { - - void log(String format, Object... arguments); - } -} diff --git a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java index 9dc49d206..d7579566f 100644 --- a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java +++ b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java @@ -1,5 +1,6 @@ package com.festago.presentation; +import com.festago.auth.presentation.AuthenticateContext; import com.festago.dto.ErrorResponse; import com.festago.exception.BadRequestException; import com.festago.exception.ErrorCode; @@ -9,7 +10,7 @@ import com.festago.exception.NotFoundException; import com.festago.exception.UnauthorizedException; import jakarta.servlet.http.HttpServletRequest; -import org.slf4j.event.Level; +import org.slf4j.Logger; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -19,71 +20,99 @@ @RestControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { - private static final String LOG_FORMAT_ERROR_CODE = "\n[🚨ERROR] - ({} {})\n{}"; - private static final String LOG_FORMAT = "\n[🚨ERROR] - ({} {})"; + private static final String LOG_FORMAT_INFO = "\n[🔵INFO] - ({} {})\n(id: {}, role: {})\n{}\n {}: {}"; + private static final String LOG_FORMAT_WARN = "\n[🟠WARN] - ({} {})\n(id: {}, role: {})\n{}"; + private static final String LOG_FORMAT_ERROR = "\n[🔴ERROR] - ({} {})\n(id: {}, role: {})"; + // INFO /* - [🚨ERROR] - (POST /admin/warn) + [🔵INFO] - (POST /admin/info) + (id: 1, role: MEMBER) FOR_TEST_ERROR - com.festago.exception.InternalServerException: 테스트용 에러입니다. + com.festago.exception.BadRequestException: 테스트용 에러입니다. */ - private final ErrorLogger errorLogger; + // WARN + /* + [🟠WARN] - (POST /admin/warn) + (id: 1, role: MEMBER) + FOR_TEST_ERROR + com.festago.exception.InternalServerException: 테스트용 에러입니다. + at com.festago.presentation.AdminController.getWarn(AdminController.java:134) + */ + + // ERROR + /* + [🔴ERROR] - (POST /admin/error) + (id: 1, role: MEMBER) + java.lang.IllegalArgumentException: 테스트용 에러입니다. + at com.festago.presentation.AdminController.getError(AdminController.java:129) + */ + + private final AuthenticateContext authenticateContext; + private final Logger errorLogger; - public GlobalExceptionHandler(ErrorLogger errorLogger) { + public GlobalExceptionHandler(AuthenticateContext authenticateContext, Logger errorLogger) { + this.authenticateContext = authenticateContext; this.errorLogger = errorLogger; } @ExceptionHandler(BadRequestException.class) public ResponseEntity handle(BadRequestException e, HttpServletRequest request) { - log(Level.INFO, e, request); + logInfo(e, request); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ErrorResponse.from(e)); } @ExceptionHandler(UnauthorizedException.class) public ResponseEntity handle(UnauthorizedException e, HttpServletRequest request) { - log(Level.INFO, e, request); + logInfo(e, request); return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ErrorResponse.from(e)); } @ExceptionHandler(ForbiddenException.class) public ResponseEntity handle(ForbiddenException e, HttpServletRequest request) { - log(Level.INFO, e, request); + logInfo(e, request); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ErrorResponse.from(e)); } @ExceptionHandler(NotFoundException.class) public ResponseEntity handle(NotFoundException e, HttpServletRequest request) { - log(Level.INFO, e, request); + logInfo(e, request); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ErrorResponse.from(e)); } @ExceptionHandler(InternalServerException.class) public ResponseEntity handle(InternalServerException e, HttpServletRequest request) { - log(Level.WARN, e, request); + logWarn(e, request); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(ErrorResponse.from(ErrorCode.INTERNAL_SERVER_ERROR)); } @ExceptionHandler(Exception.class) public ResponseEntity handle(Exception e, HttpServletRequest request) { - log(Level.ERROR, e, request); + logError(e, request); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(ErrorResponse.from(ErrorCode.INTERNAL_SERVER_ERROR)); } - private void log(Level logLevel, FestaGoException e, HttpServletRequest request) { - if (!errorLogger.isEnabledForLevel(logLevel)) { - return; + private void logInfo(FestaGoException e, HttpServletRequest request) { + if (errorLogger.isInfoEnabled()) { + errorLogger.info(LOG_FORMAT_INFO, request.getMethod(), request.getRequestURI(), authenticateContext.getId(), + authenticateContext.getRole(), e.getErrorCode(), + e.getClass().getName(), e.getMessage()); + } + } + + private void logWarn(FestaGoException e, HttpServletRequest request) { + if (errorLogger.isWarnEnabled()) { + errorLogger.warn(LOG_FORMAT_WARN, request.getMethod(), request.getRequestURI(), authenticateContext.getId(), + authenticateContext.getRole(), e.getErrorCode(), e); } - errorLogger.get(logLevel) - .log(LOG_FORMAT_ERROR_CODE, request.getMethod(), request.getRequestURI(), e.getErrorCode(), e); } - private void log(Level logLevel, Exception e, HttpServletRequest request) { - if (!errorLogger.isEnabledForLevel(logLevel)) { - return; + private void logError(Exception e, HttpServletRequest request) { + if (errorLogger.isErrorEnabled()) { + errorLogger.error(LOG_FORMAT_ERROR, request.getMethod(), request.getRequestURI(), + authenticateContext.getId(), authenticateContext.getRole(), e); } - errorLogger.get(logLevel) - .log(LOG_FORMAT, request.getMethod(), request.getRequestURI(), e); } } diff --git a/backend/src/test/java/com/festago/support/CustomWebMvcTest.java b/backend/src/test/java/com/festago/support/CustomWebMvcTest.java index 812ad7f2b..c19dde866 100644 --- a/backend/src/test/java/com/festago/support/CustomWebMvcTest.java +++ b/backend/src/test/java/com/festago/support/CustomWebMvcTest.java @@ -1,5 +1,6 @@ package com.festago.support; +import com.festago.config.ErrorLoggerConfig; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; @@ -9,7 +10,7 @@ import org.springframework.test.context.TestExecutionListeners.MergeMode; @WebMvcTest -@Import(TestAuthConfig.class) +@Import({TestAuthConfig.class, ErrorLoggerConfig.class}) @Retention(RetentionPolicy.RUNTIME) @TestExecutionListeners(value = MockAuthTestExecutionListener.class, mergeMode = MergeMode.MERGE_WITH_DEFAULTS) public @interface CustomWebMvcTest { From 636311ae3acf7ad01130f28835fa23ad2063bf4f Mon Sep 17 00:00:00 2001 From: seokjin8678 Date: Thu, 14 Sep 2023 14:47:59 +0900 Subject: [PATCH 21/74] =?UTF-8?q?[BE]=20feat:=20WARN=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=20=EC=8A=A4=ED=83=9D=20=ED=8A=B8=EB=A0=88=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EC=A0=9C=EA=B1=B0=20(#437)=20(#438)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: WARN 로그에 스택 트레이스 제거 * chore: 줄바꿈 수정 --- .../com/festago/presentation/GlobalExceptionHandler.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java index d7579566f..9fcf38b75 100644 --- a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java +++ b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java @@ -21,7 +21,7 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { private static final String LOG_FORMAT_INFO = "\n[🔵INFO] - ({} {})\n(id: {}, role: {})\n{}\n {}: {}"; - private static final String LOG_FORMAT_WARN = "\n[🟠WARN] - ({} {})\n(id: {}, role: {})\n{}"; + private static final String LOG_FORMAT_WARN = "\n[🟠WARN] - ({} {})\n(id: {}, role: {})\n{}\n {}: {}"; private static final String LOG_FORMAT_ERROR = "\n[🔴ERROR] - ({} {})\n(id: {}, role: {})"; // INFO /* @@ -37,7 +37,6 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { (id: 1, role: MEMBER) FOR_TEST_ERROR com.festago.exception.InternalServerException: 테스트용 에러입니다. - at com.festago.presentation.AdminController.getWarn(AdminController.java:134) */ // ERROR @@ -97,15 +96,14 @@ public ResponseEntity handle(Exception e, HttpServletRequest requ private void logInfo(FestaGoException e, HttpServletRequest request) { if (errorLogger.isInfoEnabled()) { errorLogger.info(LOG_FORMAT_INFO, request.getMethod(), request.getRequestURI(), authenticateContext.getId(), - authenticateContext.getRole(), e.getErrorCode(), - e.getClass().getName(), e.getMessage()); + authenticateContext.getRole(), e.getErrorCode(), e.getClass().getName(), e.getMessage()); } } private void logWarn(FestaGoException e, HttpServletRequest request) { if (errorLogger.isWarnEnabled()) { errorLogger.warn(LOG_FORMAT_WARN, request.getMethod(), request.getRequestURI(), authenticateContext.getId(), - authenticateContext.getRole(), e.getErrorCode(), e); + authenticateContext.getRole(), e.getErrorCode(), e.getClass().getName(), e.getMessage()); } } From e54c909c315d205817f156220a0244885a11c968 Mon Sep 17 00:00:00 2001 From: Guga Date: Thu, 14 Sep 2023 14:49:39 +0900 Subject: [PATCH 22/74] =?UTF-8?q?[BE]=20feat:=20validation=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#113)=20(#365)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 어노테이션 기반의 Spring validation 추가 * feat: 도메인 validation 추가 * feat: lineUp 은 null 일 수 있다. * feat: dto validation 추가 * feat: MethodArgumentNotValidException 에 대한 custom 핸들링 * feat: dto 의 예외 메시지 지정한다 * fix: Member 의 profileImage 가 null 인 경우의 null check 제거 * feat: length 검증 전 null check 가 선행되도록 변경 * refactor: Objects.isNull -> == null 확인으로 변경 * feat: Service Entity 생성 로직 삭제 * feat: socialType Enumerated 추가 * feat: @RequestBody validate 추가 * feat: dto @Valid 실패시 400 response --- .../com/festago/auth/dto/LoginRequest.java | 5 ++- .../java/com/festago/domain/Festival.java | 41 +++++++++++++++++- .../main/java/com/festago/domain/Member.java | 42 +++++++++++++++++- .../java/com/festago/domain/MemberTicket.java | 29 +++++++++++++ .../main/java/com/festago/domain/Stage.java | 43 +++++++++++++++++-- .../main/java/com/festago/domain/Ticket.java | 15 +++++++ .../java/com/festago/domain/TicketAmount.java | 14 ++++++ .../com/festago/domain/TicketEntryTime.java | 32 +++++++++++--- .../java/com/festago/dto/ErrorResponse.java | 10 +++++ .../festago/dto/FestivalCreateRequest.java | 12 +++--- .../com/festago/dto/StageCreateRequest.java | 9 ++-- .../com/festago/dto/TicketCreateRequest.java | 11 +++-- .../festago/dto/TicketValidationRequest.java | 4 +- .../com/festago/dto/TicketingRequest.java | 4 +- .../java/com/festago/exception/ErrorCode.java | 1 + .../festago/presentation/AdminController.java | 13 +++--- .../presentation/GlobalExceptionHandler.java | 11 +++++ .../presentation/MemberTicketController.java | 3 +- .../StaffMemberTicketController.java | 3 +- .../presentation/StudentController.java | 3 +- .../festago/domain/TicketEntryTimeTest.java | 21 ++++++--- 21 files changed, 283 insertions(+), 43 deletions(-) diff --git a/backend/src/main/java/com/festago/auth/dto/LoginRequest.java b/backend/src/main/java/com/festago/auth/dto/LoginRequest.java index f34f17bed..8f82722aa 100644 --- a/backend/src/main/java/com/festago/auth/dto/LoginRequest.java +++ b/backend/src/main/java/com/festago/auth/dto/LoginRequest.java @@ -1,7 +1,10 @@ package com.festago.auth.dto; import com.festago.auth.domain.SocialType; +import jakarta.validation.constraints.NotNull; -public record LoginRequest(SocialType socialType, String accessToken) { +public record LoginRequest( + @NotNull(message = "socialType 은 null 일 수 없습니다.") SocialType socialType, + @NotNull(message = "acessToken 은 null 일 수 없습니다.") String accessToken) { } diff --git a/backend/src/main/java/com/festago/domain/Festival.java b/backend/src/main/java/com/festago/domain/Festival.java index 088c4d080..2c72c9460 100644 --- a/backend/src/main/java/com/festago/domain/Festival.java +++ b/backend/src/main/java/com/festago/domain/Festival.java @@ -6,6 +6,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.time.LocalDate; import java.time.LocalDateTime; @@ -18,12 +20,18 @@ public class Festival extends BaseTimeEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotNull + @Size(max = 50) private String name; + @NotNull private LocalDate startDate; + @NotNull private LocalDate endDate; + @NotNull + @Size(max = 255) private String thumbnail; protected Festival() { @@ -38,7 +46,7 @@ public Festival(String name, LocalDate startDate, LocalDate endDate, String thum } public Festival(Long id, String name, LocalDate startDate, LocalDate endDate, String thumbnail) { - validate(startDate, endDate); + validate(name, startDate, endDate, thumbnail); this.id = id; this.name = name; this.startDate = startDate; @@ -46,7 +54,36 @@ public Festival(Long id, String name, LocalDate startDate, LocalDate endDate, St this.thumbnail = thumbnail; } - private void validate(LocalDate startDate, LocalDate endDate) { + private void validate(String name, LocalDate startDate, LocalDate endDate, String thumbnail) { + checkNotNull(name, startDate, endDate, thumbnail); + checkLength(name, thumbnail); + validateDate(startDate, endDate); + } + + private void checkNotNull(String name, LocalDate startDate, LocalDate endDate, String thumbnail) { + if (name == null || + startDate == null || + endDate == null || + thumbnail == null) { + throw new IllegalArgumentException("Festival 은 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + + private void checkLength(String name, String thumbnail) { + if (overLength(name, 50) || + overLength(thumbnail, 255)) { + throw new IllegalArgumentException("Festival 의 필드로 허용된 길이를 넘은 column 을 넣을 수 없습니다."); + } + } + + private boolean overLength(String target, int maxLength) { + if (target == null) { + return false; + } + return target.length() > maxLength; + } + + private void validateDate(LocalDate startDate, LocalDate endDate) { if (startDate.isAfter(endDate)) { throw new BadRequestException(ErrorCode.INVALID_FESTIVAL_DURATION); } diff --git a/backend/src/main/java/com/festago/domain/Member.java b/backend/src/main/java/com/festago/domain/Member.java index 2aefd4b7c..4b657e6d1 100644 --- a/backend/src/main/java/com/festago/domain/Member.java +++ b/backend/src/main/java/com/festago/domain/Member.java @@ -7,6 +7,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.time.LocalDateTime; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; @@ -17,18 +19,25 @@ public class Member extends BaseTimeEntity { private static final String DEFAULT_IMAGE_URL = "https://festa-go.site/images/default-profile.png"; - + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotNull + @Size(max = 255) private String socialId; - @Enumerated(EnumType.STRING) + @NotNull + @Enumerated(value = EnumType.STRING) private SocialType socialType; + @NotNull + @Size(max = 30) private String nickname; + @NotNull + @Size(max = 255) private String profileImage; private LocalDateTime deletedAt = null; @@ -45,6 +54,7 @@ public Member(String socialId, SocialType socialType, String nickname, String pr } public Member(Long id, String socialId, SocialType socialType, String nickname, String profileImage) { + validate(socialId, socialType, nickname, profileImage); this.id = id; this.socialId = socialId; this.socialType = socialType; @@ -52,6 +62,34 @@ public Member(Long id, String socialId, SocialType socialType, String nickname, this.profileImage = (profileImage != null) ? profileImage : DEFAULT_IMAGE_URL; } + private void validate(String socialId, SocialType socialType, String nickname, String profileImage) { + checkNotNull(socialId, socialType, nickname); + checkLength(socialId, nickname, profileImage); + } + + private void checkNotNull(String socialId, SocialType socialType, String nickname) { + if (socialId == null || + socialType == null || + nickname == null) { + throw new IllegalArgumentException("Member 는 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + + private void checkLength(String socialId, String nickname, String profileImage) { + if (overLength(socialId, 255) || + overLength(nickname, 30) || + overLength(profileImage, 255)) { + throw new IllegalArgumentException("Member 의 필드로 허용된 길이를 넘은 column 을 넣을 수 없습니다."); + } + } + + private boolean overLength(String target, int maxLength) { + if (target == null) { + return false; + } + return target.length() > maxLength; + } + public Long getId() { return id; } diff --git a/backend/src/main/java/com/festago/domain/MemberTicket.java b/backend/src/main/java/com/festago/domain/MemberTicket.java index a79aea13e..ce741075c 100644 --- a/backend/src/main/java/com/festago/domain/MemberTicket.java +++ b/backend/src/main/java/com/festago/domain/MemberTicket.java @@ -8,6 +8,8 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; import java.util.Objects; @@ -20,19 +22,25 @@ public class MemberTicket extends BaseTimeEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotNull @Enumerated(EnumType.STRING) private EntryState entryState = EntryState.BEFORE_ENTRY; + @NotNull @ManyToOne(fetch = FetchType.LAZY) private Member owner; + @NotNull @ManyToOne(fetch = FetchType.LAZY) private Stage stage; + @Min(value = 0) private int number; + @NotNull private LocalDateTime entryTime; + @NotNull @Enumerated(EnumType.STRING) private TicketType ticketType; @@ -45,6 +53,7 @@ public MemberTicket(Member owner, Stage stage, int number, LocalDateTime entryTi public MemberTicket(Long id, Member owner, Stage stage, int number, LocalDateTime entryTime, TicketType ticketType) { + validate(owner, stage, number, entryTime, ticketType); this.id = id; this.owner = owner; this.stage = stage; @@ -53,6 +62,26 @@ public MemberTicket(Long id, Member owner, Stage stage, int number, LocalDateTim this.ticketType = ticketType; } + private void validate(Member owner, Stage stage, int number, LocalDateTime entryTime, TicketType ticketType) { + checkNotNull(owner, stage, entryTime, ticketType); + checkScope(number); + } + + private void checkNotNull(Member owner, Stage stage, LocalDateTime entryTime, TicketType ticketType) { + if (owner == null || + stage == null || + entryTime == null || + ticketType == null) { + throw new IllegalArgumentException("MemberTicket 은 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + + private void checkScope(int number) { + if (number < 0) { + throw new IllegalArgumentException("MemberTicket 의 필드로 허용된 범위를 넘은 column 을 넣을 수 없습니다."); + } + } + public void changeState(EntryState originState) { if (originState != this.entryState) { return; diff --git a/backend/src/main/java/com/festago/domain/Stage.java b/backend/src/main/java/com/festago/domain/Stage.java index af2a3c299..933475dbd 100644 --- a/backend/src/main/java/com/festago/domain/Stage.java +++ b/backend/src/main/java/com/festago/domain/Stage.java @@ -2,7 +2,6 @@ import com.festago.exception.BadRequestException; import com.festago.exception.ErrorCode; -import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; @@ -10,6 +9,8 @@ import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -21,13 +22,16 @@ public class Stage extends BaseTimeEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false) + @NotNull private LocalDateTime startTime; + @Size(max = 255) private String lineUp; + @NotNull private LocalDateTime ticketOpenTime; + @NotNull @ManyToOne(fetch = FetchType.LAZY) private Festival festival; @@ -41,9 +45,13 @@ public Stage(LocalDateTime startTime, String lineUp, LocalDateTime ticketOpenTim this(null, startTime, lineUp, ticketOpenTime, festival); } + public Stage(LocalDateTime startTime, LocalDateTime ticketOpenTime, Festival festival) { + this(null, startTime, null, ticketOpenTime, festival); + } + public Stage(Long id, LocalDateTime startTime, String lineUp, LocalDateTime ticketOpenTime, Festival festival) { - validate(startTime, ticketOpenTime, festival); + validate(startTime, lineUp, ticketOpenTime, festival); this.id = id; this.startTime = startTime; this.lineUp = lineUp; @@ -51,7 +59,34 @@ public Stage(Long id, LocalDateTime startTime, String lineUp, LocalDateTime tick this.festival = festival; } - private void validate(LocalDateTime startTime, LocalDateTime ticketOpenTime, Festival festival) { + private void validate(LocalDateTime startTime, String lineUp, LocalDateTime ticketOpenTime, Festival festival) { + checkNotNull(startTime, ticketOpenTime, festival); + checkLength(lineUp); + validateTime(startTime, ticketOpenTime, festival); + } + + private void checkNotNull(LocalDateTime startTime, LocalDateTime ticketOpenTime, Festival festival) { + if (startTime == null || + ticketOpenTime == null || + festival == null) { + throw new IllegalArgumentException("Stage 는 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + + private void checkLength(String lineUp) { + if (overLength(lineUp, 255)) { + throw new IllegalArgumentException("Stage 의 필드로 허용된 범위를 넘은 column 을 넣을 수 없습니다."); + } + } + + private boolean overLength(String target, int maxLength) { + if (target == null) { + return false; + } + return target.length() > maxLength; + } + + private void validateTime(LocalDateTime startTime, LocalDateTime ticketOpenTime, Festival festival) { if (festival.isNotInDuration(startTime)) { throw new BadRequestException(ErrorCode.INVALID_STAGE_START_TIME); } diff --git a/backend/src/main/java/com/festago/domain/Ticket.java b/backend/src/main/java/com/festago/domain/Ticket.java index 2b078e292..326c2c1bc 100644 --- a/backend/src/main/java/com/festago/domain/Ticket.java +++ b/backend/src/main/java/com/festago/domain/Ticket.java @@ -14,6 +14,7 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; +import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; import java.util.Set; import java.util.SortedSet; @@ -29,9 +30,11 @@ public class Ticket extends BaseTimeEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotNull @ManyToOne(fetch = FetchType.LAZY) private Stage stage; + @NotNull @Enumerated(EnumType.STRING) private TicketType ticketType; @@ -51,12 +54,24 @@ public Ticket(Stage stage, TicketType ticketType) { } public Ticket(Long id, Stage stage, TicketType ticketType) { + validate(stage, ticketType); this.id = id; this.stage = stage; this.ticketType = ticketType; this.ticketAmount = new TicketAmount(this); } + private void validate(Stage stage, TicketType ticketType) { + checkNotNull(stage, ticketType); + } + + private void checkNotNull(Stage stage, TicketType ticketType) { + if (stage == null || + ticketType == null) { + throw new IllegalArgumentException("Ticket 은 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + public void addTicketEntryTime(LocalDateTime currentTime, LocalDateTime entryTime, int amount) { validateEntryTime(currentTime, entryTime); TicketEntryTime ticketEntryTime = new TicketEntryTime(entryTime, amount); diff --git a/backend/src/main/java/com/festago/domain/TicketAmount.java b/backend/src/main/java/com/festago/domain/TicketAmount.java index 7d55fb1a1..03d4a91db 100644 --- a/backend/src/main/java/com/festago/domain/TicketAmount.java +++ b/backend/src/main/java/com/festago/domain/TicketAmount.java @@ -8,6 +8,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.MapsId; import jakarta.persistence.OneToOne; +import jakarta.validation.constraints.Min; @Entity public class TicketAmount extends BaseTimeEntity { @@ -15,8 +16,10 @@ public class TicketAmount extends BaseTimeEntity { @Id private Long id; + @Min(value = 0) private int reservedAmount = 0; + @Min(value = 0) private int totalAmount = 0; @OneToOne(fetch = FetchType.LAZY) @@ -28,9 +31,20 @@ protected TicketAmount() { } public TicketAmount(Ticket ticket) { + validate(ticket); this.ticket = ticket; } + private void validate(Ticket ticket) { + checkNotNull(ticket); + } + + private void checkNotNull(Ticket ticket) { + if (ticket == null) { + throw new IllegalArgumentException("TicketAmount 는 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + public void increaseReservedAmount() { if (reservedAmount >= totalAmount) { throw new BadRequestException(ErrorCode.TICKET_SOLD_OUT); diff --git a/backend/src/main/java/com/festago/domain/TicketEntryTime.java b/backend/src/main/java/com/festago/domain/TicketEntryTime.java index 3994251df..e495a07d4 100644 --- a/backend/src/main/java/com/festago/domain/TicketEntryTime.java +++ b/backend/src/main/java/com/festago/domain/TicketEntryTime.java @@ -6,6 +6,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; @Entity @@ -17,25 +19,45 @@ public class TicketEntryTime extends BaseTimeEntity implements Comparable createFestival(@RequestBody FestivalCreateRequest request) { + public ResponseEntity createFestival(@RequestBody @Valid FestivalCreateRequest request) { FestivalResponse response = festivalService.create(request); return ResponseEntity.ok() .body(response); } @PostMapping("/stages") - public ResponseEntity createStage(@RequestBody StageCreateRequest request) { + public ResponseEntity createStage(@RequestBody @Valid StageCreateRequest request) { StageResponse response = stageService.create(request); return ResponseEntity.ok() .body(response); } @PostMapping("/tickets") - public ResponseEntity createTicket(@RequestBody TicketCreateRequest request) { + public ResponseEntity createTicket(@RequestBody @Valid TicketCreateRequest request) { TicketCreateResponse response = ticketService.create(request); return ResponseEntity.ok() .body(response); @@ -96,7 +97,7 @@ public ModelAndView loginPage() { } @PostMapping("/login") - public ResponseEntity login(@RequestBody AdminLoginRequest request) { + public ResponseEntity login(@RequestBody @Valid AdminLoginRequest request) { String token = adminAuthService.login(request); return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, getCookie(token)) .build(); @@ -140,7 +141,7 @@ public ResponseEntity getInfo() { } @PostMapping("/initialize") - public ResponseEntity initializeRootAdmin(@RequestBody RootAdminInitializeRequest request) { + public ResponseEntity initializeRootAdmin(@RequestBody @Valid RootAdminInitializeRequest request) { adminAuthService.initializeRootAdmin(request.password()); return ResponseEntity.ok() .build(); @@ -152,7 +153,7 @@ public ModelAndView signupPage() { } @PostMapping("/signup") - public ResponseEntity signupAdminAccount(@RequestBody AdminSignupRequest request, + public ResponseEntity signupAdminAccount(@RequestBody @Valid AdminSignupRequest request, @Admin Long adminId) { AdminSignupResponse response = adminAuthService.signup(adminId, request); return ResponseEntity.ok() diff --git a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java index 9fcf38b75..866b119cc 100644 --- a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java +++ b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java @@ -11,10 +11,14 @@ import com.festago.exception.UnauthorizedException; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; @RestControllerAdvice @@ -93,6 +97,13 @@ public ResponseEntity handle(Exception e, HttpServletRequest requ .body(ErrorResponse.from(ErrorCode.INTERNAL_SERVER_ERROR)); } + @Override + protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException e, HttpHeaders headers, + HttpStatusCode status, WebRequest request) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ErrorResponse.from(ErrorCode.INVALID_REQUEST_ARGUMENT)); + } + private void logInfo(FestaGoException e, HttpServletRequest request) { if (errorLogger.isInfoEnabled()) { errorLogger.info(LOG_FORMAT_INFO, request.getMethod(), request.getRequestURI(), authenticateContext.getId(), diff --git a/backend/src/main/java/com/festago/presentation/MemberTicketController.java b/backend/src/main/java/com/festago/presentation/MemberTicketController.java index 9ceee591d..1319d954f 100644 --- a/backend/src/main/java/com/festago/presentation/MemberTicketController.java +++ b/backend/src/main/java/com/festago/presentation/MemberTicketController.java @@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -53,7 +54,7 @@ public ResponseEntity createQR(@Member Long memberId, @PostMapping @Operation(description = "티켓을 예매한다.", summary = "티켓 예매") public ResponseEntity ticketing(@Member Long memberId, - @RequestBody TicketingRequest request) { + @RequestBody @Valid TicketingRequest request) { TicketingResponse response = ticketingService.ticketing(memberId, request); return ResponseEntity.ok() .body(response); diff --git a/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java b/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java index d3aeedd3b..cf969b956 100644 --- a/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java +++ b/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java @@ -6,6 +6,7 @@ import com.festago.dto.TicketValidationResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -25,7 +26,7 @@ public StaffMemberTicketController(EntryService entryService) { @PostMapping("/validation") @Operation(description = "스태프가 티켓을 검사한다.", summary = "티켓 검사") - public ResponseEntity validate(@RequestBody TicketValidationRequest request) { + public ResponseEntity validate(@RequestBody @Valid TicketValidationRequest request) { TicketValidationResponse response = entryService.validate(request); return ResponseEntity.ok() .body(response); diff --git a/backend/src/main/java/com/festago/presentation/StudentController.java b/backend/src/main/java/com/festago/presentation/StudentController.java index 7f0c1270a..462c87cb3 100644 --- a/backend/src/main/java/com/festago/presentation/StudentController.java +++ b/backend/src/main/java/com/festago/presentation/StudentController.java @@ -6,6 +6,7 @@ import com.festago.dto.StudentVerificateRequest; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -35,7 +36,7 @@ public ResponseEntity sendEmail(@Member Long memberId, @PostMapping("/verification") @Operation(description = "학교 인증을 수행한다.", summary = "학생 인증 수행") public ResponseEntity verificate(@Member Long memberId, - @RequestBody StudentVerificateRequest request) { + @RequestBody @Valid StudentVerificateRequest request) { studentService.verificate(memberId, request); return ResponseEntity.ok() .build(); diff --git a/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java b/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java index 32bfbc5c0..e1c283290 100644 --- a/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java +++ b/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java @@ -6,21 +6,30 @@ import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.api.Test; @DisplayNameGeneration(ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") class TicketEntryTimeTest { - @ParameterizedTest - @ValueSource(ints = {0, -1}) - void 총_수량이_1_미만이면_예외(int totalAmount) { + @Test + void 총_수량이_음수일_경우_에외() { // given LocalDateTime now = LocalDateTime.now(); // when & then - assertThatThrownBy(() -> new TicketEntryTime(now, totalAmount)) + assertThatThrownBy(() -> new TicketEntryTime(now, -1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("TicketEntryTime 의 필드로 허용된 범위를 넘은 column 을 넣을 수 없습니다."); + } + + @Test + void 총_수량이_1_미만이면_예외() { + // given + LocalDateTime now = LocalDateTime.now(); + + // when & then + assertThatThrownBy(() -> new TicketEntryTime(now, 0)) .isInstanceOf(BadRequestException.class) .hasMessage("티켓은 적어도 한장 이상 발급해야합니다."); } From d5bc76607556859aff06102f1ef6725a29f93d6e Mon Sep 17 00:00:00 2001 From: seokjin8678 Date: Thu, 14 Sep 2023 14:50:19 +0900 Subject: [PATCH 23/74] =?UTF-8?q?[BE]=20refactor:=20EntryCode=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EA=B0=9C=EC=84=A0=20(#399)=20(#401)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: EntryCode에서 시간에 관련된 부분 분리 * refactor: EntryCodeProvider 파라미터 수정 - EntryCodePayload -> MemberTicket * test: JwtEntryCodeProvider 테스트 코드 개선 * feat: JwtEntryCodeExtractor null 검사 추가 * refactor: create 정적 메서드로 생성 변경 * refactor: EntryCodeProvider 매개변수 EntryCodePayload로 변경 * refactor: EntryCodeManager 추가, 사용 * refactor: 단위에 언더스코어 추가 --- .../festago/application/EntryCodeManager.java | 34 +++++++++++++++++++ .../com/festago/application/EntryService.java | 15 +++----- .../java/com/festago/domain/EntryCode.java | 10 ------ .../com/festago/domain/EntryCodePayload.java | 8 ++--- .../infrastructure/JwtEntryCodeExtractor.java | 2 +- .../festago/application/EntryServiceTest.java | 24 ++++++------- .../JwtEntryCodeExtractorTest.java | 10 ++++++ .../JwtEntryCodeProviderTest.java | 16 ++++----- 8 files changed, 72 insertions(+), 47 deletions(-) create mode 100644 backend/src/main/java/com/festago/application/EntryCodeManager.java diff --git a/backend/src/main/java/com/festago/application/EntryCodeManager.java b/backend/src/main/java/com/festago/application/EntryCodeManager.java new file mode 100644 index 000000000..165e7ea6d --- /dev/null +++ b/backend/src/main/java/com/festago/application/EntryCodeManager.java @@ -0,0 +1,34 @@ +package com.festago.application; + +import com.festago.domain.EntryCode; +import com.festago.domain.EntryCodeExtractor; +import com.festago.domain.EntryCodePayload; +import com.festago.domain.EntryCodeProvider; +import java.util.Date; +import org.springframework.stereotype.Component; + +@Component +public class EntryCodeManager { + + private static final int MILLISECOND_FACTOR = 1_000; + private static final int DEFAULT_PERIOD = 30; + private static final int DEFAULT_OFFSET = 10; + + private final EntryCodeProvider entryCodeProvider; + private final EntryCodeExtractor entryCodeExtractor; + + public EntryCodeManager(EntryCodeProvider entryCodeProvider, EntryCodeExtractor entryCodeExtractor) { + this.entryCodeProvider = entryCodeProvider; + this.entryCodeExtractor = entryCodeExtractor; + } + + public EntryCode provide(EntryCodePayload entryCodePayload, long currentTimeMillis) { + Date expiredAt = new Date(currentTimeMillis + (DEFAULT_PERIOD + DEFAULT_OFFSET) * MILLISECOND_FACTOR); + String code = entryCodeProvider.provide(entryCodePayload, expiredAt); + return new EntryCode(code, DEFAULT_PERIOD, DEFAULT_OFFSET); + } + + public EntryCodePayload extract(String code) { + return entryCodeExtractor.extract(code); + } +} diff --git a/backend/src/main/java/com/festago/application/EntryService.java b/backend/src/main/java/com/festago/application/EntryService.java index e4073a633..f0b9ced3a 100644 --- a/backend/src/main/java/com/festago/application/EntryService.java +++ b/backend/src/main/java/com/festago/application/EntryService.java @@ -1,9 +1,7 @@ package com.festago.application; import com.festago.domain.EntryCode; -import com.festago.domain.EntryCodeExtractor; import com.festago.domain.EntryCodePayload; -import com.festago.domain.EntryCodeProvider; import com.festago.domain.MemberTicket; import com.festago.domain.MemberTicketRepository; import com.festago.dto.EntryCodeResponse; @@ -21,15 +19,12 @@ @Transactional public class EntryService { - private final EntryCodeProvider entryCodeProvider; - private final EntryCodeExtractor entryCodeExtractor; + private final EntryCodeManager entryCodeManager; private final MemberTicketRepository memberTicketRepository; private final Clock clock; - public EntryService(EntryCodeProvider entryCodeProvider, EntryCodeExtractor entryCodeExtractor, - MemberTicketRepository memberTicketRepository, Clock clock) { - this.entryCodeProvider = entryCodeProvider; - this.entryCodeExtractor = entryCodeExtractor; + public EntryService(EntryCodeManager entryCodeManager, MemberTicketRepository memberTicketRepository, Clock clock) { + this.entryCodeManager = entryCodeManager; this.memberTicketRepository = memberTicketRepository; this.clock = clock; } @@ -42,7 +37,7 @@ public EntryCodeResponse createEntryCode(Long memberId, Long memberTicketId) { if (!memberTicket.canEntry(LocalDateTime.now(clock))) { throw new BadRequestException(ErrorCode.NOT_ENTRY_TIME); } - EntryCode entryCode = EntryCode.create(entryCodeProvider, memberTicket); + EntryCode entryCode = entryCodeManager.provide(EntryCodePayload.from(memberTicket), clock.millis()); return EntryCodeResponse.of(entryCode); } @@ -52,7 +47,7 @@ private MemberTicket findMemberTicket(Long memberTicketId) { } public TicketValidationResponse validate(TicketValidationRequest request) { - EntryCodePayload entryCodePayload = entryCodeExtractor.extract(request.code()); + EntryCodePayload entryCodePayload = entryCodeManager.extract(request.code()); MemberTicket memberTicket = findMemberTicket(entryCodePayload.getMemberTicketId()); memberTicket.changeState(entryCodePayload.getEntryState()); return TicketValidationResponse.from(memberTicket); diff --git a/backend/src/main/java/com/festago/domain/EntryCode.java b/backend/src/main/java/com/festago/domain/EntryCode.java index 2ad8fbca0..6a433a5f2 100644 --- a/backend/src/main/java/com/festago/domain/EntryCode.java +++ b/backend/src/main/java/com/festago/domain/EntryCode.java @@ -2,13 +2,9 @@ import com.festago.exception.ErrorCode; import com.festago.exception.InternalServerException; -import java.util.Date; public class EntryCode { - private static final long DEFAULT_PERIOD = 30; - private static final long DEFAULT_OFFSET = 10; - private static final int MILLISECOND_FACTOR = 1000; private static final int MINIMUM_PERIOD = 0; private static final int MINIMUM_OFFSET = 0; @@ -36,12 +32,6 @@ private boolean isNegative(long offset) { return offset < MINIMUM_OFFSET; } - public static EntryCode create(EntryCodeProvider entryCodeProvider, MemberTicket memberTicket) { - Date expiredAt = new Date(new Date().getTime() + (DEFAULT_PERIOD + DEFAULT_OFFSET) * MILLISECOND_FACTOR); - String code = entryCodeProvider.provide(EntryCodePayload.from(memberTicket), expiredAt); - return new EntryCode(code, DEFAULT_PERIOD, DEFAULT_OFFSET); - } - public String getCode() { return code; } diff --git a/backend/src/main/java/com/festago/domain/EntryCodePayload.java b/backend/src/main/java/com/festago/domain/EntryCodePayload.java index ee29374e0..51a82e779 100644 --- a/backend/src/main/java/com/festago/domain/EntryCodePayload.java +++ b/backend/src/main/java/com/festago/domain/EntryCodePayload.java @@ -14,16 +14,16 @@ public EntryCodePayload(Long memberTicketId, EntryState entryState) { this.entryState = entryState; } - public static EntryCodePayload from(MemberTicket memberTicket) { - return new EntryCodePayload(memberTicket.getId(), memberTicket.getEntryState()); - } - private void validate(Long memberTicketId, EntryState entryState) { if (memberTicketId == null || entryState == null) { throw new InternalServerException(ErrorCode.INVALID_ENTRY_CODE_PAYLOAD); } } + public static EntryCodePayload from(MemberTicket memberTicket) { + return new EntryCodePayload(memberTicket.getId(), memberTicket.getEntryState()); + } + public Long getMemberTicketId() { return memberTicketId; } diff --git a/backend/src/main/java/com/festago/infrastructure/JwtEntryCodeExtractor.java b/backend/src/main/java/com/festago/infrastructure/JwtEntryCodeExtractor.java index d58010f29..d18de11bf 100644 --- a/backend/src/main/java/com/festago/infrastructure/JwtEntryCodeExtractor.java +++ b/backend/src/main/java/com/festago/infrastructure/JwtEntryCodeExtractor.java @@ -43,7 +43,7 @@ private Claims getClaims(String code) { .getBody(); } catch (ExpiredJwtException e) { throw new BadRequestException(ErrorCode.EXPIRED_ENTRY_CODE); - } catch (JwtException e) { + } catch (JwtException | IllegalArgumentException e) { throw new BadRequestException(ErrorCode.INVALID_ENTRY_CODE); } } diff --git a/backend/src/test/java/com/festago/application/EntryServiceTest.java b/backend/src/test/java/com/festago/application/EntryServiceTest.java index 47c55e311..ea2a7e8cb 100644 --- a/backend/src/test/java/com/festago/application/EntryServiceTest.java +++ b/backend/src/test/java/com/festago/application/EntryServiceTest.java @@ -7,9 +7,8 @@ import static org.mockito.BDDMockito.anyLong; import static org.mockito.BDDMockito.given; -import com.festago.domain.EntryCodeExtractor; +import com.festago.domain.EntryCode; import com.festago.domain.EntryCodePayload; -import com.festago.domain.EntryCodeProvider; import com.festago.domain.EntryState; import com.festago.domain.Festival; import com.festago.domain.Member; @@ -48,10 +47,7 @@ class EntryServiceTest { @Mock - EntryCodeProvider entryCodeProvider; - - @Mock - EntryCodeExtractor entryCodeExtractor; + EntryCodeManager entryCodeManager; @Mock MemberTicketRepository memberTicketRepository; @@ -181,24 +177,24 @@ class 티켓의_QR_생성_요청 { .stage(stage) .entryTime(entryTime) .build(); - String code = "3112321312123"; + EntryCode entryCode = new EntryCode("1234", 30, 10); Long memberId = memberTicket.getOwner().getId(); Long memberTicketId = memberTicket.getId(); given(memberTicketRepository.findById(anyLong())) .willReturn(Optional.of(memberTicket)); - given(entryCodeProvider.provide(any(), any())) - .willReturn(code); + given(entryCodeManager.provide(any(EntryCodePayload.class), anyLong())) + .willReturn(entryCode); given(clock.instant()) .willReturn(now); // when - EntryCodeResponse entryCode = entryService.createEntryCode(memberId, memberTicketId); + EntryCodeResponse response = entryService.createEntryCode(memberId, memberTicketId); // then assertSoftly(softly -> { - softly.assertThat(entryCode.code()).isEqualTo(code); - softly.assertThat(entryCode.period()).isEqualTo(30); + softly.assertThat(response.code()).isEqualTo(entryCode.getCode()); + softly.assertThat(response.period()).isEqualTo(30); }); } } @@ -213,7 +209,7 @@ class 티켓_검사 { MemberTicket memberTicket = MemberTicketFixture.memberTicket() .id(1L) .build(); - given(entryCodeExtractor.extract(anyString())) + given(entryCodeManager.extract(anyString())) .willReturn(new EntryCodePayload(1L, EntryState.BEFORE_ENTRY)); given(memberTicketRepository.findById(anyLong())) .willReturn(Optional.of(memberTicket)); @@ -235,7 +231,7 @@ class 티켓_검사 { MemberTicket memberTicket = MemberTicketFixture.memberTicket() .id(1L) .build(); - given(entryCodeExtractor.extract(anyString())) + given(entryCodeManager.extract(anyString())) .willReturn(new EntryCodePayload(1L, EntryState.AFTER_ENTRY)); given(memberTicketRepository.findById(anyLong())) .willReturn(Optional.of(memberTicket)); diff --git a/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeExtractorTest.java b/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeExtractorTest.java index 62a28e147..da4a31c1b 100644 --- a/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeExtractorTest.java +++ b/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeExtractorTest.java @@ -38,6 +38,16 @@ class JwtEntryCodeExtractorTest { .hasMessage("올바르지 않은 입장코드입니다."); } + @Test + void 토큰이_null_이면_예외() { + String code = null; + + // when & then + assertThatThrownBy(() -> jwtEntryCodeExtractor.extract(code)) + .isInstanceOf(BadRequestException.class) + .hasMessage("올바르지 않은 입장코드입니다."); + } + @Test void 기간이_만료된_토큰이면_예외() { //given diff --git a/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeProviderTest.java b/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeProviderTest.java index 5bdfc7d66..dc6d4557c 100644 --- a/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeProviderTest.java +++ b/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeProviderTest.java @@ -27,14 +27,14 @@ class JwtEntryCodeProviderTest { void expiredAt이_과거이면_예외() { // given Date now = new Date(); - Date expiredAt = new Date(now.getTime() - 1000L); + Date expiredAt = new Date(now.getTime() - 1_000); MemberTicket memberTicket = MemberTicketFixture.memberTicket() .id(1L) .build(); - EntryCodePayload payload = EntryCodePayload.from(memberTicket); + EntryCodePayload entryCodePayload = EntryCodePayload.from(memberTicket); // when & then - assertThatThrownBy(() -> entryCodeProvider.provide(payload, expiredAt)) + assertThatThrownBy(() -> entryCodeProvider.provide(entryCodePayload, expiredAt)) .isInstanceOf(InternalServerException.class) .hasMessage("올바르지 않은 입장코드 만료 일자입니다."); } @@ -42,13 +42,14 @@ class JwtEntryCodeProviderTest { @Test void JWT_토큰을_생성() { // given - long period = 30000; + long period = 30_000; MemberTicket memberTicket = MemberTicketFixture.memberTicket().id(1L).build(); Date now = new Date(); Date expiredAt = new Date(now.getTime() + period); + EntryCodePayload entryCodePayload = EntryCodePayload.from(memberTicket); // when - String code = entryCodeProvider.provide(EntryCodePayload.from(memberTicket), expiredAt); + String code = entryCodeProvider.provide(entryCodePayload, expiredAt); // then Claims claims = Jwts.parserBuilder() @@ -57,12 +58,11 @@ class JwtEntryCodeProviderTest { .parseClaimsJws(code) .getBody(); - Long actualMemberTicketId = (long) ((int) claims.get("ticketId")); + Long actualMemberTicketId = claims.get("ticketId", Long.class); Date actualExpiredAt = claims.getExpiration(); assertSoftly(softly -> { - softly.assertThat(actualExpiredAt.getTime() - now.getTime() / 1000 * 1000) - .isEqualTo(period); + softly.assertThat(actualExpiredAt).isEqualToIgnoringMillis(expiredAt); softly.assertThat(actualMemberTicketId).isEqualTo(memberTicket.getId()); }); } From 13bfb38c2f312206ff4f7795a2e0c81b8dbae5f6 Mon Sep 17 00:00:00 2001 From: seokjin8678 Date: Thu, 14 Sep 2023 15:01:34 +0900 Subject: [PATCH 24/74] =?UTF-8?q?[BE]=20feat:=20InvalidMediaTypeException?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=ED=95=B8=EB=93=A4=EB=A7=81=20(#439)=20?= =?UTF-8?q?(#440)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/festago/presentation/GlobalExceptionHandler.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java index 866b119cc..1df4a7d82 100644 --- a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java +++ b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java @@ -13,6 +13,7 @@ import org.slf4j.Logger; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -59,6 +60,11 @@ public GlobalExceptionHandler(AuthenticateContext authenticateContext, Logger er this.errorLogger = errorLogger; } + @ExceptionHandler(InvalidMediaTypeException.class) + public ResponseEntity handle(InvalidMediaTypeException e) { + return ResponseEntity.badRequest().build(); + } + @ExceptionHandler(BadRequestException.class) public ResponseEntity handle(BadRequestException e, HttpServletRequest request) { logInfo(e, request); From fe3e7dacf3dc7a6207e0556f72a75789d01d826c Mon Sep 17 00:00:00 2001 From: Guga Date: Thu, 14 Sep 2023 20:59:20 +0900 Subject: [PATCH 25/74] =?UTF-8?q?[BE]=20feat:=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=EB=B3=84=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?(#441)=20(#442)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ => admin}/application/AdminService.java | 26 +++++++------- .../festago/{auth => admin}/domain/Admin.java | 4 +-- .../dto/AdminFestivalResponse.java | 2 +- .../{ => admin}/dto/AdminResponse.java | 2 +- .../{ => admin}/dto/AdminStageResponse.java | 2 +- .../{ => admin}/dto/AdminTicketResponse.java | 4 +-- .../repository}/AdminRepository.java | 3 +- .../auth/application/AdminAuthService.java | 13 ++++--- .../auth/application/AuthExtractor.java | 8 +++++ .../auth/application/AuthFacadeService.java | 3 -- .../auth/application/AuthProvider.java | 8 +++++ .../festago/auth/application/AuthService.java | 8 ++--- .../auth/application/OAuth2Client.java | 11 ++++++ .../OAuth2Clients.java | 9 ++--- .../TokenExtractor.java | 2 +- .../com/festago/auth/config/AuthConfig.java | 8 ++--- .../com/festago/auth/config/LoginConfig.java | 8 ++--- .../festago/auth/domain/AuthExtractor.java | 6 ---- .../com/festago/auth/domain/AuthPayload.java | 4 +-- .../com/festago/auth/domain/AuthProvider.java | 6 ---- .../com/festago/auth/domain/OAuth2Client.java | 8 ----- .../java/com/festago/auth/domain/Role.java | 4 +-- .../com/festago/auth/domain/UserInfo.java | 2 +- .../com/festago/auth/dto/LoginMemberDto.java | 2 +- .../infrastructure/CookieTokenExtractor.java | 2 +- .../infrastructure/FestagoOAuth2Client.java | 6 ++-- .../infrastructure/HeaderTokenExtractor.java | 6 ++-- .../auth/infrastructure/JwtAuthExtractor.java | 6 ++-- .../auth/infrastructure/JwtAuthProvider.java | 2 +- .../infrastructure/KakaoOAuth2Client.java | 2 +- .../KakaoOAuth2UserInfoErrorHandler.java | 6 ++-- .../{ => common}/aop/LogRequestBody.java | 2 +- .../aop/LogRequestBodyAspect.java | 6 ++-- .../{ => common}/domain/BaseTimeEntity.java | 2 +- .../exception/BadRequestException.java | 2 +- .../{ => common}/exception/ErrorCode.java | 2 +- .../exception/FestaGoException.java | 2 +- .../exception/ForbiddenException.java | 2 +- .../exception/InternalServerException.java | 2 +- .../exception/NotFoundException.java | 2 +- .../exception/UnauthorizedException.java | 2 +- .../exception}/dto/ErrorResponse.java | 6 ++-- .../festago/domain/EntryCodeExtractor.java | 6 ---- .../java/com/festago/domain/MailClient.java | 6 ---- .../domain/VerificationCodeProvider.java | 6 ---- .../entry/application/EntryCodeExtractor.java | 8 +++++ .../application/EntryCodeManager.java | 8 ++--- .../application}/EntryCodeProvider.java | 3 +- .../{ => entry}/application/EntryService.java | 22 ++++++------ .../{ => entry}/config/EntryCodeConfig.java | 10 +++--- .../festago/{ => entry}/domain/EntryCode.java | 6 ++-- .../{ => entry}/domain/EntryCodePayload.java | 16 +++++---- .../{ => entry}/dto/EntryCodeResponse.java | 4 +-- .../dto/TicketValidationRequest.java | 2 +- .../dto/TicketValidationResponse.java | 6 ++-- .../infrastructure/JwtEntryCodeExtractor.java | 12 +++---- .../infrastructure/JwtEntryCodeProvider.java | 10 +++--- .../application/FestivalService.java | 24 ++++++------- .../{ => festival}/domain/Festival.java | 7 ++-- .../dto/FestivalCreateRequest.java | 4 +-- .../dto/FestivalDetailResponse.java | 6 ++-- .../dto/FestivalDetailStageResponse.java | 4 +-- .../dto/FestivalDetailTicketResponse.java | 8 ++--- .../{ => festival}/dto/FestivalResponse.java | 4 +-- .../{ => festival}/dto/FestivalsResponse.java | 4 +-- .../repository}/FestivalRepository.java | 3 +- .../application/MemberService.java | 12 +++---- .../festago/{ => member}/domain/Member.java | 3 +- .../dto/MemberProfileResponse.java | 4 +-- .../repository}/MemberRepository.java | 3 +- .../festago/presentation/AdminController.java | 30 ++++++++-------- .../presentation/AuthController.java | 2 +- .../presentation/FestivalController.java | 6 ++-- .../presentation/GlobalExceptionHandler.java | 20 +++++------ .../presentation/MemberController.java | 4 +-- .../presentation/MemberTicketController.java | 16 ++++----- .../presentation/SchoolController.java | 4 +-- .../StaffMemberTicketController.java | 6 ++-- .../festago/presentation/StageController.java | 4 +-- .../presentation/StudentController.java | 6 ++-- .../auth}/AuthInterceptor.java | 12 +++---- .../auth}/AuthenticateContext.java | 2 +- .../auth}/RoleArgumentResolver.java | 6 ++-- .../common}/ErrorFilter.java | 2 +- .../application/SchoolService.java | 6 ++-- .../festago/{ => school}/domain/School.java | 7 ++-- .../{ => school}/dto/SchoolResponse.java | 4 +-- .../{ => school}/dto/SchoolsResponse.java | 4 +-- .../repository}/SchoolRepository.java | 3 +- .../{ => stage}/application/StageService.java | 18 +++++----- .../com/festago/{ => stage}/domain/Stage.java | 9 +++-- .../{ => stage}/dto/StageCreateRequest.java | 2 +- .../{ => stage}/dto/StageResponse.java | 4 +-- .../repository}/StageRepository.java | 3 +- .../student/application/MailClient.java | 8 +++++ .../application/StudentService.java | 34 +++++++++---------- .../application/VerificationCodeProvider.java | 8 +++++ .../festago/{ => student}/domain/Student.java | 9 +++-- .../{ => student}/domain/StudentCode.java | 9 +++-- .../domain/VerificationCode.java | 9 +++-- .../domain/VerificationMailPayload.java | 6 ++-- .../dto/StudentSendMailRequest.java | 2 +- .../dto/StudentVerificateRequest.java | 2 +- .../infrastructure/GoogleMailClient.java | 6 ++-- .../infrastructure/MockMailClient.java | 6 ++-- .../RandomVerificationCodeProvider.java | 6 ++-- .../repository}/StudentCodeRepository.java | 5 ++- .../repository}/StudentRepository.java | 3 +- .../application/TicketService.java | 24 ++++++------- .../festago/{ => ticket}/domain/Ticket.java | 12 ++++--- .../{ => ticket}/domain/TicketAmount.java | 9 ++--- .../{ => ticket}/domain/TicketEntryTime.java | 7 ++-- .../{ => ticket}/domain/TicketType.java | 2 +- .../{ => ticket}/dto/StageTicketResponse.java | 8 ++--- .../dto/StageTicketsResponse.java | 4 +-- .../{ => ticket}/dto/TicketCreateRequest.java | 4 +-- .../dto/TicketCreateResponse.java | 4 +-- .../repository}/TicketAmountRepository.java | 3 +- .../repository}/TicketRepository.java | 5 ++- .../application/MemberTicketService.java | 18 +++++----- .../application/TicketingService.java | 28 +++++++-------- .../{ => ticketing}/domain/EntryState.java | 6 ++-- .../{ => ticketing}/domain/MemberTicket.java | 6 +++- .../dto/MemberTicketFestivalResponse.java | 4 +-- .../dto/MemberTicketResponse.java | 9 ++--- .../dto/MemberTicketsResponse.java | 4 +-- .../{ => ticketing}/dto/TicketingRequest.java | 2 +- .../dto/TicketingResponse.java | 4 +-- .../repository}/MemberTicketRepository.java | 5 ++- .../festago/application/EntryServiceTest.java | 28 ++++++++------- .../application/FestivalServiceTest.java | 23 +++++++------ .../application/MemberTicketServiceTest.java | 19 ++++++----- .../festago/application/StageServiceTest.java | 13 +++---- .../application/StudentServiceTest.java | 29 ++++++++-------- .../application/TicketServiceTest.java | 15 ++++---- .../FestivalServiceIntegrationTest.java | 26 +++++++------- .../MemberTicketIntegrationTest.java | 20 +++++------ .../StageServiceIntegrationTest.java | 8 ++--- .../TicketServiceIntegrationTest.java | 24 ++++++------- .../TicketingServiceIntegrationTest.java | 14 ++++---- .../AdminAuthFacadeServiceTest.java | 11 +++--- .../application/AuthFacadeServiceTest.java | 4 +-- .../auth/application/AuthServiceTest.java | 6 ++-- .../AuthFacadeServiceIntegrationTest.java | 4 +-- .../auth/domain/OAuth2ClientsTest.java | 8 +++-- .../HeaderTokenExtractorTest.java | 2 +- .../infrastructure/JwtAuthExtractorTest.java | 4 +-- .../KakaoOAuth2UserInfoClientTest.java | 4 +-- .../auth/presentation/AuthControllerTest.java | 1 + .../RoleArgumentResolverTest.java | 4 ++- .../com/festago/domain/EntryCodeTest.java | 3 +- .../com/festago/domain/EntryStateTest.java | 3 +- .../java/com/festago/domain/FestivalTest.java | 3 +- .../festago/domain/MemberRepositoryTest.java | 2 ++ .../java/com/festago/domain/MemberTest.java | 1 + .../domain/MemberTicketRepositoryTest.java | 10 ++++++ .../com/festago/domain/MemberTicketTest.java | 10 ++++-- .../RandomVerificationCodeProviderTest.java | 3 +- .../festago/domain/StageRepositoryTest.java | 7 ++++ .../java/com/festago/domain/StageTest.java | 3 +- .../com/festago/domain/TicketAmountTest.java | 3 +- .../festago/domain/TicketEntryTimeTest.java | 3 +- .../festago/domain/TicketRepositoryTest.java | 7 ++++ .../java/com/festago/domain/TicketTest.java | 7 +++- .../festago/domain/VerificationCodeTest.java | 3 +- .../dto/FestivalCreateRequestTest.java | 3 +- .../exception/FestaGoExceptionTest.java | 3 ++ .../JwtEntryCodeExtractorTest.java | 7 ++-- .../JwtEntryCodeProviderTest.java | 9 ++--- .../presentation/AdminControllerTest.java | 32 ++++++++--------- .../presentation/FestivalControllerTest.java | 8 ++--- .../presentation/MemberControllerTest.java | 6 ++-- .../MemberTicketControllerTest.java | 22 ++++++------ .../presentation/SchoolControllerTest.java | 6 ++-- .../StaffMemberTicketControllerTest.java | 8 ++--- .../presentation/StageControllerTest.java | 8 ++--- .../presentation/StudentControllerTest.java | 6 ++-- .../com/festago/support/FestivalFixture.java | 2 +- .../com/festago/support/MemberFixture.java | 2 +- .../festago/support/MemberTicketFixture.java | 8 ++--- .../festago/support/MockAuthExtractor.java | 4 +-- .../MockAuthTestExecutionListener.java | 2 +- .../com/festago/support/StageFixture.java | 4 +-- .../com/festago/support/TestAuthConfig.java | 4 +-- .../com/festago/support/TicketFixture.java | 6 ++-- 185 files changed, 738 insertions(+), 632 deletions(-) rename backend/src/main/java/com/festago/{ => admin}/application/AdminService.java (82%) rename backend/src/main/java/com/festago/{auth => admin}/domain/Admin.java (90%) rename backend/src/main/java/com/festago/{ => admin}/dto/AdminFestivalResponse.java (84%) rename backend/src/main/java/com/festago/{ => admin}/dto/AdminResponse.java (86%) rename backend/src/main/java/com/festago/{ => admin}/dto/AdminStageResponse.java (86%) rename backend/src/main/java/com/festago/{ => admin}/dto/AdminTicketResponse.java (77%) rename backend/src/main/java/com/festago/{auth/domain => admin/repository}/AdminRepository.java (77%) create mode 100644 backend/src/main/java/com/festago/auth/application/AuthExtractor.java create mode 100644 backend/src/main/java/com/festago/auth/application/AuthProvider.java create mode 100644 backend/src/main/java/com/festago/auth/application/OAuth2Client.java rename backend/src/main/java/com/festago/auth/{domain => application}/OAuth2Clients.java (86%) rename backend/src/main/java/com/festago/auth/{domain => application}/TokenExtractor.java (81%) delete mode 100644 backend/src/main/java/com/festago/auth/domain/AuthExtractor.java delete mode 100644 backend/src/main/java/com/festago/auth/domain/AuthProvider.java delete mode 100644 backend/src/main/java/com/festago/auth/domain/OAuth2Client.java rename backend/src/main/java/com/festago/{ => common}/aop/LogRequestBody.java (92%) rename backend/src/main/java/com/festago/{ => common}/aop/LogRequestBodyAspect.java (96%) rename backend/src/main/java/com/festago/{ => common}/domain/BaseTimeEntity.java (95%) rename backend/src/main/java/com/festago/{ => common}/exception/BadRequestException.java (79%) rename backend/src/main/java/com/festago/{ => common}/exception/ErrorCode.java (99%) rename backend/src/main/java/com/festago/{ => common}/exception/FestaGoException.java (93%) rename backend/src/main/java/com/festago/{ => common}/exception/ForbiddenException.java (79%) rename backend/src/main/java/com/festago/{ => common}/exception/InternalServerException.java (87%) rename backend/src/main/java/com/festago/{ => common}/exception/NotFoundException.java (79%) rename backend/src/main/java/com/festago/{ => common}/exception/UnauthorizedException.java (80%) rename backend/src/main/java/com/festago/{ => common/exception}/dto/ErrorResponse.java (85%) delete mode 100644 backend/src/main/java/com/festago/domain/EntryCodeExtractor.java delete mode 100644 backend/src/main/java/com/festago/domain/MailClient.java delete mode 100644 backend/src/main/java/com/festago/domain/VerificationCodeProvider.java create mode 100644 backend/src/main/java/com/festago/entry/application/EntryCodeExtractor.java rename backend/src/main/java/com/festago/{ => entry}/application/EntryCodeManager.java (83%) rename backend/src/main/java/com/festago/{domain => entry/application}/EntryCodeProvider.java (60%) rename backend/src/main/java/com/festago/{ => entry}/application/EntryService.java (76%) rename backend/src/main/java/com/festago/{ => entry}/config/EntryCodeConfig.java (69%) rename backend/src/main/java/com/festago/{ => entry}/domain/EntryCode.java (87%) rename backend/src/main/java/com/festago/{ => entry}/domain/EntryCodePayload.java (78%) rename backend/src/main/java/com/festago/{ => entry}/dto/EntryCodeResponse.java (77%) rename backend/src/main/java/com/festago/{ => entry}/dto/TicketValidationRequest.java (84%) rename backend/src/main/java/com/festago/{ => entry}/dto/TicketValidationResponse.java (64%) rename backend/src/main/java/com/festago/{ => entry}/infrastructure/JwtEntryCodeExtractor.java (83%) rename backend/src/main/java/com/festago/{ => entry}/infrastructure/JwtEntryCodeProvider.java (82%) rename backend/src/main/java/com/festago/{ => festival}/application/FestivalService.java (74%) rename backend/src/main/java/com/festago/{ => festival}/domain/Festival.java (94%) rename backend/src/main/java/com/festago/{ => festival}/dto/FestivalCreateRequest.java (89%) rename backend/src/main/java/com/festago/{ => festival}/dto/FestivalDetailResponse.java (86%) rename backend/src/main/java/com/festago/{ => festival}/dto/FestivalDetailStageResponse.java (90%) rename backend/src/main/java/com/festago/{ => festival}/dto/FestivalDetailTicketResponse.java (74%) rename backend/src/main/java/com/festago/{ => festival}/dto/FestivalResponse.java (84%) rename backend/src/main/java/com/festago/{ => festival}/dto/FestivalsResponse.java (84%) rename backend/src/main/java/com/festago/{domain => festival/repository}/FestivalRepository.java (62%) rename backend/src/main/java/com/festago/{ => member}/application/MemberService.java (68%) rename backend/src/main/java/com/festago/{ => member}/domain/Member.java (97%) rename backend/src/main/java/com/festago/{ => member}/dto/MemberProfileResponse.java (79%) rename backend/src/main/java/com/festago/{domain => member/repository}/MemberRepository.java (78%) rename backend/src/main/java/com/festago/{auth => }/presentation/AuthController.java (97%) rename backend/src/main/java/com/festago/{auth/presentation => presentation/auth}/AuthInterceptor.java (90%) rename backend/src/main/java/com/festago/{auth/presentation => presentation/auth}/AuthenticateContext.java (92%) rename backend/src/main/java/com/festago/{auth/presentation => presentation/auth}/RoleArgumentResolver.java (91%) rename backend/src/main/java/com/festago/{auth/presentation => presentation/common}/ErrorFilter.java (96%) rename backend/src/main/java/com/festago/{ => school}/application/SchoolService.java (77%) rename backend/src/main/java/com/festago/{ => school}/domain/School.java (90%) rename backend/src/main/java/com/festago/{ => school}/dto/SchoolResponse.java (79%) rename backend/src/main/java/com/festago/{ => school}/dto/SchoolsResponse.java (85%) rename backend/src/main/java/com/festago/{domain => school/repository}/SchoolRepository.java (63%) rename backend/src/main/java/com/festago/{ => stage}/application/StageService.java (71%) rename backend/src/main/java/com/festago/{ => stage}/domain/Stage.java (93%) rename backend/src/main/java/com/festago/{ => stage}/dto/StageCreateRequest.java (94%) rename backend/src/main/java/com/festago/{ => stage}/dto/StageResponse.java (77%) rename backend/src/main/java/com/festago/{domain => stage/repository}/StageRepository.java (87%) create mode 100644 backend/src/main/java/com/festago/student/application/MailClient.java rename backend/src/main/java/com/festago/{ => student}/application/StudentService.java (78%) create mode 100644 backend/src/main/java/com/festago/student/application/VerificationCodeProvider.java rename backend/src/main/java/com/festago/{ => student}/domain/Student.java (88%) rename backend/src/main/java/com/festago/{ => student}/domain/StudentCode.java (86%) rename backend/src/main/java/com/festago/{ => student}/domain/VerificationCode.java (89%) rename backend/src/main/java/com/festago/{ => student}/domain/VerificationMailPayload.java (84%) rename backend/src/main/java/com/festago/{ => student}/dto/StudentSendMailRequest.java (72%) rename backend/src/main/java/com/festago/{ => student}/dto/StudentVerificateRequest.java (63%) rename backend/src/main/java/com/festago/{ => student}/infrastructure/GoogleMailClient.java (88%) rename backend/src/main/java/com/festago/{ => student}/infrastructure/MockMailClient.java (64%) rename backend/src/main/java/com/festago/{ => student}/infrastructure/RandomVerificationCodeProvider.java (79%) rename backend/src/main/java/com/festago/{domain => student/repository}/StudentCodeRepository.java (62%) rename backend/src/main/java/com/festago/{domain => student/repository}/StudentRepository.java (74%) rename backend/src/main/java/com/festago/{ => ticket}/application/TicketService.java (73%) rename backend/src/main/java/com/festago/{ => ticket}/domain/Ticket.java (93%) rename backend/src/main/java/com/festago/{ => ticket}/domain/TicketAmount.java (87%) rename backend/src/main/java/com/festago/{ => ticket}/domain/TicketEntryTime.java (93%) rename backend/src/main/java/com/festago/{ => ticket}/domain/TicketType.java (63%) rename backend/src/main/java/com/festago/{ => ticket}/dto/StageTicketResponse.java (73%) rename backend/src/main/java/com/festago/{ => ticket}/dto/StageTicketsResponse.java (85%) rename backend/src/main/java/com/festago/{ => ticket}/dto/TicketCreateRequest.java (87%) rename backend/src/main/java/com/festago/{ => ticket}/dto/TicketCreateResponse.java (71%) rename backend/src/main/java/com/festago/{domain => ticket/repository}/TicketAmountRepository.java (87%) rename backend/src/main/java/com/festago/{domain => ticket/repository}/TicketRepository.java (80%) rename backend/src/main/java/com/festago/{ => ticketing}/application/MemberTicketService.java (86%) rename backend/src/main/java/com/festago/{ => ticketing}/application/TicketingService.java (78%) rename backend/src/main/java/com/festago/{ => ticketing}/domain/EntryState.java (83%) rename backend/src/main/java/com/festago/{ => ticketing}/domain/MemberTicket.java (94%) rename backend/src/main/java/com/festago/{ => ticketing}/dto/MemberTicketFestivalResponse.java (80%) rename backend/src/main/java/com/festago/{ => ticketing}/dto/MemberTicketResponse.java (81%) rename backend/src/main/java/com/festago/{ => ticketing}/dto/MemberTicketsResponse.java (84%) rename backend/src/main/java/com/festago/{ => ticketing}/dto/TicketingRequest.java (82%) rename backend/src/main/java/com/festago/{ => ticketing}/dto/TicketingResponse.java (80%) rename backend/src/main/java/com/festago/{domain => ticketing/repository}/MemberTicketRepository.java (67%) diff --git a/backend/src/main/java/com/festago/application/AdminService.java b/backend/src/main/java/com/festago/admin/application/AdminService.java similarity index 82% rename from backend/src/main/java/com/festago/application/AdminService.java rename to backend/src/main/java/com/festago/admin/application/AdminService.java index 20b337d79..6ee9d2de8 100644 --- a/backend/src/main/java/com/festago/application/AdminService.java +++ b/backend/src/main/java/com/festago/admin/application/AdminService.java @@ -1,17 +1,17 @@ -package com.festago.application; +package com.festago.admin.application; -import com.festago.domain.Festival; -import com.festago.domain.FestivalRepository; -import com.festago.domain.Stage; -import com.festago.domain.StageRepository; -import com.festago.domain.Ticket; -import com.festago.domain.TicketAmount; -import com.festago.domain.TicketEntryTime; -import com.festago.domain.TicketRepository; -import com.festago.dto.AdminFestivalResponse; -import com.festago.dto.AdminResponse; -import com.festago.dto.AdminStageResponse; -import com.festago.dto.AdminTicketResponse; +import com.festago.admin.dto.AdminFestivalResponse; +import com.festago.admin.dto.AdminResponse; +import com.festago.admin.dto.AdminStageResponse; +import com.festago.admin.dto.AdminTicketResponse; +import com.festago.festival.domain.Festival; +import com.festago.festival.repository.FestivalRepository; +import com.festago.stage.domain.Stage; +import com.festago.stage.repository.StageRepository; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketAmount; +import com.festago.ticket.domain.TicketEntryTime; +import com.festago.ticket.repository.TicketRepository; import java.time.LocalDateTime; import java.util.List; import java.util.Map; diff --git a/backend/src/main/java/com/festago/auth/domain/Admin.java b/backend/src/main/java/com/festago/admin/domain/Admin.java similarity index 90% rename from backend/src/main/java/com/festago/auth/domain/Admin.java rename to backend/src/main/java/com/festago/admin/domain/Admin.java index 60aec0c40..40e5ca0a4 100644 --- a/backend/src/main/java/com/festago/auth/domain/Admin.java +++ b/backend/src/main/java/com/festago/admin/domain/Admin.java @@ -1,6 +1,6 @@ -package com.festago.auth.domain; +package com.festago.admin.domain; -import com.festago.domain.BaseTimeEntity; +import com.festago.common.domain.BaseTimeEntity; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; diff --git a/backend/src/main/java/com/festago/dto/AdminFestivalResponse.java b/backend/src/main/java/com/festago/admin/dto/AdminFestivalResponse.java similarity index 84% rename from backend/src/main/java/com/festago/dto/AdminFestivalResponse.java rename to backend/src/main/java/com/festago/admin/dto/AdminFestivalResponse.java index 05b0b7e34..ad409142f 100644 --- a/backend/src/main/java/com/festago/dto/AdminFestivalResponse.java +++ b/backend/src/main/java/com/festago/admin/dto/AdminFestivalResponse.java @@ -1,4 +1,4 @@ -package com.festago.dto; +package com.festago.admin.dto; import java.time.LocalDate; diff --git a/backend/src/main/java/com/festago/dto/AdminResponse.java b/backend/src/main/java/com/festago/admin/dto/AdminResponse.java similarity index 86% rename from backend/src/main/java/com/festago/dto/AdminResponse.java rename to backend/src/main/java/com/festago/admin/dto/AdminResponse.java index 1017c3a34..13c6498ab 100644 --- a/backend/src/main/java/com/festago/dto/AdminResponse.java +++ b/backend/src/main/java/com/festago/admin/dto/AdminResponse.java @@ -1,4 +1,4 @@ -package com.festago.dto; +package com.festago.admin.dto; import java.util.List; diff --git a/backend/src/main/java/com/festago/dto/AdminStageResponse.java b/backend/src/main/java/com/festago/admin/dto/AdminStageResponse.java similarity index 86% rename from backend/src/main/java/com/festago/dto/AdminStageResponse.java rename to backend/src/main/java/com/festago/admin/dto/AdminStageResponse.java index 7b5d09742..ab568d4c2 100644 --- a/backend/src/main/java/com/festago/dto/AdminStageResponse.java +++ b/backend/src/main/java/com/festago/admin/dto/AdminStageResponse.java @@ -1,4 +1,4 @@ -package com.festago.dto; +package com.festago.admin.dto; import java.time.LocalDateTime; import java.util.List; diff --git a/backend/src/main/java/com/festago/dto/AdminTicketResponse.java b/backend/src/main/java/com/festago/admin/dto/AdminTicketResponse.java similarity index 77% rename from backend/src/main/java/com/festago/dto/AdminTicketResponse.java rename to backend/src/main/java/com/festago/admin/dto/AdminTicketResponse.java index 9f2cdb3c2..88c93754d 100644 --- a/backend/src/main/java/com/festago/dto/AdminTicketResponse.java +++ b/backend/src/main/java/com/festago/admin/dto/AdminTicketResponse.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.admin.dto; -import com.festago.domain.TicketType; +import com.festago.ticket.domain.TicketType; import java.time.LocalDateTime; import java.util.Map; diff --git a/backend/src/main/java/com/festago/auth/domain/AdminRepository.java b/backend/src/main/java/com/festago/admin/repository/AdminRepository.java similarity index 77% rename from backend/src/main/java/com/festago/auth/domain/AdminRepository.java rename to backend/src/main/java/com/festago/admin/repository/AdminRepository.java index 399ad36d9..6bb333397 100644 --- a/backend/src/main/java/com/festago/auth/domain/AdminRepository.java +++ b/backend/src/main/java/com/festago/admin/repository/AdminRepository.java @@ -1,5 +1,6 @@ -package com.festago.auth.domain; +package com.festago.admin.repository; +import com.festago.admin.domain.Admin; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/backend/src/main/java/com/festago/auth/application/AdminAuthService.java b/backend/src/main/java/com/festago/auth/application/AdminAuthService.java index a5e788238..9d80d2ccd 100644 --- a/backend/src/main/java/com/festago/auth/application/AdminAuthService.java +++ b/backend/src/main/java/com/festago/auth/application/AdminAuthService.java @@ -1,17 +1,16 @@ package com.festago.auth.application; -import com.festago.auth.domain.Admin; -import com.festago.auth.domain.AdminRepository; +import com.festago.admin.domain.Admin; +import com.festago.admin.repository.AdminRepository; import com.festago.auth.domain.AuthPayload; -import com.festago.auth.domain.AuthProvider; import com.festago.auth.domain.Role; import com.festago.auth.dto.AdminLoginRequest; import com.festago.auth.dto.AdminSignupRequest; import com.festago.auth.dto.AdminSignupResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; -import com.festago.exception.ForbiddenException; -import com.festago.exception.UnauthorizedException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.ForbiddenException; +import com.festago.common.exception.UnauthorizedException; import java.util.Objects; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/backend/src/main/java/com/festago/auth/application/AuthExtractor.java b/backend/src/main/java/com/festago/auth/application/AuthExtractor.java new file mode 100644 index 000000000..326ae5121 --- /dev/null +++ b/backend/src/main/java/com/festago/auth/application/AuthExtractor.java @@ -0,0 +1,8 @@ +package com.festago.auth.application; + +import com.festago.auth.domain.AuthPayload; + +public interface AuthExtractor { + + AuthPayload extract(String token); +} diff --git a/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java b/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java index 7f9373f7f..b87ffea85 100644 --- a/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java +++ b/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java @@ -1,9 +1,6 @@ package com.festago.auth.application; import com.festago.auth.domain.AuthPayload; -import com.festago.auth.domain.AuthProvider; -import com.festago.auth.domain.OAuth2Client; -import com.festago.auth.domain.OAuth2Clients; import com.festago.auth.domain.Role; import com.festago.auth.domain.UserInfo; import com.festago.auth.dto.LoginMemberDto; diff --git a/backend/src/main/java/com/festago/auth/application/AuthProvider.java b/backend/src/main/java/com/festago/auth/application/AuthProvider.java new file mode 100644 index 000000000..f4a52c123 --- /dev/null +++ b/backend/src/main/java/com/festago/auth/application/AuthProvider.java @@ -0,0 +1,8 @@ +package com.festago.auth.application; + +import com.festago.auth.domain.AuthPayload; + +public interface AuthProvider { + + String provide(AuthPayload authPayload); +} diff --git a/backend/src/main/java/com/festago/auth/application/AuthService.java b/backend/src/main/java/com/festago/auth/application/AuthService.java index 7f6881a27..6c8b26647 100644 --- a/backend/src/main/java/com/festago/auth/application/AuthService.java +++ b/backend/src/main/java/com/festago/auth/application/AuthService.java @@ -2,10 +2,10 @@ import com.festago.auth.domain.UserInfo; import com.festago.auth.dto.LoginMemberDto; -import com.festago.domain.Member; -import com.festago.domain.MemberRepository; -import com.festago.exception.ErrorCode; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.NotFoundException; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/backend/src/main/java/com/festago/auth/application/OAuth2Client.java b/backend/src/main/java/com/festago/auth/application/OAuth2Client.java new file mode 100644 index 000000000..1e4e1d378 --- /dev/null +++ b/backend/src/main/java/com/festago/auth/application/OAuth2Client.java @@ -0,0 +1,11 @@ +package com.festago.auth.application; + +import com.festago.auth.domain.SocialType; +import com.festago.auth.domain.UserInfo; + +public interface OAuth2Client { + + UserInfo getUserInfo(String accessToken); + + SocialType getSocialType(); +} diff --git a/backend/src/main/java/com/festago/auth/domain/OAuth2Clients.java b/backend/src/main/java/com/festago/auth/application/OAuth2Clients.java similarity index 86% rename from backend/src/main/java/com/festago/auth/domain/OAuth2Clients.java rename to backend/src/main/java/com/festago/auth/application/OAuth2Clients.java index 59e3bc436..7805c57f0 100644 --- a/backend/src/main/java/com/festago/auth/domain/OAuth2Clients.java +++ b/backend/src/main/java/com/festago/auth/application/OAuth2Clients.java @@ -1,8 +1,9 @@ -package com.festago.auth.domain; +package com.festago.auth.application; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.auth.domain.SocialType; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; import java.util.EnumMap; import java.util.List; import java.util.Map; diff --git a/backend/src/main/java/com/festago/auth/domain/TokenExtractor.java b/backend/src/main/java/com/festago/auth/application/TokenExtractor.java similarity index 81% rename from backend/src/main/java/com/festago/auth/domain/TokenExtractor.java rename to backend/src/main/java/com/festago/auth/application/TokenExtractor.java index 004c60bb6..f9396bd9c 100644 --- a/backend/src/main/java/com/festago/auth/domain/TokenExtractor.java +++ b/backend/src/main/java/com/festago/auth/application/TokenExtractor.java @@ -1,4 +1,4 @@ -package com.festago.auth.domain; +package com.festago.auth.application; import jakarta.servlet.http.HttpServletRequest; import java.util.Optional; diff --git a/backend/src/main/java/com/festago/auth/config/AuthConfig.java b/backend/src/main/java/com/festago/auth/config/AuthConfig.java index ef7bd2daf..5912d12b3 100644 --- a/backend/src/main/java/com/festago/auth/config/AuthConfig.java +++ b/backend/src/main/java/com/festago/auth/config/AuthConfig.java @@ -1,9 +1,9 @@ package com.festago.auth.config; -import com.festago.auth.domain.AuthExtractor; -import com.festago.auth.domain.AuthProvider; -import com.festago.auth.domain.OAuth2Client; -import com.festago.auth.domain.OAuth2Clients; +import com.festago.auth.application.AuthExtractor; +import com.festago.auth.application.AuthProvider; +import com.festago.auth.application.OAuth2Client; +import com.festago.auth.application.OAuth2Clients; import com.festago.auth.infrastructure.JwtAuthExtractor; import com.festago.auth.infrastructure.JwtAuthProvider; import java.util.List; diff --git a/backend/src/main/java/com/festago/auth/config/LoginConfig.java b/backend/src/main/java/com/festago/auth/config/LoginConfig.java index 1c0c755be..34715834f 100644 --- a/backend/src/main/java/com/festago/auth/config/LoginConfig.java +++ b/backend/src/main/java/com/festago/auth/config/LoginConfig.java @@ -1,12 +1,12 @@ package com.festago.auth.config; -import com.festago.auth.domain.AuthExtractor; +import com.festago.auth.application.AuthExtractor; import com.festago.auth.domain.Role; import com.festago.auth.infrastructure.CookieTokenExtractor; import com.festago.auth.infrastructure.HeaderTokenExtractor; -import com.festago.auth.presentation.AuthInterceptor; -import com.festago.auth.presentation.AuthenticateContext; -import com.festago.auth.presentation.RoleArgumentResolver; +import com.festago.presentation.auth.AuthInterceptor; +import com.festago.presentation.auth.AuthenticateContext; +import com.festago.presentation.auth.RoleArgumentResolver; import java.util.List; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/backend/src/main/java/com/festago/auth/domain/AuthExtractor.java b/backend/src/main/java/com/festago/auth/domain/AuthExtractor.java deleted file mode 100644 index a8b4bd2d5..000000000 --- a/backend/src/main/java/com/festago/auth/domain/AuthExtractor.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.festago.auth.domain; - -public interface AuthExtractor { - - AuthPayload extract(String token); -} diff --git a/backend/src/main/java/com/festago/auth/domain/AuthPayload.java b/backend/src/main/java/com/festago/auth/domain/AuthPayload.java index 0c8f91b12..1b174f74c 100644 --- a/backend/src/main/java/com/festago/auth/domain/AuthPayload.java +++ b/backend/src/main/java/com/festago/auth/domain/AuthPayload.java @@ -1,7 +1,7 @@ package com.festago.auth.domain; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; public class AuthPayload { diff --git a/backend/src/main/java/com/festago/auth/domain/AuthProvider.java b/backend/src/main/java/com/festago/auth/domain/AuthProvider.java deleted file mode 100644 index 195dc78c2..000000000 --- a/backend/src/main/java/com/festago/auth/domain/AuthProvider.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.festago.auth.domain; - -public interface AuthProvider { - - String provide(AuthPayload authPayload); -} diff --git a/backend/src/main/java/com/festago/auth/domain/OAuth2Client.java b/backend/src/main/java/com/festago/auth/domain/OAuth2Client.java deleted file mode 100644 index 39de5dd4f..000000000 --- a/backend/src/main/java/com/festago/auth/domain/OAuth2Client.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.festago.auth.domain; - -public interface OAuth2Client { - - UserInfo getUserInfo(String accessToken); - - SocialType getSocialType(); -} diff --git a/backend/src/main/java/com/festago/auth/domain/Role.java b/backend/src/main/java/com/festago/auth/domain/Role.java index 28e1924dd..69936580b 100644 --- a/backend/src/main/java/com/festago/auth/domain/Role.java +++ b/backend/src/main/java/com/festago/auth/domain/Role.java @@ -3,8 +3,8 @@ import com.festago.auth.annotation.Admin; import com.festago.auth.annotation.Anonymous; import com.festago.auth.annotation.Member; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; import java.lang.annotation.Annotation; public enum Role { diff --git a/backend/src/main/java/com/festago/auth/domain/UserInfo.java b/backend/src/main/java/com/festago/auth/domain/UserInfo.java index 0d36f66f8..3df1d31be 100644 --- a/backend/src/main/java/com/festago/auth/domain/UserInfo.java +++ b/backend/src/main/java/com/festago/auth/domain/UserInfo.java @@ -1,6 +1,6 @@ package com.festago.auth.domain; -import com.festago.domain.Member; +import com.festago.member.domain.Member; public record UserInfo( String socialId, diff --git a/backend/src/main/java/com/festago/auth/dto/LoginMemberDto.java b/backend/src/main/java/com/festago/auth/dto/LoginMemberDto.java index f331449ab..5a921bffb 100644 --- a/backend/src/main/java/com/festago/auth/dto/LoginMemberDto.java +++ b/backend/src/main/java/com/festago/auth/dto/LoginMemberDto.java @@ -1,6 +1,6 @@ package com.festago.auth.dto; -import com.festago.domain.Member; +import com.festago.member.domain.Member; public record LoginMemberDto( boolean isNew, diff --git a/backend/src/main/java/com/festago/auth/infrastructure/CookieTokenExtractor.java b/backend/src/main/java/com/festago/auth/infrastructure/CookieTokenExtractor.java index 1e8f03a41..e3d490374 100644 --- a/backend/src/main/java/com/festago/auth/infrastructure/CookieTokenExtractor.java +++ b/backend/src/main/java/com/festago/auth/infrastructure/CookieTokenExtractor.java @@ -1,6 +1,6 @@ package com.festago.auth.infrastructure; -import com.festago.auth.domain.TokenExtractor; +import com.festago.auth.application.TokenExtractor; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import java.util.Objects; diff --git a/backend/src/main/java/com/festago/auth/infrastructure/FestagoOAuth2Client.java b/backend/src/main/java/com/festago/auth/infrastructure/FestagoOAuth2Client.java index 2012371f4..b46f74a3a 100644 --- a/backend/src/main/java/com/festago/auth/infrastructure/FestagoOAuth2Client.java +++ b/backend/src/main/java/com/festago/auth/infrastructure/FestagoOAuth2Client.java @@ -1,10 +1,10 @@ package com.festago.auth.infrastructure; -import com.festago.auth.domain.OAuth2Client; +import com.festago.auth.application.OAuth2Client; import com.festago.auth.domain.SocialType; import com.festago.auth.domain.UserInfo; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; diff --git a/backend/src/main/java/com/festago/auth/infrastructure/HeaderTokenExtractor.java b/backend/src/main/java/com/festago/auth/infrastructure/HeaderTokenExtractor.java index f0e4f6b09..f0eab8f78 100644 --- a/backend/src/main/java/com/festago/auth/infrastructure/HeaderTokenExtractor.java +++ b/backend/src/main/java/com/festago/auth/infrastructure/HeaderTokenExtractor.java @@ -1,8 +1,8 @@ package com.festago.auth.infrastructure; -import com.festago.auth.domain.TokenExtractor; -import com.festago.exception.ErrorCode; -import com.festago.exception.UnauthorizedException; +import com.festago.auth.application.TokenExtractor; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.UnauthorizedException; import jakarta.servlet.http.HttpServletRequest; import java.util.Optional; import org.springframework.http.HttpHeaders; diff --git a/backend/src/main/java/com/festago/auth/infrastructure/JwtAuthExtractor.java b/backend/src/main/java/com/festago/auth/infrastructure/JwtAuthExtractor.java index 1ee63953d..5eef34745 100644 --- a/backend/src/main/java/com/festago/auth/infrastructure/JwtAuthExtractor.java +++ b/backend/src/main/java/com/festago/auth/infrastructure/JwtAuthExtractor.java @@ -1,10 +1,10 @@ package com.festago.auth.infrastructure; -import com.festago.auth.domain.AuthExtractor; +import com.festago.auth.application.AuthExtractor; import com.festago.auth.domain.AuthPayload; import com.festago.auth.domain.Role; -import com.festago.exception.ErrorCode; -import com.festago.exception.UnauthorizedException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.UnauthorizedException; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.JwtException; diff --git a/backend/src/main/java/com/festago/auth/infrastructure/JwtAuthProvider.java b/backend/src/main/java/com/festago/auth/infrastructure/JwtAuthProvider.java index 7e06132c3..77ce6bda1 100644 --- a/backend/src/main/java/com/festago/auth/infrastructure/JwtAuthProvider.java +++ b/backend/src/main/java/com/festago/auth/infrastructure/JwtAuthProvider.java @@ -1,7 +1,7 @@ package com.festago.auth.infrastructure; +import com.festago.auth.application.AuthProvider; import com.festago.auth.domain.AuthPayload; -import com.festago.auth.domain.AuthProvider; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; diff --git a/backend/src/main/java/com/festago/auth/infrastructure/KakaoOAuth2Client.java b/backend/src/main/java/com/festago/auth/infrastructure/KakaoOAuth2Client.java index 8a6436b2b..b89eda3c0 100644 --- a/backend/src/main/java/com/festago/auth/infrastructure/KakaoOAuth2Client.java +++ b/backend/src/main/java/com/festago/auth/infrastructure/KakaoOAuth2Client.java @@ -1,6 +1,6 @@ package com.festago.auth.infrastructure; -import com.festago.auth.domain.OAuth2Client; +import com.festago.auth.application.OAuth2Client; import com.festago.auth.domain.SocialType; import com.festago.auth.domain.UserInfo; import org.springframework.stereotype.Component; diff --git a/backend/src/main/java/com/festago/auth/infrastructure/KakaoOAuth2UserInfoErrorHandler.java b/backend/src/main/java/com/festago/auth/infrastructure/KakaoOAuth2UserInfoErrorHandler.java index 4860bc89c..044f4d408 100644 --- a/backend/src/main/java/com/festago/auth/infrastructure/KakaoOAuth2UserInfoErrorHandler.java +++ b/backend/src/main/java/com/festago/auth/infrastructure/KakaoOAuth2UserInfoErrorHandler.java @@ -1,8 +1,8 @@ package com.festago.auth.infrastructure; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; import java.io.IOException; import org.springframework.http.HttpStatusCode; import org.springframework.http.client.ClientHttpResponse; diff --git a/backend/src/main/java/com/festago/aop/LogRequestBody.java b/backend/src/main/java/com/festago/common/aop/LogRequestBody.java similarity index 92% rename from backend/src/main/java/com/festago/aop/LogRequestBody.java rename to backend/src/main/java/com/festago/common/aop/LogRequestBody.java index 005c4d2ae..372190b58 100644 --- a/backend/src/main/java/com/festago/aop/LogRequestBody.java +++ b/backend/src/main/java/com/festago/common/aop/LogRequestBody.java @@ -1,4 +1,4 @@ -package com.festago.aop; +package com.festago.common.aop; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/backend/src/main/java/com/festago/aop/LogRequestBodyAspect.java b/backend/src/main/java/com/festago/common/aop/LogRequestBodyAspect.java similarity index 96% rename from backend/src/main/java/com/festago/aop/LogRequestBodyAspect.java rename to backend/src/main/java/com/festago/common/aop/LogRequestBodyAspect.java index ebb553e4c..e00ad0e9e 100644 --- a/backend/src/main/java/com/festago/aop/LogRequestBodyAspect.java +++ b/backend/src/main/java/com/festago/common/aop/LogRequestBodyAspect.java @@ -1,8 +1,8 @@ -package com.festago.aop; +package com.festago.common.aop; import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.lang.reflect.Method; diff --git a/backend/src/main/java/com/festago/domain/BaseTimeEntity.java b/backend/src/main/java/com/festago/common/domain/BaseTimeEntity.java similarity index 95% rename from backend/src/main/java/com/festago/domain/BaseTimeEntity.java rename to backend/src/main/java/com/festago/common/domain/BaseTimeEntity.java index 82c446193..7a8621f42 100644 --- a/backend/src/main/java/com/festago/domain/BaseTimeEntity.java +++ b/backend/src/main/java/com/festago/common/domain/BaseTimeEntity.java @@ -1,4 +1,4 @@ -package com.festago.domain; +package com.festago.common.domain; import jakarta.persistence.EntityListeners; import jakarta.persistence.MappedSuperclass; diff --git a/backend/src/main/java/com/festago/exception/BadRequestException.java b/backend/src/main/java/com/festago/common/exception/BadRequestException.java similarity index 79% rename from backend/src/main/java/com/festago/exception/BadRequestException.java rename to backend/src/main/java/com/festago/common/exception/BadRequestException.java index 13ac36288..cd4372162 100644 --- a/backend/src/main/java/com/festago/exception/BadRequestException.java +++ b/backend/src/main/java/com/festago/common/exception/BadRequestException.java @@ -1,4 +1,4 @@ -package com.festago.exception; +package com.festago.common.exception; public class BadRequestException extends FestaGoException { diff --git a/backend/src/main/java/com/festago/exception/ErrorCode.java b/backend/src/main/java/com/festago/common/exception/ErrorCode.java similarity index 99% rename from backend/src/main/java/com/festago/exception/ErrorCode.java rename to backend/src/main/java/com/festago/common/exception/ErrorCode.java index bcf1cae53..175e4dca1 100644 --- a/backend/src/main/java/com/festago/exception/ErrorCode.java +++ b/backend/src/main/java/com/festago/common/exception/ErrorCode.java @@ -1,4 +1,4 @@ -package com.festago.exception; +package com.festago.common.exception; public enum ErrorCode { // 400 diff --git a/backend/src/main/java/com/festago/exception/FestaGoException.java b/backend/src/main/java/com/festago/common/exception/FestaGoException.java similarity index 93% rename from backend/src/main/java/com/festago/exception/FestaGoException.java rename to backend/src/main/java/com/festago/common/exception/FestaGoException.java index 1a9ad0fa0..4bbdab694 100644 --- a/backend/src/main/java/com/festago/exception/FestaGoException.java +++ b/backend/src/main/java/com/festago/common/exception/FestaGoException.java @@ -1,4 +1,4 @@ -package com.festago.exception; +package com.festago.common.exception; import org.springframework.core.NestedRuntimeException; diff --git a/backend/src/main/java/com/festago/exception/ForbiddenException.java b/backend/src/main/java/com/festago/common/exception/ForbiddenException.java similarity index 79% rename from backend/src/main/java/com/festago/exception/ForbiddenException.java rename to backend/src/main/java/com/festago/common/exception/ForbiddenException.java index b1b9f400e..e7b08812b 100644 --- a/backend/src/main/java/com/festago/exception/ForbiddenException.java +++ b/backend/src/main/java/com/festago/common/exception/ForbiddenException.java @@ -1,4 +1,4 @@ -package com.festago.exception; +package com.festago.common.exception; public class ForbiddenException extends FestaGoException { diff --git a/backend/src/main/java/com/festago/exception/InternalServerException.java b/backend/src/main/java/com/festago/common/exception/InternalServerException.java similarity index 87% rename from backend/src/main/java/com/festago/exception/InternalServerException.java rename to backend/src/main/java/com/festago/common/exception/InternalServerException.java index d9cf8f4aa..0fbf320f5 100644 --- a/backend/src/main/java/com/festago/exception/InternalServerException.java +++ b/backend/src/main/java/com/festago/common/exception/InternalServerException.java @@ -1,4 +1,4 @@ -package com.festago.exception; +package com.festago.common.exception; public class InternalServerException extends FestaGoException { diff --git a/backend/src/main/java/com/festago/exception/NotFoundException.java b/backend/src/main/java/com/festago/common/exception/NotFoundException.java similarity index 79% rename from backend/src/main/java/com/festago/exception/NotFoundException.java rename to backend/src/main/java/com/festago/common/exception/NotFoundException.java index 6fc8777ca..4600daf49 100644 --- a/backend/src/main/java/com/festago/exception/NotFoundException.java +++ b/backend/src/main/java/com/festago/common/exception/NotFoundException.java @@ -1,4 +1,4 @@ -package com.festago.exception; +package com.festago.common.exception; public class NotFoundException extends FestaGoException { diff --git a/backend/src/main/java/com/festago/exception/UnauthorizedException.java b/backend/src/main/java/com/festago/common/exception/UnauthorizedException.java similarity index 80% rename from backend/src/main/java/com/festago/exception/UnauthorizedException.java rename to backend/src/main/java/com/festago/common/exception/UnauthorizedException.java index 55935b1fd..ffef316c0 100644 --- a/backend/src/main/java/com/festago/exception/UnauthorizedException.java +++ b/backend/src/main/java/com/festago/common/exception/UnauthorizedException.java @@ -1,4 +1,4 @@ -package com.festago.exception; +package com.festago.common.exception; public class UnauthorizedException extends FestaGoException { diff --git a/backend/src/main/java/com/festago/dto/ErrorResponse.java b/backend/src/main/java/com/festago/common/exception/dto/ErrorResponse.java similarity index 85% rename from backend/src/main/java/com/festago/dto/ErrorResponse.java rename to backend/src/main/java/com/festago/common/exception/dto/ErrorResponse.java index cb76fcd0a..7c58f746e 100644 --- a/backend/src/main/java/com/festago/dto/ErrorResponse.java +++ b/backend/src/main/java/com/festago/common/exception/dto/ErrorResponse.java @@ -1,7 +1,7 @@ -package com.festago.dto; +package com.festago.common.exception.dto; -import com.festago.exception.ErrorCode; -import com.festago.exception.FestaGoException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.FestaGoException; import org.springframework.web.bind.MethodArgumentNotValidException; public record ErrorResponse( diff --git a/backend/src/main/java/com/festago/domain/EntryCodeExtractor.java b/backend/src/main/java/com/festago/domain/EntryCodeExtractor.java deleted file mode 100644 index 429df79ad..000000000 --- a/backend/src/main/java/com/festago/domain/EntryCodeExtractor.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.festago.domain; - -public interface EntryCodeExtractor { - - EntryCodePayload extract(String code); -} diff --git a/backend/src/main/java/com/festago/domain/MailClient.java b/backend/src/main/java/com/festago/domain/MailClient.java deleted file mode 100644 index 141c0aa57..000000000 --- a/backend/src/main/java/com/festago/domain/MailClient.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.festago.domain; - -public interface MailClient { - - void send(VerificationMailPayload payload); -} diff --git a/backend/src/main/java/com/festago/domain/VerificationCodeProvider.java b/backend/src/main/java/com/festago/domain/VerificationCodeProvider.java deleted file mode 100644 index eb3b9e6e7..000000000 --- a/backend/src/main/java/com/festago/domain/VerificationCodeProvider.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.festago.domain; - -public interface VerificationCodeProvider { - - VerificationCode provide(); -} diff --git a/backend/src/main/java/com/festago/entry/application/EntryCodeExtractor.java b/backend/src/main/java/com/festago/entry/application/EntryCodeExtractor.java new file mode 100644 index 000000000..89716d035 --- /dev/null +++ b/backend/src/main/java/com/festago/entry/application/EntryCodeExtractor.java @@ -0,0 +1,8 @@ +package com.festago.entry.application; + +import com.festago.entry.domain.EntryCodePayload; + +public interface EntryCodeExtractor { + + EntryCodePayload extract(String code); +} diff --git a/backend/src/main/java/com/festago/application/EntryCodeManager.java b/backend/src/main/java/com/festago/entry/application/EntryCodeManager.java similarity index 83% rename from backend/src/main/java/com/festago/application/EntryCodeManager.java rename to backend/src/main/java/com/festago/entry/application/EntryCodeManager.java index 165e7ea6d..ac6e0d509 100644 --- a/backend/src/main/java/com/festago/application/EntryCodeManager.java +++ b/backend/src/main/java/com/festago/entry/application/EntryCodeManager.java @@ -1,9 +1,7 @@ -package com.festago.application; +package com.festago.entry.application; -import com.festago.domain.EntryCode; -import com.festago.domain.EntryCodeExtractor; -import com.festago.domain.EntryCodePayload; -import com.festago.domain.EntryCodeProvider; +import com.festago.entry.domain.EntryCode; +import com.festago.entry.domain.EntryCodePayload; import java.util.Date; import org.springframework.stereotype.Component; diff --git a/backend/src/main/java/com/festago/domain/EntryCodeProvider.java b/backend/src/main/java/com/festago/entry/application/EntryCodeProvider.java similarity index 60% rename from backend/src/main/java/com/festago/domain/EntryCodeProvider.java rename to backend/src/main/java/com/festago/entry/application/EntryCodeProvider.java index 083bc01c0..1f024f9ec 100644 --- a/backend/src/main/java/com/festago/domain/EntryCodeProvider.java +++ b/backend/src/main/java/com/festago/entry/application/EntryCodeProvider.java @@ -1,5 +1,6 @@ -package com.festago.domain; +package com.festago.entry.application; +import com.festago.entry.domain.EntryCodePayload; import java.util.Date; public interface EntryCodeProvider { diff --git a/backend/src/main/java/com/festago/application/EntryService.java b/backend/src/main/java/com/festago/entry/application/EntryService.java similarity index 76% rename from backend/src/main/java/com/festago/application/EntryService.java rename to backend/src/main/java/com/festago/entry/application/EntryService.java index f0b9ced3a..1e2f23ec3 100644 --- a/backend/src/main/java/com/festago/application/EntryService.java +++ b/backend/src/main/java/com/festago/entry/application/EntryService.java @@ -1,15 +1,15 @@ -package com.festago.application; +package com.festago.entry.application; -import com.festago.domain.EntryCode; -import com.festago.domain.EntryCodePayload; -import com.festago.domain.MemberTicket; -import com.festago.domain.MemberTicketRepository; -import com.festago.dto.EntryCodeResponse; -import com.festago.dto.TicketValidationRequest; -import com.festago.dto.TicketValidationResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.NotFoundException; +import com.festago.entry.domain.EntryCode; +import com.festago.entry.domain.EntryCodePayload; +import com.festago.entry.dto.EntryCodeResponse; +import com.festago.entry.dto.TicketValidationRequest; +import com.festago.entry.dto.TicketValidationResponse; +import com.festago.ticketing.domain.MemberTicket; +import com.festago.ticketing.repository.MemberTicketRepository; import java.time.Clock; import java.time.LocalDateTime; import org.springframework.stereotype.Service; diff --git a/backend/src/main/java/com/festago/config/EntryCodeConfig.java b/backend/src/main/java/com/festago/entry/config/EntryCodeConfig.java similarity index 69% rename from backend/src/main/java/com/festago/config/EntryCodeConfig.java rename to backend/src/main/java/com/festago/entry/config/EntryCodeConfig.java index 924e798b2..bc910c2b5 100644 --- a/backend/src/main/java/com/festago/config/EntryCodeConfig.java +++ b/backend/src/main/java/com/festago/entry/config/EntryCodeConfig.java @@ -1,9 +1,9 @@ -package com.festago.config; +package com.festago.entry.config; -import com.festago.domain.EntryCodeExtractor; -import com.festago.domain.EntryCodeProvider; -import com.festago.infrastructure.JwtEntryCodeExtractor; -import com.festago.infrastructure.JwtEntryCodeProvider; +import com.festago.entry.application.EntryCodeExtractor; +import com.festago.entry.application.EntryCodeProvider; +import com.festago.entry.infrastructure.JwtEntryCodeExtractor; +import com.festago.entry.infrastructure.JwtEntryCodeProvider; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/backend/src/main/java/com/festago/domain/EntryCode.java b/backend/src/main/java/com/festago/entry/domain/EntryCode.java similarity index 87% rename from backend/src/main/java/com/festago/domain/EntryCode.java rename to backend/src/main/java/com/festago/entry/domain/EntryCode.java index 6a433a5f2..c75fde867 100644 --- a/backend/src/main/java/com/festago/domain/EntryCode.java +++ b/backend/src/main/java/com/festago/entry/domain/EntryCode.java @@ -1,7 +1,7 @@ -package com.festago.domain; +package com.festago.entry.domain; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; public class EntryCode { diff --git a/backend/src/main/java/com/festago/domain/EntryCodePayload.java b/backend/src/main/java/com/festago/entry/domain/EntryCodePayload.java similarity index 78% rename from backend/src/main/java/com/festago/domain/EntryCodePayload.java rename to backend/src/main/java/com/festago/entry/domain/EntryCodePayload.java index 51a82e779..38ff7c411 100644 --- a/backend/src/main/java/com/festago/domain/EntryCodePayload.java +++ b/backend/src/main/java/com/festago/entry/domain/EntryCodePayload.java @@ -1,7 +1,9 @@ -package com.festago.domain; +package com.festago.entry.domain; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; +import com.festago.ticketing.domain.EntryState; +import com.festago.ticketing.domain.MemberTicket; public class EntryCodePayload { @@ -14,16 +16,16 @@ public EntryCodePayload(Long memberTicketId, EntryState entryState) { this.entryState = entryState; } + public static EntryCodePayload from(MemberTicket memberTicket) { + return new EntryCodePayload(memberTicket.getId(), memberTicket.getEntryState()); + } + private void validate(Long memberTicketId, EntryState entryState) { if (memberTicketId == null || entryState == null) { throw new InternalServerException(ErrorCode.INVALID_ENTRY_CODE_PAYLOAD); } } - public static EntryCodePayload from(MemberTicket memberTicket) { - return new EntryCodePayload(memberTicket.getId(), memberTicket.getEntryState()); - } - public Long getMemberTicketId() { return memberTicketId; } diff --git a/backend/src/main/java/com/festago/dto/EntryCodeResponse.java b/backend/src/main/java/com/festago/entry/dto/EntryCodeResponse.java similarity index 77% rename from backend/src/main/java/com/festago/dto/EntryCodeResponse.java rename to backend/src/main/java/com/festago/entry/dto/EntryCodeResponse.java index d6ff2d14f..c161502e9 100644 --- a/backend/src/main/java/com/festago/dto/EntryCodeResponse.java +++ b/backend/src/main/java/com/festago/entry/dto/EntryCodeResponse.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.entry.dto; -import com.festago.domain.EntryCode; +import com.festago.entry.domain.EntryCode; public record EntryCodeResponse( String code, diff --git a/backend/src/main/java/com/festago/dto/TicketValidationRequest.java b/backend/src/main/java/com/festago/entry/dto/TicketValidationRequest.java similarity index 84% rename from backend/src/main/java/com/festago/dto/TicketValidationRequest.java rename to backend/src/main/java/com/festago/entry/dto/TicketValidationRequest.java index 03ffeb4cc..e8aeba744 100644 --- a/backend/src/main/java/com/festago/dto/TicketValidationRequest.java +++ b/backend/src/main/java/com/festago/entry/dto/TicketValidationRequest.java @@ -1,4 +1,4 @@ -package com.festago.dto; +package com.festago.entry.dto; import jakarta.validation.constraints.NotNull; diff --git a/backend/src/main/java/com/festago/dto/TicketValidationResponse.java b/backend/src/main/java/com/festago/entry/dto/TicketValidationResponse.java similarity index 64% rename from backend/src/main/java/com/festago/dto/TicketValidationResponse.java rename to backend/src/main/java/com/festago/entry/dto/TicketValidationResponse.java index 5ce421d09..3c5f01175 100644 --- a/backend/src/main/java/com/festago/dto/TicketValidationResponse.java +++ b/backend/src/main/java/com/festago/entry/dto/TicketValidationResponse.java @@ -1,7 +1,7 @@ -package com.festago.dto; +package com.festago.entry.dto; -import com.festago.domain.EntryState; -import com.festago.domain.MemberTicket; +import com.festago.ticketing.domain.EntryState; +import com.festago.ticketing.domain.MemberTicket; public record TicketValidationResponse( EntryState updatedState) { diff --git a/backend/src/main/java/com/festago/infrastructure/JwtEntryCodeExtractor.java b/backend/src/main/java/com/festago/entry/infrastructure/JwtEntryCodeExtractor.java similarity index 83% rename from backend/src/main/java/com/festago/infrastructure/JwtEntryCodeExtractor.java rename to backend/src/main/java/com/festago/entry/infrastructure/JwtEntryCodeExtractor.java index d18de11bf..dbc0bf63c 100644 --- a/backend/src/main/java/com/festago/infrastructure/JwtEntryCodeExtractor.java +++ b/backend/src/main/java/com/festago/entry/infrastructure/JwtEntryCodeExtractor.java @@ -1,10 +1,10 @@ -package com.festago.infrastructure; +package com.festago.entry.infrastructure; -import com.festago.domain.EntryCodeExtractor; -import com.festago.domain.EntryCodePayload; -import com.festago.domain.EntryState; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.entry.application.EntryCodeExtractor; +import com.festago.entry.domain.EntryCodePayload; +import com.festago.ticketing.domain.EntryState; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.JwtException; diff --git a/backend/src/main/java/com/festago/infrastructure/JwtEntryCodeProvider.java b/backend/src/main/java/com/festago/entry/infrastructure/JwtEntryCodeProvider.java similarity index 82% rename from backend/src/main/java/com/festago/infrastructure/JwtEntryCodeProvider.java rename to backend/src/main/java/com/festago/entry/infrastructure/JwtEntryCodeProvider.java index 634fd52a2..852915e6c 100644 --- a/backend/src/main/java/com/festago/infrastructure/JwtEntryCodeProvider.java +++ b/backend/src/main/java/com/festago/entry/infrastructure/JwtEntryCodeProvider.java @@ -1,9 +1,9 @@ -package com.festago.infrastructure; +package com.festago.entry.infrastructure; -import com.festago.domain.EntryCodePayload; -import com.festago.domain.EntryCodeProvider; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; +import com.festago.entry.application.EntryCodeProvider; +import com.festago.entry.domain.EntryCodePayload; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; diff --git a/backend/src/main/java/com/festago/application/FestivalService.java b/backend/src/main/java/com/festago/festival/application/FestivalService.java similarity index 74% rename from backend/src/main/java/com/festago/application/FestivalService.java rename to backend/src/main/java/com/festago/festival/application/FestivalService.java index 6f2f8e855..75e6fdbc5 100644 --- a/backend/src/main/java/com/festago/application/FestivalService.java +++ b/backend/src/main/java/com/festago/festival/application/FestivalService.java @@ -1,18 +1,18 @@ -package com.festago.application; +package com.festago.festival.application; import static java.util.Comparator.comparing; -import com.festago.domain.Festival; -import com.festago.domain.FestivalRepository; -import com.festago.domain.Stage; -import com.festago.domain.StageRepository; -import com.festago.dto.FestivalCreateRequest; -import com.festago.dto.FestivalDetailResponse; -import com.festago.dto.FestivalResponse; -import com.festago.dto.FestivalsResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.NotFoundException; +import com.festago.festival.domain.Festival; +import com.festago.festival.dto.FestivalCreateRequest; +import com.festago.festival.dto.FestivalDetailResponse; +import com.festago.festival.dto.FestivalResponse; +import com.festago.festival.dto.FestivalsResponse; +import com.festago.festival.repository.FestivalRepository; +import com.festago.stage.domain.Stage; +import com.festago.stage.repository.StageRepository; import java.time.LocalDate; import java.util.List; import org.springframework.stereotype.Service; diff --git a/backend/src/main/java/com/festago/domain/Festival.java b/backend/src/main/java/com/festago/festival/domain/Festival.java similarity index 94% rename from backend/src/main/java/com/festago/domain/Festival.java rename to backend/src/main/java/com/festago/festival/domain/Festival.java index 2c72c9460..df2d3c30d 100644 --- a/backend/src/main/java/com/festago/domain/Festival.java +++ b/backend/src/main/java/com/festago/festival/domain/Festival.java @@ -1,7 +1,8 @@ -package com.festago.domain; +package com.festago.festival.domain; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; +import com.festago.common.domain.BaseTimeEntity; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; diff --git a/backend/src/main/java/com/festago/dto/FestivalCreateRequest.java b/backend/src/main/java/com/festago/festival/dto/FestivalCreateRequest.java similarity index 89% rename from backend/src/main/java/com/festago/dto/FestivalCreateRequest.java rename to backend/src/main/java/com/festago/festival/dto/FestivalCreateRequest.java index aac290345..fd908a0f1 100644 --- a/backend/src/main/java/com/festago/dto/FestivalCreateRequest.java +++ b/backend/src/main/java/com/festago/festival/dto/FestivalCreateRequest.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.festival.dto; -import com.festago.domain.Festival; +import com.festago.festival.domain.Festival; import jakarta.validation.constraints.NotNull; import java.time.LocalDate; import org.springframework.format.annotation.DateTimeFormat; diff --git a/backend/src/main/java/com/festago/dto/FestivalDetailResponse.java b/backend/src/main/java/com/festago/festival/dto/FestivalDetailResponse.java similarity index 86% rename from backend/src/main/java/com/festago/dto/FestivalDetailResponse.java rename to backend/src/main/java/com/festago/festival/dto/FestivalDetailResponse.java index d9910e4f4..5ff6d92ea 100644 --- a/backend/src/main/java/com/festago/dto/FestivalDetailResponse.java +++ b/backend/src/main/java/com/festago/festival/dto/FestivalDetailResponse.java @@ -1,7 +1,7 @@ -package com.festago.dto; +package com.festago.festival.dto; -import com.festago.domain.Festival; -import com.festago.domain.Stage; +import com.festago.festival.domain.Festival; +import com.festago.stage.domain.Stage; import java.time.LocalDate; import java.util.List; diff --git a/backend/src/main/java/com/festago/dto/FestivalDetailStageResponse.java b/backend/src/main/java/com/festago/festival/dto/FestivalDetailStageResponse.java similarity index 90% rename from backend/src/main/java/com/festago/dto/FestivalDetailStageResponse.java rename to backend/src/main/java/com/festago/festival/dto/FestivalDetailStageResponse.java index c25aeecbe..e9704cec8 100644 --- a/backend/src/main/java/com/festago/dto/FestivalDetailStageResponse.java +++ b/backend/src/main/java/com/festago/festival/dto/FestivalDetailStageResponse.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.festival.dto; -import com.festago.domain.Stage; +import com.festago.stage.domain.Stage; import java.time.LocalDateTime; import java.util.List; diff --git a/backend/src/main/java/com/festago/dto/FestivalDetailTicketResponse.java b/backend/src/main/java/com/festago/festival/dto/FestivalDetailTicketResponse.java similarity index 74% rename from backend/src/main/java/com/festago/dto/FestivalDetailTicketResponse.java rename to backend/src/main/java/com/festago/festival/dto/FestivalDetailTicketResponse.java index 848ccc865..971042219 100644 --- a/backend/src/main/java/com/festago/dto/FestivalDetailTicketResponse.java +++ b/backend/src/main/java/com/festago/festival/dto/FestivalDetailTicketResponse.java @@ -1,8 +1,8 @@ -package com.festago.dto; +package com.festago.festival.dto; -import com.festago.domain.Ticket; -import com.festago.domain.TicketAmount; -import com.festago.domain.TicketType; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketAmount; +import com.festago.ticket.domain.TicketType; public record FestivalDetailTicketResponse( Long id, diff --git a/backend/src/main/java/com/festago/dto/FestivalResponse.java b/backend/src/main/java/com/festago/festival/dto/FestivalResponse.java similarity index 84% rename from backend/src/main/java/com/festago/dto/FestivalResponse.java rename to backend/src/main/java/com/festago/festival/dto/FestivalResponse.java index 17655e7b7..d59f9ae93 100644 --- a/backend/src/main/java/com/festago/dto/FestivalResponse.java +++ b/backend/src/main/java/com/festago/festival/dto/FestivalResponse.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.festival.dto; -import com.festago.domain.Festival; +import com.festago.festival.domain.Festival; import java.time.LocalDate; public record FestivalResponse( diff --git a/backend/src/main/java/com/festago/dto/FestivalsResponse.java b/backend/src/main/java/com/festago/festival/dto/FestivalsResponse.java similarity index 84% rename from backend/src/main/java/com/festago/dto/FestivalsResponse.java rename to backend/src/main/java/com/festago/festival/dto/FestivalsResponse.java index 37ddd27bf..44b04c1b1 100644 --- a/backend/src/main/java/com/festago/dto/FestivalsResponse.java +++ b/backend/src/main/java/com/festago/festival/dto/FestivalsResponse.java @@ -1,9 +1,9 @@ -package com.festago.dto; +package com.festago.festival.dto; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; -import com.festago.domain.Festival; +import com.festago.festival.domain.Festival; import java.util.List; public record FestivalsResponse( diff --git a/backend/src/main/java/com/festago/domain/FestivalRepository.java b/backend/src/main/java/com/festago/festival/repository/FestivalRepository.java similarity index 62% rename from backend/src/main/java/com/festago/domain/FestivalRepository.java rename to backend/src/main/java/com/festago/festival/repository/FestivalRepository.java index f17005af6..10b3c02c6 100644 --- a/backend/src/main/java/com/festago/domain/FestivalRepository.java +++ b/backend/src/main/java/com/festago/festival/repository/FestivalRepository.java @@ -1,5 +1,6 @@ -package com.festago.domain; +package com.festago.festival.repository; +import com.festago.festival.domain.Festival; import org.springframework.data.jpa.repository.JpaRepository; public interface FestivalRepository extends JpaRepository { diff --git a/backend/src/main/java/com/festago/application/MemberService.java b/backend/src/main/java/com/festago/member/application/MemberService.java similarity index 68% rename from backend/src/main/java/com/festago/application/MemberService.java rename to backend/src/main/java/com/festago/member/application/MemberService.java index d5f094d6f..e9528e803 100644 --- a/backend/src/main/java/com/festago/application/MemberService.java +++ b/backend/src/main/java/com/festago/member/application/MemberService.java @@ -1,10 +1,10 @@ -package com.festago.application; +package com.festago.member.application; -import com.festago.domain.Member; -import com.festago.domain.MemberRepository; -import com.festago.dto.MemberProfileResponse; -import com.festago.exception.ErrorCode; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.NotFoundException; +import com.festago.member.domain.Member; +import com.festago.member.dto.MemberProfileResponse; +import com.festago.member.repository.MemberRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/backend/src/main/java/com/festago/domain/Member.java b/backend/src/main/java/com/festago/member/domain/Member.java similarity index 97% rename from backend/src/main/java/com/festago/domain/Member.java rename to backend/src/main/java/com/festago/member/domain/Member.java index 4b657e6d1..a990a0392 100644 --- a/backend/src/main/java/com/festago/domain/Member.java +++ b/backend/src/main/java/com/festago/member/domain/Member.java @@ -1,6 +1,7 @@ -package com.festago.domain; +package com.festago.member.domain; import com.festago.auth.domain.SocialType; +import com.festago.common.domain.BaseTimeEntity; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; diff --git a/backend/src/main/java/com/festago/dto/MemberProfileResponse.java b/backend/src/main/java/com/festago/member/dto/MemberProfileResponse.java similarity index 79% rename from backend/src/main/java/com/festago/dto/MemberProfileResponse.java rename to backend/src/main/java/com/festago/member/dto/MemberProfileResponse.java index aeec3fb2c..70e30baf7 100644 --- a/backend/src/main/java/com/festago/dto/MemberProfileResponse.java +++ b/backend/src/main/java/com/festago/member/dto/MemberProfileResponse.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.member.dto; -import com.festago.domain.Member; +import com.festago.member.domain.Member; public record MemberProfileResponse( Long memberId, diff --git a/backend/src/main/java/com/festago/domain/MemberRepository.java b/backend/src/main/java/com/festago/member/repository/MemberRepository.java similarity index 78% rename from backend/src/main/java/com/festago/domain/MemberRepository.java rename to backend/src/main/java/com/festago/member/repository/MemberRepository.java index b9cab1507..e9536e0af 100644 --- a/backend/src/main/java/com/festago/domain/MemberRepository.java +++ b/backend/src/main/java/com/festago/member/repository/MemberRepository.java @@ -1,6 +1,7 @@ -package com.festago.domain; +package com.festago.member.repository; import com.festago.auth.domain.SocialType; +import com.festago.member.domain.Member; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/backend/src/main/java/com/festago/presentation/AdminController.java b/backend/src/main/java/com/festago/presentation/AdminController.java index 415066190..19ef5de85 100644 --- a/backend/src/main/java/com/festago/presentation/AdminController.java +++ b/backend/src/main/java/com/festago/presentation/AdminController.java @@ -1,26 +1,26 @@ package com.festago.presentation; -import com.festago.application.AdminService; -import com.festago.application.FestivalService; -import com.festago.application.StageService; -import com.festago.application.TicketService; +import com.festago.admin.application.AdminService; +import com.festago.admin.dto.AdminResponse; import com.festago.auth.annotation.Admin; import com.festago.auth.application.AdminAuthService; import com.festago.auth.dto.AdminLoginRequest; import com.festago.auth.dto.AdminSignupRequest; import com.festago.auth.dto.AdminSignupResponse; import com.festago.auth.dto.RootAdminInitializeRequest; -import com.festago.dto.AdminResponse; -import com.festago.dto.FestivalCreateRequest; -import com.festago.dto.FestivalResponse; -import com.festago.dto.StageCreateRequest; -import com.festago.dto.StageResponse; -import com.festago.dto.TicketCreateRequest; -import com.festago.dto.TicketCreateResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; -import com.festago.exception.UnauthorizedException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; +import com.festago.common.exception.UnauthorizedException; +import com.festago.festival.application.FestivalService; +import com.festago.festival.dto.FestivalCreateRequest; +import com.festago.festival.dto.FestivalResponse; +import com.festago.stage.application.StageService; +import com.festago.stage.dto.StageCreateRequest; +import com.festago.stage.dto.StageResponse; +import com.festago.ticket.application.TicketService; +import com.festago.ticket.dto.TicketCreateRequest; +import com.festago.ticket.dto.TicketCreateResponse; import io.swagger.v3.oas.annotations.Hidden; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; diff --git a/backend/src/main/java/com/festago/auth/presentation/AuthController.java b/backend/src/main/java/com/festago/presentation/AuthController.java similarity index 97% rename from backend/src/main/java/com/festago/auth/presentation/AuthController.java rename to backend/src/main/java/com/festago/presentation/AuthController.java index e703f4197..9d0e83f6f 100644 --- a/backend/src/main/java/com/festago/auth/presentation/AuthController.java +++ b/backend/src/main/java/com/festago/presentation/AuthController.java @@ -1,4 +1,4 @@ -package com.festago.auth.presentation; +package com.festago.presentation; import com.festago.auth.annotation.Member; import com.festago.auth.application.AuthFacadeService; diff --git a/backend/src/main/java/com/festago/presentation/FestivalController.java b/backend/src/main/java/com/festago/presentation/FestivalController.java index bab130bb8..462b0f0b3 100644 --- a/backend/src/main/java/com/festago/presentation/FestivalController.java +++ b/backend/src/main/java/com/festago/presentation/FestivalController.java @@ -1,8 +1,8 @@ package com.festago.presentation; -import com.festago.application.FestivalService; -import com.festago.dto.FestivalDetailResponse; -import com.festago.dto.FestivalsResponse; +import com.festago.festival.application.FestivalService; +import com.festago.festival.dto.FestivalDetailResponse; +import com.festago.festival.dto.FestivalsResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; diff --git a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java index 1df4a7d82..1bc3b023b 100644 --- a/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java +++ b/backend/src/main/java/com/festago/presentation/GlobalExceptionHandler.java @@ -1,20 +1,20 @@ package com.festago.presentation; -import com.festago.auth.presentation.AuthenticateContext; -import com.festago.dto.ErrorResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; -import com.festago.exception.FestaGoException; -import com.festago.exception.ForbiddenException; -import com.festago.exception.InternalServerException; -import com.festago.exception.NotFoundException; -import com.festago.exception.UnauthorizedException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.FestaGoException; +import com.festago.common.exception.ForbiddenException; +import com.festago.common.exception.InternalServerException; +import com.festago.common.exception.NotFoundException; +import com.festago.common.exception.UnauthorizedException; +import com.festago.common.exception.dto.ErrorResponse; +import com.festago.presentation.auth.AuthenticateContext; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; -import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.HttpStatusCode; +import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; diff --git a/backend/src/main/java/com/festago/presentation/MemberController.java b/backend/src/main/java/com/festago/presentation/MemberController.java index 269b2ce51..b27cb3550 100644 --- a/backend/src/main/java/com/festago/presentation/MemberController.java +++ b/backend/src/main/java/com/festago/presentation/MemberController.java @@ -1,8 +1,8 @@ package com.festago.presentation; -import com.festago.application.MemberService; import com.festago.auth.annotation.Member; -import com.festago.dto.MemberProfileResponse; +import com.festago.member.application.MemberService; +import com.festago.member.dto.MemberProfileResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/backend/src/main/java/com/festago/presentation/MemberTicketController.java b/backend/src/main/java/com/festago/presentation/MemberTicketController.java index 1319d954f..2997fb3a6 100644 --- a/backend/src/main/java/com/festago/presentation/MemberTicketController.java +++ b/backend/src/main/java/com/festago/presentation/MemberTicketController.java @@ -1,14 +1,14 @@ package com.festago.presentation; -import com.festago.application.EntryService; -import com.festago.application.MemberTicketService; -import com.festago.application.TicketingService; import com.festago.auth.annotation.Member; -import com.festago.dto.EntryCodeResponse; -import com.festago.dto.MemberTicketResponse; -import com.festago.dto.MemberTicketsResponse; -import com.festago.dto.TicketingRequest; -import com.festago.dto.TicketingResponse; +import com.festago.entry.application.EntryService; +import com.festago.entry.dto.EntryCodeResponse; +import com.festago.ticketing.application.MemberTicketService; +import com.festago.ticketing.application.TicketingService; +import com.festago.ticketing.dto.MemberTicketResponse; +import com.festago.ticketing.dto.MemberTicketsResponse; +import com.festago.ticketing.dto.TicketingRequest; +import com.festago.ticketing.dto.TicketingResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/backend/src/main/java/com/festago/presentation/SchoolController.java b/backend/src/main/java/com/festago/presentation/SchoolController.java index 4f942e162..672d0c0e6 100644 --- a/backend/src/main/java/com/festago/presentation/SchoolController.java +++ b/backend/src/main/java/com/festago/presentation/SchoolController.java @@ -1,7 +1,7 @@ package com.festago.presentation; -import com.festago.application.SchoolService; -import com.festago.dto.SchoolsResponse; +import com.festago.school.application.SchoolService; +import com.festago.school.dto.SchoolsResponse; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java b/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java index cf969b956..be44bda14 100644 --- a/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java +++ b/backend/src/main/java/com/festago/presentation/StaffMemberTicketController.java @@ -1,9 +1,9 @@ package com.festago.presentation; -import com.festago.application.EntryService; -import com.festago.dto.TicketValidationRequest; -import com.festago.dto.TicketValidationResponse; +import com.festago.entry.application.EntryService; +import com.festago.entry.dto.TicketValidationRequest; +import com.festago.entry.dto.TicketValidationResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; diff --git a/backend/src/main/java/com/festago/presentation/StageController.java b/backend/src/main/java/com/festago/presentation/StageController.java index 928a190e3..73b707239 100644 --- a/backend/src/main/java/com/festago/presentation/StageController.java +++ b/backend/src/main/java/com/festago/presentation/StageController.java @@ -1,7 +1,7 @@ package com.festago.presentation; -import com.festago.application.TicketService; -import com.festago.dto.StageTicketsResponse; +import com.festago.ticket.application.TicketService; +import com.festago.ticket.dto.StageTicketsResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; diff --git a/backend/src/main/java/com/festago/presentation/StudentController.java b/backend/src/main/java/com/festago/presentation/StudentController.java index 462c87cb3..d0f397f92 100644 --- a/backend/src/main/java/com/festago/presentation/StudentController.java +++ b/backend/src/main/java/com/festago/presentation/StudentController.java @@ -1,9 +1,9 @@ package com.festago.presentation; -import com.festago.application.StudentService; import com.festago.auth.annotation.Member; -import com.festago.dto.StudentSendMailRequest; -import com.festago.dto.StudentVerificateRequest; +import com.festago.student.application.StudentService; +import com.festago.student.dto.StudentSendMailRequest; +import com.festago.student.dto.StudentVerificateRequest; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; diff --git a/backend/src/main/java/com/festago/auth/presentation/AuthInterceptor.java b/backend/src/main/java/com/festago/presentation/auth/AuthInterceptor.java similarity index 90% rename from backend/src/main/java/com/festago/auth/presentation/AuthInterceptor.java rename to backend/src/main/java/com/festago/presentation/auth/AuthInterceptor.java index 87c401da5..8d4399183 100644 --- a/backend/src/main/java/com/festago/auth/presentation/AuthInterceptor.java +++ b/backend/src/main/java/com/festago/presentation/auth/AuthInterceptor.java @@ -1,12 +1,12 @@ -package com.festago.auth.presentation; +package com.festago.presentation.auth; -import com.festago.auth.domain.AuthExtractor; +import com.festago.auth.application.AuthExtractor; +import com.festago.auth.application.TokenExtractor; import com.festago.auth.domain.AuthPayload; import com.festago.auth.domain.Role; -import com.festago.auth.domain.TokenExtractor; -import com.festago.exception.ErrorCode; -import com.festago.exception.ForbiddenException; -import com.festago.exception.UnauthorizedException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.ForbiddenException; +import com.festago.common.exception.UnauthorizedException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.util.Assert; diff --git a/backend/src/main/java/com/festago/auth/presentation/AuthenticateContext.java b/backend/src/main/java/com/festago/presentation/auth/AuthenticateContext.java similarity index 92% rename from backend/src/main/java/com/festago/auth/presentation/AuthenticateContext.java rename to backend/src/main/java/com/festago/presentation/auth/AuthenticateContext.java index 2edae0e28..5334bf2be 100644 --- a/backend/src/main/java/com/festago/auth/presentation/AuthenticateContext.java +++ b/backend/src/main/java/com/festago/presentation/auth/AuthenticateContext.java @@ -1,4 +1,4 @@ -package com.festago.auth.presentation; +package com.festago.presentation.auth; import com.festago.auth.domain.Role; import org.springframework.stereotype.Component; diff --git a/backend/src/main/java/com/festago/auth/presentation/RoleArgumentResolver.java b/backend/src/main/java/com/festago/presentation/auth/RoleArgumentResolver.java similarity index 91% rename from backend/src/main/java/com/festago/auth/presentation/RoleArgumentResolver.java rename to backend/src/main/java/com/festago/presentation/auth/RoleArgumentResolver.java index 9fd393edb..c48d2c2f9 100644 --- a/backend/src/main/java/com/festago/auth/presentation/RoleArgumentResolver.java +++ b/backend/src/main/java/com/festago/presentation/auth/RoleArgumentResolver.java @@ -1,8 +1,8 @@ -package com.festago.auth.presentation; +package com.festago.presentation.auth; import com.festago.auth.domain.Role; -import com.festago.exception.ErrorCode; -import com.festago.exception.ForbiddenException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.ForbiddenException; import org.springframework.core.MethodParameter; import org.springframework.util.Assert; import org.springframework.web.bind.support.WebDataBinderFactory; diff --git a/backend/src/main/java/com/festago/auth/presentation/ErrorFilter.java b/backend/src/main/java/com/festago/presentation/common/ErrorFilter.java similarity index 96% rename from backend/src/main/java/com/festago/auth/presentation/ErrorFilter.java rename to backend/src/main/java/com/festago/presentation/common/ErrorFilter.java index 8bdb75a0b..c3a2a1218 100644 --- a/backend/src/main/java/com/festago/auth/presentation/ErrorFilter.java +++ b/backend/src/main/java/com/festago/presentation/common/ErrorFilter.java @@ -1,4 +1,4 @@ -package com.festago.auth.presentation; +package com.festago.presentation.common; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; diff --git a/backend/src/main/java/com/festago/application/SchoolService.java b/backend/src/main/java/com/festago/school/application/SchoolService.java similarity index 77% rename from backend/src/main/java/com/festago/application/SchoolService.java rename to backend/src/main/java/com/festago/school/application/SchoolService.java index edb571b4a..1c0220b71 100644 --- a/backend/src/main/java/com/festago/application/SchoolService.java +++ b/backend/src/main/java/com/festago/school/application/SchoolService.java @@ -1,7 +1,7 @@ -package com.festago.application; +package com.festago.school.application; -import com.festago.domain.SchoolRepository; -import com.festago.dto.SchoolsResponse; +import com.festago.school.dto.SchoolsResponse; +import com.festago.school.repository.SchoolRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/backend/src/main/java/com/festago/domain/School.java b/backend/src/main/java/com/festago/school/domain/School.java similarity index 90% rename from backend/src/main/java/com/festago/domain/School.java rename to backend/src/main/java/com/festago/school/domain/School.java index 2275386c3..231a41fca 100644 --- a/backend/src/main/java/com/festago/domain/School.java +++ b/backend/src/main/java/com/festago/school/domain/School.java @@ -1,7 +1,8 @@ -package com.festago.domain; +package com.festago.school.domain; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.domain.BaseTimeEntity; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; diff --git a/backend/src/main/java/com/festago/dto/SchoolResponse.java b/backend/src/main/java/com/festago/school/dto/SchoolResponse.java similarity index 79% rename from backend/src/main/java/com/festago/dto/SchoolResponse.java rename to backend/src/main/java/com/festago/school/dto/SchoolResponse.java index a33a104db..e75e78900 100644 --- a/backend/src/main/java/com/festago/dto/SchoolResponse.java +++ b/backend/src/main/java/com/festago/school/dto/SchoolResponse.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.school.dto; -import com.festago.domain.School; +import com.festago.school.domain.School; public record SchoolResponse( Long id, diff --git a/backend/src/main/java/com/festago/dto/SchoolsResponse.java b/backend/src/main/java/com/festago/school/dto/SchoolsResponse.java similarity index 85% rename from backend/src/main/java/com/festago/dto/SchoolsResponse.java rename to backend/src/main/java/com/festago/school/dto/SchoolsResponse.java index f92e33f9e..129b1f887 100644 --- a/backend/src/main/java/com/festago/dto/SchoolsResponse.java +++ b/backend/src/main/java/com/festago/school/dto/SchoolsResponse.java @@ -1,9 +1,9 @@ -package com.festago.dto; +package com.festago.school.dto; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; -import com.festago.domain.School; +import com.festago.school.domain.School; import java.util.List; public record SchoolsResponse( diff --git a/backend/src/main/java/com/festago/domain/SchoolRepository.java b/backend/src/main/java/com/festago/school/repository/SchoolRepository.java similarity index 63% rename from backend/src/main/java/com/festago/domain/SchoolRepository.java rename to backend/src/main/java/com/festago/school/repository/SchoolRepository.java index 1d5e27222..e733df5c6 100644 --- a/backend/src/main/java/com/festago/domain/SchoolRepository.java +++ b/backend/src/main/java/com/festago/school/repository/SchoolRepository.java @@ -1,5 +1,6 @@ -package com.festago.domain; +package com.festago.school.repository; +import com.festago.school.domain.School; import org.springframework.data.jpa.repository.JpaRepository; public interface SchoolRepository extends JpaRepository { diff --git a/backend/src/main/java/com/festago/application/StageService.java b/backend/src/main/java/com/festago/stage/application/StageService.java similarity index 71% rename from backend/src/main/java/com/festago/application/StageService.java rename to backend/src/main/java/com/festago/stage/application/StageService.java index 98cdf3cae..5198becab 100644 --- a/backend/src/main/java/com/festago/application/StageService.java +++ b/backend/src/main/java/com/festago/stage/application/StageService.java @@ -1,13 +1,13 @@ -package com.festago.application; +package com.festago.stage.application; -import com.festago.domain.Festival; -import com.festago.domain.FestivalRepository; -import com.festago.domain.Stage; -import com.festago.domain.StageRepository; -import com.festago.dto.StageCreateRequest; -import com.festago.dto.StageResponse; -import com.festago.exception.ErrorCode; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.NotFoundException; +import com.festago.festival.domain.Festival; +import com.festago.festival.repository.FestivalRepository; +import com.festago.stage.domain.Stage; +import com.festago.stage.dto.StageCreateRequest; +import com.festago.stage.dto.StageResponse; +import com.festago.stage.repository.StageRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/backend/src/main/java/com/festago/domain/Stage.java b/backend/src/main/java/com/festago/stage/domain/Stage.java similarity index 93% rename from backend/src/main/java/com/festago/domain/Stage.java rename to backend/src/main/java/com/festago/stage/domain/Stage.java index 933475dbd..9faaf2b5e 100644 --- a/backend/src/main/java/com/festago/domain/Stage.java +++ b/backend/src/main/java/com/festago/stage/domain/Stage.java @@ -1,7 +1,10 @@ -package com.festago.domain; +package com.festago.stage.domain; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; +import com.festago.common.domain.BaseTimeEntity; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.festival.domain.Festival; +import com.festago.ticket.domain.Ticket; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; diff --git a/backend/src/main/java/com/festago/dto/StageCreateRequest.java b/backend/src/main/java/com/festago/stage/dto/StageCreateRequest.java similarity index 94% rename from backend/src/main/java/com/festago/dto/StageCreateRequest.java rename to backend/src/main/java/com/festago/stage/dto/StageCreateRequest.java index bb0468c9f..00691a8db 100644 --- a/backend/src/main/java/com/festago/dto/StageCreateRequest.java +++ b/backend/src/main/java/com/festago/stage/dto/StageCreateRequest.java @@ -1,4 +1,4 @@ -package com.festago.dto; +package com.festago.stage.dto; import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; diff --git a/backend/src/main/java/com/festago/dto/StageResponse.java b/backend/src/main/java/com/festago/stage/dto/StageResponse.java similarity index 77% rename from backend/src/main/java/com/festago/dto/StageResponse.java rename to backend/src/main/java/com/festago/stage/dto/StageResponse.java index a2d049e99..1aea96eaa 100644 --- a/backend/src/main/java/com/festago/dto/StageResponse.java +++ b/backend/src/main/java/com/festago/stage/dto/StageResponse.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.stage.dto; -import com.festago.domain.Stage; +import com.festago.stage.domain.Stage; import java.time.LocalDateTime; public record StageResponse( diff --git a/backend/src/main/java/com/festago/domain/StageRepository.java b/backend/src/main/java/com/festago/stage/repository/StageRepository.java similarity index 87% rename from backend/src/main/java/com/festago/domain/StageRepository.java rename to backend/src/main/java/com/festago/stage/repository/StageRepository.java index 6531d7ef4..0956dc2b9 100644 --- a/backend/src/main/java/com/festago/domain/StageRepository.java +++ b/backend/src/main/java/com/festago/stage/repository/StageRepository.java @@ -1,5 +1,6 @@ -package com.festago.domain; +package com.festago.stage.repository; +import com.festago.stage.domain.Stage; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; diff --git a/backend/src/main/java/com/festago/student/application/MailClient.java b/backend/src/main/java/com/festago/student/application/MailClient.java new file mode 100644 index 000000000..29f0ec11c --- /dev/null +++ b/backend/src/main/java/com/festago/student/application/MailClient.java @@ -0,0 +1,8 @@ +package com.festago.student.application; + +import com.festago.student.domain.VerificationMailPayload; + +public interface MailClient { + + void send(VerificationMailPayload payload); +} diff --git a/backend/src/main/java/com/festago/application/StudentService.java b/backend/src/main/java/com/festago/student/application/StudentService.java similarity index 78% rename from backend/src/main/java/com/festago/application/StudentService.java rename to backend/src/main/java/com/festago/student/application/StudentService.java index ea52de469..0ae184eb3 100644 --- a/backend/src/main/java/com/festago/application/StudentService.java +++ b/backend/src/main/java/com/festago/student/application/StudentService.java @@ -1,22 +1,20 @@ -package com.festago.application; +package com.festago.student.application; -import com.festago.domain.MailClient; -import com.festago.domain.Member; -import com.festago.domain.MemberRepository; -import com.festago.domain.School; -import com.festago.domain.SchoolRepository; -import com.festago.domain.Student; -import com.festago.domain.StudentCode; -import com.festago.domain.StudentCodeRepository; -import com.festago.domain.StudentRepository; -import com.festago.domain.VerificationCode; -import com.festago.domain.VerificationCodeProvider; -import com.festago.domain.VerificationMailPayload; -import com.festago.dto.StudentSendMailRequest; -import com.festago.dto.StudentVerificateRequest; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.NotFoundException; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; +import com.festago.school.domain.School; +import com.festago.school.repository.SchoolRepository; +import com.festago.student.domain.Student; +import com.festago.student.domain.StudentCode; +import com.festago.student.domain.VerificationCode; +import com.festago.student.domain.VerificationMailPayload; +import com.festago.student.dto.StudentSendMailRequest; +import com.festago.student.dto.StudentVerificateRequest; +import com.festago.student.repository.StudentCodeRepository; +import com.festago.student.repository.StudentRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/backend/src/main/java/com/festago/student/application/VerificationCodeProvider.java b/backend/src/main/java/com/festago/student/application/VerificationCodeProvider.java new file mode 100644 index 000000000..0538ecc1c --- /dev/null +++ b/backend/src/main/java/com/festago/student/application/VerificationCodeProvider.java @@ -0,0 +1,8 @@ +package com.festago.student.application; + +import com.festago.student.domain.VerificationCode; + +public interface VerificationCodeProvider { + + VerificationCode provide(); +} diff --git a/backend/src/main/java/com/festago/domain/Student.java b/backend/src/main/java/com/festago/student/domain/Student.java similarity index 88% rename from backend/src/main/java/com/festago/domain/Student.java rename to backend/src/main/java/com/festago/student/domain/Student.java index 9e09ad219..2b7b46214 100644 --- a/backend/src/main/java/com/festago/domain/Student.java +++ b/backend/src/main/java/com/festago/student/domain/Student.java @@ -1,7 +1,10 @@ -package com.festago.domain; +package com.festago.student.domain; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.domain.BaseTimeEntity; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; +import com.festago.member.domain.Member; +import com.festago.school.domain.School; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; diff --git a/backend/src/main/java/com/festago/domain/StudentCode.java b/backend/src/main/java/com/festago/student/domain/StudentCode.java similarity index 86% rename from backend/src/main/java/com/festago/domain/StudentCode.java rename to backend/src/main/java/com/festago/student/domain/StudentCode.java index 935f500a2..947e58a61 100644 --- a/backend/src/main/java/com/festago/domain/StudentCode.java +++ b/backend/src/main/java/com/festago/student/domain/StudentCode.java @@ -1,7 +1,10 @@ -package com.festago.domain; +package com.festago.student.domain; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.domain.BaseTimeEntity; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; +import com.festago.member.domain.Member; +import com.festago.school.domain.School; import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; diff --git a/backend/src/main/java/com/festago/domain/VerificationCode.java b/backend/src/main/java/com/festago/student/domain/VerificationCode.java similarity index 89% rename from backend/src/main/java/com/festago/domain/VerificationCode.java rename to backend/src/main/java/com/festago/student/domain/VerificationCode.java index 1220650d7..2236a9b24 100644 --- a/backend/src/main/java/com/festago/domain/VerificationCode.java +++ b/backend/src/main/java/com/festago/student/domain/VerificationCode.java @@ -1,7 +1,7 @@ -package com.festago.domain; +package com.festago.student.domain; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; import java.util.regex.Pattern; @@ -9,9 +9,8 @@ @Embeddable public class VerificationCode { - private static final Pattern POSITIVE_REGEX = Pattern.compile("^\\d+$"); public static final int LENGTH = 6; - + private static final Pattern POSITIVE_REGEX = Pattern.compile("^\\d+$"); @Column(name = "code") private String value; diff --git a/backend/src/main/java/com/festago/domain/VerificationMailPayload.java b/backend/src/main/java/com/festago/student/domain/VerificationMailPayload.java similarity index 84% rename from backend/src/main/java/com/festago/domain/VerificationMailPayload.java rename to backend/src/main/java/com/festago/student/domain/VerificationMailPayload.java index 3ed2fd4fb..e6e159d06 100644 --- a/backend/src/main/java/com/festago/domain/VerificationMailPayload.java +++ b/backend/src/main/java/com/festago/student/domain/VerificationMailPayload.java @@ -1,7 +1,7 @@ -package com.festago.domain; +package com.festago.student.domain; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; public class VerificationMailPayload { diff --git a/backend/src/main/java/com/festago/dto/StudentSendMailRequest.java b/backend/src/main/java/com/festago/student/dto/StudentSendMailRequest.java similarity index 72% rename from backend/src/main/java/com/festago/dto/StudentSendMailRequest.java rename to backend/src/main/java/com/festago/student/dto/StudentSendMailRequest.java index dbf8e8218..f58238144 100644 --- a/backend/src/main/java/com/festago/dto/StudentSendMailRequest.java +++ b/backend/src/main/java/com/festago/student/dto/StudentSendMailRequest.java @@ -1,4 +1,4 @@ -package com.festago.dto; +package com.festago.student.dto; public record StudentSendMailRequest( String username, diff --git a/backend/src/main/java/com/festago/dto/StudentVerificateRequest.java b/backend/src/main/java/com/festago/student/dto/StudentVerificateRequest.java similarity index 63% rename from backend/src/main/java/com/festago/dto/StudentVerificateRequest.java rename to backend/src/main/java/com/festago/student/dto/StudentVerificateRequest.java index 2c22c8ecb..8e9053d1d 100644 --- a/backend/src/main/java/com/festago/dto/StudentVerificateRequest.java +++ b/backend/src/main/java/com/festago/student/dto/StudentVerificateRequest.java @@ -1,4 +1,4 @@ -package com.festago.dto; +package com.festago.student.dto; public record StudentVerificateRequest(String code) { diff --git a/backend/src/main/java/com/festago/infrastructure/GoogleMailClient.java b/backend/src/main/java/com/festago/student/infrastructure/GoogleMailClient.java similarity index 88% rename from backend/src/main/java/com/festago/infrastructure/GoogleMailClient.java rename to backend/src/main/java/com/festago/student/infrastructure/GoogleMailClient.java index 713ba13c2..8fe87e1d9 100644 --- a/backend/src/main/java/com/festago/infrastructure/GoogleMailClient.java +++ b/backend/src/main/java/com/festago/student/infrastructure/GoogleMailClient.java @@ -1,7 +1,7 @@ -package com.festago.infrastructure; +package com.festago.student.infrastructure; -import com.festago.domain.MailClient; -import com.festago.domain.VerificationMailPayload; +import com.festago.student.application.MailClient; +import com.festago.student.domain.VerificationMailPayload; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.mail.MailSender; diff --git a/backend/src/main/java/com/festago/infrastructure/MockMailClient.java b/backend/src/main/java/com/festago/student/infrastructure/MockMailClient.java similarity index 64% rename from backend/src/main/java/com/festago/infrastructure/MockMailClient.java rename to backend/src/main/java/com/festago/student/infrastructure/MockMailClient.java index f4bea068d..5fd9181d9 100644 --- a/backend/src/main/java/com/festago/infrastructure/MockMailClient.java +++ b/backend/src/main/java/com/festago/student/infrastructure/MockMailClient.java @@ -1,7 +1,7 @@ -package com.festago.infrastructure; +package com.festago.student.infrastructure; -import com.festago.domain.MailClient; -import com.festago.domain.VerificationMailPayload; +import com.festago.student.application.MailClient; +import com.festago.student.domain.VerificationMailPayload; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; diff --git a/backend/src/main/java/com/festago/infrastructure/RandomVerificationCodeProvider.java b/backend/src/main/java/com/festago/student/infrastructure/RandomVerificationCodeProvider.java similarity index 79% rename from backend/src/main/java/com/festago/infrastructure/RandomVerificationCodeProvider.java rename to backend/src/main/java/com/festago/student/infrastructure/RandomVerificationCodeProvider.java index fbf1f4451..b40146cb4 100644 --- a/backend/src/main/java/com/festago/infrastructure/RandomVerificationCodeProvider.java +++ b/backend/src/main/java/com/festago/student/infrastructure/RandomVerificationCodeProvider.java @@ -1,10 +1,10 @@ -package com.festago.infrastructure; +package com.festago.student.infrastructure; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.joining; -import com.festago.domain.VerificationCode; -import com.festago.domain.VerificationCodeProvider; +import com.festago.student.application.VerificationCodeProvider; +import com.festago.student.domain.VerificationCode; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; import org.springframework.stereotype.Component; diff --git a/backend/src/main/java/com/festago/domain/StudentCodeRepository.java b/backend/src/main/java/com/festago/student/repository/StudentCodeRepository.java similarity index 62% rename from backend/src/main/java/com/festago/domain/StudentCodeRepository.java rename to backend/src/main/java/com/festago/student/repository/StudentCodeRepository.java index 54c627b1f..6afe6cbd2 100644 --- a/backend/src/main/java/com/festago/domain/StudentCodeRepository.java +++ b/backend/src/main/java/com/festago/student/repository/StudentCodeRepository.java @@ -1,5 +1,8 @@ -package com.festago.domain; +package com.festago.student.repository; +import com.festago.member.domain.Member; +import com.festago.student.domain.StudentCode; +import com.festago.student.domain.VerificationCode; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/backend/src/main/java/com/festago/domain/StudentRepository.java b/backend/src/main/java/com/festago/student/repository/StudentRepository.java similarity index 74% rename from backend/src/main/java/com/festago/domain/StudentRepository.java rename to backend/src/main/java/com/festago/student/repository/StudentRepository.java index ab1cdf49d..43576d299 100644 --- a/backend/src/main/java/com/festago/domain/StudentRepository.java +++ b/backend/src/main/java/com/festago/student/repository/StudentRepository.java @@ -1,5 +1,6 @@ -package com.festago.domain; +package com.festago.student.repository; +import com.festago.student.domain.Student; import org.springframework.data.jpa.repository.JpaRepository; public interface StudentRepository extends JpaRepository { diff --git a/backend/src/main/java/com/festago/application/TicketService.java b/backend/src/main/java/com/festago/ticket/application/TicketService.java similarity index 73% rename from backend/src/main/java/com/festago/application/TicketService.java rename to backend/src/main/java/com/festago/ticket/application/TicketService.java index 6bdc6ddf4..79a8ef17b 100644 --- a/backend/src/main/java/com/festago/application/TicketService.java +++ b/backend/src/main/java/com/festago/ticket/application/TicketService.java @@ -1,15 +1,15 @@ -package com.festago.application; - -import com.festago.domain.Stage; -import com.festago.domain.StageRepository; -import com.festago.domain.Ticket; -import com.festago.domain.TicketRepository; -import com.festago.domain.TicketType; -import com.festago.dto.StageTicketsResponse; -import com.festago.dto.TicketCreateRequest; -import com.festago.dto.TicketCreateResponse; -import com.festago.exception.ErrorCode; -import com.festago.exception.NotFoundException; +package com.festago.ticket.application; + +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.NotFoundException; +import com.festago.stage.domain.Stage; +import com.festago.stage.repository.StageRepository; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketType; +import com.festago.ticket.dto.StageTicketsResponse; +import com.festago.ticket.dto.TicketCreateRequest; +import com.festago.ticket.dto.TicketCreateResponse; +import com.festago.ticket.repository.TicketRepository; import java.time.Clock; import java.time.LocalDateTime; import org.springframework.stereotype.Service; diff --git a/backend/src/main/java/com/festago/domain/Ticket.java b/backend/src/main/java/com/festago/ticket/domain/Ticket.java similarity index 93% rename from backend/src/main/java/com/festago/domain/Ticket.java rename to backend/src/main/java/com/festago/ticket/domain/Ticket.java index 326c2c1bc..5ed3c789d 100644 --- a/backend/src/main/java/com/festago/domain/Ticket.java +++ b/backend/src/main/java/com/festago/ticket/domain/Ticket.java @@ -1,7 +1,11 @@ -package com.festago.domain; - -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; +package com.festago.ticket.domain; + +import com.festago.common.domain.BaseTimeEntity; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.member.domain.Member; +import com.festago.stage.domain.Stage; +import com.festago.ticketing.domain.MemberTicket; import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; diff --git a/backend/src/main/java/com/festago/domain/TicketAmount.java b/backend/src/main/java/com/festago/ticket/domain/TicketAmount.java similarity index 87% rename from backend/src/main/java/com/festago/domain/TicketAmount.java rename to backend/src/main/java/com/festago/ticket/domain/TicketAmount.java index 03d4a91db..b3faa00b6 100644 --- a/backend/src/main/java/com/festago/domain/TicketAmount.java +++ b/backend/src/main/java/com/festago/ticket/domain/TicketAmount.java @@ -1,7 +1,8 @@ -package com.festago.domain; +package com.festago.ticket.domain; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; +import com.festago.common.domain.BaseTimeEntity; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.Id; @@ -27,7 +28,7 @@ public class TicketAmount extends BaseTimeEntity { @JoinColumn(name = "ticket_id") private Ticket ticket; - protected TicketAmount() { + public TicketAmount() { } public TicketAmount(Ticket ticket) { diff --git a/backend/src/main/java/com/festago/domain/TicketEntryTime.java b/backend/src/main/java/com/festago/ticket/domain/TicketEntryTime.java similarity index 93% rename from backend/src/main/java/com/festago/domain/TicketEntryTime.java rename to backend/src/main/java/com/festago/ticket/domain/TicketEntryTime.java index e495a07d4..3a0500f6d 100644 --- a/backend/src/main/java/com/festago/domain/TicketEntryTime.java +++ b/backend/src/main/java/com/festago/ticket/domain/TicketEntryTime.java @@ -1,7 +1,8 @@ -package com.festago.domain; +package com.festago.ticket.domain; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; +import com.festago.common.domain.BaseTimeEntity; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; diff --git a/backend/src/main/java/com/festago/domain/TicketType.java b/backend/src/main/java/com/festago/ticket/domain/TicketType.java similarity index 63% rename from backend/src/main/java/com/festago/domain/TicketType.java rename to backend/src/main/java/com/festago/ticket/domain/TicketType.java index 914350966..42973899b 100644 --- a/backend/src/main/java/com/festago/domain/TicketType.java +++ b/backend/src/main/java/com/festago/ticket/domain/TicketType.java @@ -1,4 +1,4 @@ -package com.festago.domain; +package com.festago.ticket.domain; public enum TicketType { STUDENT, diff --git a/backend/src/main/java/com/festago/dto/StageTicketResponse.java b/backend/src/main/java/com/festago/ticket/dto/StageTicketResponse.java similarity index 73% rename from backend/src/main/java/com/festago/dto/StageTicketResponse.java rename to backend/src/main/java/com/festago/ticket/dto/StageTicketResponse.java index b525f9a08..271a57e9f 100644 --- a/backend/src/main/java/com/festago/dto/StageTicketResponse.java +++ b/backend/src/main/java/com/festago/ticket/dto/StageTicketResponse.java @@ -1,8 +1,8 @@ -package com.festago.dto; +package com.festago.ticket.dto; -import com.festago.domain.Ticket; -import com.festago.domain.TicketAmount; -import com.festago.domain.TicketType; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketAmount; +import com.festago.ticket.domain.TicketType; public record StageTicketResponse( Long id, diff --git a/backend/src/main/java/com/festago/dto/StageTicketsResponse.java b/backend/src/main/java/com/festago/ticket/dto/StageTicketsResponse.java similarity index 85% rename from backend/src/main/java/com/festago/dto/StageTicketsResponse.java rename to backend/src/main/java/com/festago/ticket/dto/StageTicketsResponse.java index 7a184ed02..870d73f85 100644 --- a/backend/src/main/java/com/festago/dto/StageTicketsResponse.java +++ b/backend/src/main/java/com/festago/ticket/dto/StageTicketsResponse.java @@ -1,9 +1,9 @@ -package com.festago.dto; +package com.festago.ticket.dto; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; -import com.festago.domain.Ticket; +import com.festago.ticket.domain.Ticket; import java.util.List; public record StageTicketsResponse( diff --git a/backend/src/main/java/com/festago/dto/TicketCreateRequest.java b/backend/src/main/java/com/festago/ticket/dto/TicketCreateRequest.java similarity index 87% rename from backend/src/main/java/com/festago/dto/TicketCreateRequest.java rename to backend/src/main/java/com/festago/ticket/dto/TicketCreateRequest.java index c90b8e872..823bdca2b 100644 --- a/backend/src/main/java/com/festago/dto/TicketCreateRequest.java +++ b/backend/src/main/java/com/festago/ticket/dto/TicketCreateRequest.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.ticket.dto; -import com.festago.domain.TicketType; +import com.festago.ticket.domain.TicketType; import jakarta.validation.constraints.NotNull; import java.time.LocalDateTime; import org.springframework.format.annotation.DateTimeFormat; diff --git a/backend/src/main/java/com/festago/dto/TicketCreateResponse.java b/backend/src/main/java/com/festago/ticket/dto/TicketCreateResponse.java similarity index 71% rename from backend/src/main/java/com/festago/dto/TicketCreateResponse.java rename to backend/src/main/java/com/festago/ticket/dto/TicketCreateResponse.java index fc06a4450..148114fe6 100644 --- a/backend/src/main/java/com/festago/dto/TicketCreateResponse.java +++ b/backend/src/main/java/com/festago/ticket/dto/TicketCreateResponse.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.ticket.dto; -import com.festago.domain.Ticket; +import com.festago.ticket.domain.Ticket; public record TicketCreateResponse( Long id) { diff --git a/backend/src/main/java/com/festago/domain/TicketAmountRepository.java b/backend/src/main/java/com/festago/ticket/repository/TicketAmountRepository.java similarity index 87% rename from backend/src/main/java/com/festago/domain/TicketAmountRepository.java rename to backend/src/main/java/com/festago/ticket/repository/TicketAmountRepository.java index dca248cfb..0ec6f7b3e 100644 --- a/backend/src/main/java/com/festago/domain/TicketAmountRepository.java +++ b/backend/src/main/java/com/festago/ticket/repository/TicketAmountRepository.java @@ -1,5 +1,6 @@ -package com.festago.domain; +package com.festago.ticket.repository; +import com.festago.ticket.domain.TicketAmount; import jakarta.persistence.LockModeType; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/backend/src/main/java/com/festago/domain/TicketRepository.java b/backend/src/main/java/com/festago/ticket/repository/TicketRepository.java similarity index 80% rename from backend/src/main/java/com/festago/domain/TicketRepository.java rename to backend/src/main/java/com/festago/ticket/repository/TicketRepository.java index 75e7079cf..8c5ab50af 100644 --- a/backend/src/main/java/com/festago/domain/TicketRepository.java +++ b/backend/src/main/java/com/festago/ticket/repository/TicketRepository.java @@ -1,5 +1,8 @@ -package com.festago.domain; +package com.festago.ticket.repository; +import com.festago.stage.domain.Stage; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketType; import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/backend/src/main/java/com/festago/application/MemberTicketService.java b/backend/src/main/java/com/festago/ticketing/application/MemberTicketService.java similarity index 86% rename from backend/src/main/java/com/festago/application/MemberTicketService.java rename to backend/src/main/java/com/festago/ticketing/application/MemberTicketService.java index 050d05f46..ef4b2d0d4 100644 --- a/backend/src/main/java/com/festago/application/MemberTicketService.java +++ b/backend/src/main/java/com/festago/ticketing/application/MemberTicketService.java @@ -1,17 +1,17 @@ -package com.festago.application; +package com.festago.ticketing.application; import static java.util.Comparator.comparing; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; -import com.festago.domain.MemberRepository; -import com.festago.domain.MemberTicket; -import com.festago.domain.MemberTicketRepository; -import com.festago.dto.MemberTicketResponse; -import com.festago.dto.MemberTicketsResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.NotFoundException; +import com.festago.member.repository.MemberRepository; +import com.festago.ticketing.domain.MemberTicket; +import com.festago.ticketing.dto.MemberTicketResponse; +import com.festago.ticketing.dto.MemberTicketsResponse; +import com.festago.ticketing.repository.MemberTicketRepository; import java.time.Clock; import java.time.Duration; import java.time.LocalDateTime; diff --git a/backend/src/main/java/com/festago/application/TicketingService.java b/backend/src/main/java/com/festago/ticketing/application/TicketingService.java similarity index 78% rename from backend/src/main/java/com/festago/application/TicketingService.java rename to backend/src/main/java/com/festago/ticketing/application/TicketingService.java index 2319fb673..81893faf8 100644 --- a/backend/src/main/java/com/festago/application/TicketingService.java +++ b/backend/src/main/java/com/festago/ticketing/application/TicketingService.java @@ -1,18 +1,18 @@ -package com.festago.application; +package com.festago.ticketing.application; -import com.festago.domain.Member; -import com.festago.domain.MemberRepository; -import com.festago.domain.MemberTicket; -import com.festago.domain.MemberTicketRepository; -import com.festago.domain.Ticket; -import com.festago.domain.TicketAmount; -import com.festago.domain.TicketAmountRepository; -import com.festago.domain.TicketRepository; -import com.festago.dto.TicketingRequest; -import com.festago.dto.TicketingResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.ErrorCode; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.NotFoundException; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketAmount; +import com.festago.ticket.repository.TicketAmountRepository; +import com.festago.ticket.repository.TicketRepository; +import com.festago.ticketing.domain.MemberTicket; +import com.festago.ticketing.dto.TicketingRequest; +import com.festago.ticketing.dto.TicketingResponse; +import com.festago.ticketing.repository.MemberTicketRepository; import java.time.Clock; import java.time.LocalDateTime; import org.springframework.stereotype.Service; diff --git a/backend/src/main/java/com/festago/domain/EntryState.java b/backend/src/main/java/com/festago/ticketing/domain/EntryState.java similarity index 83% rename from backend/src/main/java/com/festago/domain/EntryState.java rename to backend/src/main/java/com/festago/ticketing/domain/EntryState.java index 46f6413a0..76c68a288 100644 --- a/backend/src/main/java/com/festago/domain/EntryState.java +++ b/backend/src/main/java/com/festago/ticketing/domain/EntryState.java @@ -1,7 +1,7 @@ -package com.festago.domain; +package com.festago.ticketing.domain; -import com.festago.exception.ErrorCode; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; public enum EntryState { BEFORE_ENTRY(0), diff --git a/backend/src/main/java/com/festago/domain/MemberTicket.java b/backend/src/main/java/com/festago/ticketing/domain/MemberTicket.java similarity index 94% rename from backend/src/main/java/com/festago/domain/MemberTicket.java rename to backend/src/main/java/com/festago/ticketing/domain/MemberTicket.java index ce741075c..cf7a5bc5e 100644 --- a/backend/src/main/java/com/festago/domain/MemberTicket.java +++ b/backend/src/main/java/com/festago/ticketing/domain/MemberTicket.java @@ -1,5 +1,9 @@ -package com.festago.domain; +package com.festago.ticketing.domain; +import com.festago.common.domain.BaseTimeEntity; +import com.festago.member.domain.Member; +import com.festago.stage.domain.Stage; +import com.festago.ticket.domain.TicketType; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; diff --git a/backend/src/main/java/com/festago/dto/MemberTicketFestivalResponse.java b/backend/src/main/java/com/festago/ticketing/dto/MemberTicketFestivalResponse.java similarity index 80% rename from backend/src/main/java/com/festago/dto/MemberTicketFestivalResponse.java rename to backend/src/main/java/com/festago/ticketing/dto/MemberTicketFestivalResponse.java index 45cdbf0b7..0b3779cf0 100644 --- a/backend/src/main/java/com/festago/dto/MemberTicketFestivalResponse.java +++ b/backend/src/main/java/com/festago/ticketing/dto/MemberTicketFestivalResponse.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.ticketing.dto; -import com.festago.domain.Festival; +import com.festago.festival.domain.Festival; public record MemberTicketFestivalResponse( Long id, diff --git a/backend/src/main/java/com/festago/dto/MemberTicketResponse.java b/backend/src/main/java/com/festago/ticketing/dto/MemberTicketResponse.java similarity index 81% rename from backend/src/main/java/com/festago/dto/MemberTicketResponse.java rename to backend/src/main/java/com/festago/ticketing/dto/MemberTicketResponse.java index f90a1004e..bd41105be 100644 --- a/backend/src/main/java/com/festago/dto/MemberTicketResponse.java +++ b/backend/src/main/java/com/festago/ticketing/dto/MemberTicketResponse.java @@ -1,8 +1,9 @@ -package com.festago.dto; +package com.festago.ticketing.dto; -import com.festago.domain.EntryState; -import com.festago.domain.MemberTicket; -import com.festago.domain.Stage; +import com.festago.stage.domain.Stage; +import com.festago.stage.dto.StageResponse; +import com.festago.ticketing.domain.EntryState; +import com.festago.ticketing.domain.MemberTicket; import java.time.LocalDateTime; public record MemberTicketResponse( diff --git a/backend/src/main/java/com/festago/dto/MemberTicketsResponse.java b/backend/src/main/java/com/festago/ticketing/dto/MemberTicketsResponse.java similarity index 84% rename from backend/src/main/java/com/festago/dto/MemberTicketsResponse.java rename to backend/src/main/java/com/festago/ticketing/dto/MemberTicketsResponse.java index 90cd91f58..b06e2aa41 100644 --- a/backend/src/main/java/com/festago/dto/MemberTicketsResponse.java +++ b/backend/src/main/java/com/festago/ticketing/dto/MemberTicketsResponse.java @@ -1,9 +1,9 @@ -package com.festago.dto; +package com.festago.ticketing.dto; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; -import com.festago.domain.MemberTicket; +import com.festago.ticketing.domain.MemberTicket; import java.util.List; public record MemberTicketsResponse( diff --git a/backend/src/main/java/com/festago/dto/TicketingRequest.java b/backend/src/main/java/com/festago/ticketing/dto/TicketingRequest.java similarity index 82% rename from backend/src/main/java/com/festago/dto/TicketingRequest.java rename to backend/src/main/java/com/festago/ticketing/dto/TicketingRequest.java index 0c3bbaba8..a2fe08a38 100644 --- a/backend/src/main/java/com/festago/dto/TicketingRequest.java +++ b/backend/src/main/java/com/festago/ticketing/dto/TicketingRequest.java @@ -1,4 +1,4 @@ -package com.festago.dto; +package com.festago.ticketing.dto; import jakarta.validation.constraints.NotNull; diff --git a/backend/src/main/java/com/festago/dto/TicketingResponse.java b/backend/src/main/java/com/festago/ticketing/dto/TicketingResponse.java similarity index 80% rename from backend/src/main/java/com/festago/dto/TicketingResponse.java rename to backend/src/main/java/com/festago/ticketing/dto/TicketingResponse.java index 0dd10b058..8e3234374 100644 --- a/backend/src/main/java/com/festago/dto/TicketingResponse.java +++ b/backend/src/main/java/com/festago/ticketing/dto/TicketingResponse.java @@ -1,6 +1,6 @@ -package com.festago.dto; +package com.festago.ticketing.dto; -import com.festago.domain.MemberTicket; +import com.festago.ticketing.domain.MemberTicket; import java.time.LocalDateTime; public record TicketingResponse( diff --git a/backend/src/main/java/com/festago/domain/MemberTicketRepository.java b/backend/src/main/java/com/festago/ticketing/repository/MemberTicketRepository.java similarity index 67% rename from backend/src/main/java/com/festago/domain/MemberTicketRepository.java rename to backend/src/main/java/com/festago/ticketing/repository/MemberTicketRepository.java index 547f93c4c..4608b6208 100644 --- a/backend/src/main/java/com/festago/domain/MemberTicketRepository.java +++ b/backend/src/main/java/com/festago/ticketing/repository/MemberTicketRepository.java @@ -1,5 +1,8 @@ -package com.festago.domain; +package com.festago.ticketing.repository; +import com.festago.member.domain.Member; +import com.festago.stage.domain.Stage; +import com.festago.ticketing.domain.MemberTicket; import java.util.List; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/backend/src/test/java/com/festago/application/EntryServiceTest.java b/backend/src/test/java/com/festago/application/EntryServiceTest.java index ea2a7e8cb..962c1a3af 100644 --- a/backend/src/test/java/com/festago/application/EntryServiceTest.java +++ b/backend/src/test/java/com/festago/application/EntryServiceTest.java @@ -7,24 +7,26 @@ import static org.mockito.BDDMockito.anyLong; import static org.mockito.BDDMockito.given; -import com.festago.domain.EntryCode; -import com.festago.domain.EntryCodePayload; -import com.festago.domain.EntryState; -import com.festago.domain.Festival; -import com.festago.domain.Member; -import com.festago.domain.MemberTicket; -import com.festago.domain.MemberTicketRepository; -import com.festago.domain.Stage; -import com.festago.dto.EntryCodeResponse; -import com.festago.dto.TicketValidationRequest; -import com.festago.dto.TicketValidationResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.NotFoundException; +import com.festago.entry.application.EntryCodeManager; +import com.festago.entry.application.EntryService; +import com.festago.entry.domain.EntryCode; +import com.festago.entry.domain.EntryCodePayload; +import com.festago.entry.dto.EntryCodeResponse; +import com.festago.entry.dto.TicketValidationRequest; +import com.festago.entry.dto.TicketValidationResponse; +import com.festago.festival.domain.Festival; +import com.festago.member.domain.Member; +import com.festago.stage.domain.Stage; import com.festago.support.FestivalFixture; import com.festago.support.MemberFixture; import com.festago.support.MemberTicketFixture; import com.festago.support.StageFixture; import com.festago.support.TimeInstantProvider; +import com.festago.ticketing.domain.EntryState; +import com.festago.ticketing.domain.MemberTicket; +import com.festago.ticketing.repository.MemberTicketRepository; import java.time.Clock; import java.time.Instant; import java.time.LocalDateTime; diff --git a/backend/src/test/java/com/festago/application/FestivalServiceTest.java b/backend/src/test/java/com/festago/application/FestivalServiceTest.java index a34a7f3d3..edd5cab95 100644 --- a/backend/src/test/java/com/festago/application/FestivalServiceTest.java +++ b/backend/src/test/java/com/festago/application/FestivalServiceTest.java @@ -5,17 +5,18 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; -import com.festago.domain.Festival; -import com.festago.domain.FestivalRepository; -import com.festago.domain.Stage; -import com.festago.domain.StageRepository; -import com.festago.dto.FestivalCreateRequest; -import com.festago.dto.FestivalDetailResponse; -import com.festago.dto.FestivalDetailStageResponse; -import com.festago.dto.FestivalResponse; -import com.festago.dto.FestivalsResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.NotFoundException; +import com.festago.festival.application.FestivalService; +import com.festago.festival.domain.Festival; +import com.festago.festival.dto.FestivalCreateRequest; +import com.festago.festival.dto.FestivalDetailResponse; +import com.festago.festival.dto.FestivalDetailStageResponse; +import com.festago.festival.dto.FestivalResponse; +import com.festago.festival.dto.FestivalsResponse; +import com.festago.festival.repository.FestivalRepository; +import com.festago.stage.domain.Stage; +import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; import com.festago.support.StageFixture; import java.time.LocalDate; diff --git a/backend/src/test/java/com/festago/application/MemberTicketServiceTest.java b/backend/src/test/java/com/festago/application/MemberTicketServiceTest.java index 591a820c1..4fa00125e 100644 --- a/backend/src/test/java/com/festago/application/MemberTicketServiceTest.java +++ b/backend/src/test/java/com/festago/application/MemberTicketServiceTest.java @@ -7,18 +7,19 @@ import static org.mockito.BDDMockito.anyLong; import static org.mockito.BDDMockito.given; -import com.festago.domain.Member; -import com.festago.domain.MemberRepository; -import com.festago.domain.MemberTicket; -import com.festago.domain.MemberTicketRepository; -import com.festago.domain.Stage; -import com.festago.dto.MemberTicketResponse; -import com.festago.dto.MemberTicketsResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.NotFoundException; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; +import com.festago.stage.domain.Stage; import com.festago.support.MemberFixture; import com.festago.support.MemberTicketFixture; import com.festago.support.StageFixture; +import com.festago.ticketing.application.MemberTicketService; +import com.festago.ticketing.domain.MemberTicket; +import com.festago.ticketing.dto.MemberTicketResponse; +import com.festago.ticketing.dto.MemberTicketsResponse; +import com.festago.ticketing.repository.MemberTicketRepository; import java.time.Clock; import java.time.LocalDateTime; import java.util.List; diff --git a/backend/src/test/java/com/festago/application/StageServiceTest.java b/backend/src/test/java/com/festago/application/StageServiceTest.java index 5ee2c92ea..a2261cd22 100644 --- a/backend/src/test/java/com/festago/application/StageServiceTest.java +++ b/backend/src/test/java/com/festago/application/StageServiceTest.java @@ -5,12 +5,13 @@ import static org.mockito.BDDMockito.anyLong; import static org.mockito.BDDMockito.given; -import com.festago.domain.Festival; -import com.festago.domain.FestivalRepository; -import com.festago.domain.Stage; -import com.festago.domain.StageRepository; -import com.festago.dto.StageCreateRequest; -import com.festago.dto.StageResponse; +import com.festago.festival.domain.Festival; +import com.festago.festival.repository.FestivalRepository; +import com.festago.stage.application.StageService; +import com.festago.stage.domain.Stage; +import com.festago.stage.dto.StageCreateRequest; +import com.festago.stage.dto.StageResponse; +import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; import java.time.LocalDateTime; import java.util.Optional; diff --git a/backend/src/test/java/com/festago/application/StudentServiceTest.java b/backend/src/test/java/com/festago/application/StudentServiceTest.java index 9f5896b20..41e94d388 100644 --- a/backend/src/test/java/com/festago/application/StudentServiceTest.java +++ b/backend/src/test/java/com/festago/application/StudentServiceTest.java @@ -6,20 +6,21 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; -import com.festago.domain.MailClient; -import com.festago.domain.Member; -import com.festago.domain.MemberRepository; -import com.festago.domain.School; -import com.festago.domain.SchoolRepository; -import com.festago.domain.StudentCode; -import com.festago.domain.StudentCodeRepository; -import com.festago.domain.StudentRepository; -import com.festago.domain.VerificationCode; -import com.festago.domain.VerificationCodeProvider; -import com.festago.dto.StudentSendMailRequest; -import com.festago.dto.StudentVerificateRequest; -import com.festago.exception.BadRequestException; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.NotFoundException; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; +import com.festago.school.domain.School; +import com.festago.school.repository.SchoolRepository; +import com.festago.student.application.MailClient; +import com.festago.student.application.StudentService; +import com.festago.student.application.VerificationCodeProvider; +import com.festago.student.domain.StudentCode; +import com.festago.student.domain.VerificationCode; +import com.festago.student.dto.StudentSendMailRequest; +import com.festago.student.dto.StudentVerificateRequest; +import com.festago.student.repository.StudentCodeRepository; +import com.festago.student.repository.StudentRepository; import com.festago.support.MemberFixture; import java.util.Optional; import org.junit.jupiter.api.DisplayNameGeneration; diff --git a/backend/src/test/java/com/festago/application/TicketServiceTest.java b/backend/src/test/java/com/festago/application/TicketServiceTest.java index 7f8095604..cca7c198a 100644 --- a/backend/src/test/java/com/festago/application/TicketServiceTest.java +++ b/backend/src/test/java/com/festago/application/TicketServiceTest.java @@ -3,14 +3,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; -import com.festago.domain.Stage; -import com.festago.domain.Ticket; -import com.festago.domain.TicketRepository; -import com.festago.domain.TicketType; -import com.festago.dto.StageTicketResponse; -import com.festago.dto.StageTicketsResponse; +import com.festago.stage.domain.Stage; import com.festago.support.StageFixture; import com.festago.support.TicketFixture; +import com.festago.ticket.application.TicketService; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketType; +import com.festago.ticket.dto.StageTicketResponse; +import com.festago.ticket.dto.StageTicketsResponse; +import com.festago.ticket.repository.TicketRepository; import java.util.List; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; @@ -27,7 +28,7 @@ class TicketServiceTest { @Mock TicketRepository ticketRepository; - + @InjectMocks TicketService ticketService; diff --git a/backend/src/test/java/com/festago/application/integration/FestivalServiceIntegrationTest.java b/backend/src/test/java/com/festago/application/integration/FestivalServiceIntegrationTest.java index 71f838dfb..7b863ef60 100644 --- a/backend/src/test/java/com/festago/application/integration/FestivalServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/application/integration/FestivalServiceIntegrationTest.java @@ -2,22 +2,22 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.festago.application.FestivalService; -import com.festago.domain.Festival; -import com.festago.domain.FestivalRepository; -import com.festago.domain.Stage; -import com.festago.domain.StageRepository; -import com.festago.domain.Ticket; -import com.festago.domain.TicketRepository; -import com.festago.domain.TicketType; -import com.festago.dto.FestivalCreateRequest; -import com.festago.dto.FestivalDetailResponse; -import com.festago.dto.FestivalDetailStageResponse; -import com.festago.dto.FestivalDetailTicketResponse; -import com.festago.dto.FestivalResponse; +import com.festago.festival.application.FestivalService; +import com.festago.festival.domain.Festival; +import com.festago.festival.dto.FestivalCreateRequest; +import com.festago.festival.dto.FestivalDetailResponse; +import com.festago.festival.dto.FestivalDetailStageResponse; +import com.festago.festival.dto.FestivalDetailTicketResponse; +import com.festago.festival.dto.FestivalResponse; +import com.festago.festival.repository.FestivalRepository; +import com.festago.stage.domain.Stage; +import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; import com.festago.support.StageFixture; import com.festago.support.TicketFixture; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketType; +import com.festago.ticket.repository.TicketRepository; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; diff --git a/backend/src/test/java/com/festago/application/integration/MemberTicketIntegrationTest.java b/backend/src/test/java/com/festago/application/integration/MemberTicketIntegrationTest.java index 4391e4ecb..b4e719f72 100644 --- a/backend/src/test/java/com/festago/application/integration/MemberTicketIntegrationTest.java +++ b/backend/src/test/java/com/festago/application/integration/MemberTicketIntegrationTest.java @@ -2,20 +2,20 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.festago.application.MemberTicketService; -import com.festago.domain.Festival; -import com.festago.domain.FestivalRepository; -import com.festago.domain.Member; -import com.festago.domain.MemberRepository; -import com.festago.domain.MemberTicketRepository; -import com.festago.domain.Stage; -import com.festago.domain.StageRepository; -import com.festago.domain.TicketRepository; -import com.festago.dto.MemberTicketsResponse; +import com.festago.festival.domain.Festival; +import com.festago.festival.repository.FestivalRepository; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; +import com.festago.stage.domain.Stage; +import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; import com.festago.support.MemberFixture; import com.festago.support.MemberTicketFixture; import com.festago.support.StageFixture; +import com.festago.ticket.repository.TicketRepository; +import com.festago.ticketing.application.MemberTicketService; +import com.festago.ticketing.dto.MemberTicketsResponse; +import com.festago.ticketing.repository.MemberTicketRepository; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; diff --git a/backend/src/test/java/com/festago/application/integration/StageServiceIntegrationTest.java b/backend/src/test/java/com/festago/application/integration/StageServiceIntegrationTest.java index f73f37098..25f471e8e 100644 --- a/backend/src/test/java/com/festago/application/integration/StageServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/application/integration/StageServiceIntegrationTest.java @@ -2,10 +2,10 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.festago.application.StageService; -import com.festago.domain.FestivalRepository; -import com.festago.dto.StageCreateRequest; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.NotFoundException; +import com.festago.festival.repository.FestivalRepository; +import com.festago.stage.application.StageService; +import com.festago.stage.dto.StageCreateRequest; import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/application/integration/TicketServiceIntegrationTest.java b/backend/src/test/java/com/festago/application/integration/TicketServiceIntegrationTest.java index 7a5fca505..a0d755858 100644 --- a/backend/src/test/java/com/festago/application/integration/TicketServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/application/integration/TicketServiceIntegrationTest.java @@ -4,20 +4,20 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.doReturn; -import com.festago.application.TicketService; -import com.festago.domain.Festival; -import com.festago.domain.FestivalRepository; -import com.festago.domain.Stage; -import com.festago.domain.StageRepository; -import com.festago.domain.TicketAmount; -import com.festago.domain.TicketAmountRepository; -import com.festago.domain.TicketRepository; -import com.festago.domain.TicketType; -import com.festago.dto.TicketCreateRequest; -import com.festago.dto.TicketCreateResponse; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.NotFoundException; +import com.festago.festival.domain.Festival; +import com.festago.festival.repository.FestivalRepository; +import com.festago.stage.domain.Stage; +import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; import com.festago.support.StageFixture; +import com.festago.ticket.application.TicketService; +import com.festago.ticket.domain.TicketAmount; +import com.festago.ticket.domain.TicketType; +import com.festago.ticket.dto.TicketCreateRequest; +import com.festago.ticket.dto.TicketCreateResponse; +import com.festago.ticket.repository.TicketAmountRepository; +import com.festago.ticket.repository.TicketRepository; import java.time.Clock; import java.time.LocalDateTime; import java.time.ZoneOffset; diff --git a/backend/src/test/java/com/festago/application/integration/TicketingServiceIntegrationTest.java b/backend/src/test/java/com/festago/application/integration/TicketingServiceIntegrationTest.java index 00ecb925a..5b57991bb 100644 --- a/backend/src/test/java/com/festago/application/integration/TicketingServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/application/integration/TicketingServiceIntegrationTest.java @@ -5,14 +5,14 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; -import com.festago.application.TicketingService; -import com.festago.domain.Member; -import com.festago.domain.MemberRepository; -import com.festago.domain.MemberTicketRepository; -import com.festago.domain.Stage; -import com.festago.dto.TicketingRequest; -import com.festago.exception.BadRequestException; +import com.festago.common.exception.BadRequestException; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; +import com.festago.stage.domain.Stage; import com.festago.support.MemberFixture; +import com.festago.ticketing.application.TicketingService; +import com.festago.ticketing.dto.TicketingRequest; +import com.festago.ticketing.repository.MemberTicketRepository; import java.time.Clock; import java.time.Instant; import java.util.List; diff --git a/backend/src/test/java/com/festago/auth/application/AdminAuthFacadeServiceTest.java b/backend/src/test/java/com/festago/auth/application/AdminAuthFacadeServiceTest.java index 99f798a1f..0a232719a 100644 --- a/backend/src/test/java/com/festago/auth/application/AdminAuthFacadeServiceTest.java +++ b/backend/src/test/java/com/festago/auth/application/AdminAuthFacadeServiceTest.java @@ -7,15 +7,14 @@ import static org.mockito.BDDMockito.anyString; import static org.mockito.BDDMockito.given; -import com.festago.auth.domain.Admin; -import com.festago.auth.domain.AdminRepository; -import com.festago.auth.domain.AuthProvider; +import com.festago.admin.domain.Admin; +import com.festago.admin.repository.AdminRepository; import com.festago.auth.dto.AdminLoginRequest; import com.festago.auth.dto.AdminSignupRequest; import com.festago.auth.dto.AdminSignupResponse; -import com.festago.exception.BadRequestException; -import com.festago.exception.ForbiddenException; -import com.festago.exception.UnauthorizedException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.ForbiddenException; +import com.festago.common.exception.UnauthorizedException; import java.util.Optional; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java b/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java index 5c56d1322..e953d8e06 100644 --- a/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java +++ b/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java @@ -6,15 +6,13 @@ import static org.mockito.BDDMockito.mock; import com.festago.auth.domain.AuthPayload; -import com.festago.auth.domain.AuthProvider; -import com.festago.auth.domain.OAuth2Clients; import com.festago.auth.domain.SocialType; import com.festago.auth.domain.UserInfo; import com.festago.auth.dto.LoginMemberDto; import com.festago.auth.dto.LoginRequest; import com.festago.auth.dto.LoginResponse; import com.festago.auth.infrastructure.FestagoOAuth2Client; -import com.festago.domain.Member; +import com.festago.member.domain.Member; import com.festago.support.MemberFixture; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; diff --git a/backend/src/test/java/com/festago/auth/application/AuthServiceTest.java b/backend/src/test/java/com/festago/auth/application/AuthServiceTest.java index c6a0fedc3..e7f30e34b 100644 --- a/backend/src/test/java/com/festago/auth/application/AuthServiceTest.java +++ b/backend/src/test/java/com/festago/auth/application/AuthServiceTest.java @@ -10,9 +10,9 @@ import com.festago.auth.domain.SocialType; import com.festago.auth.domain.UserInfo; import com.festago.auth.dto.LoginMemberDto; -import com.festago.domain.Member; -import com.festago.domain.MemberRepository; -import com.festago.exception.NotFoundException; +import com.festago.common.exception.NotFoundException; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; import com.festago.support.MemberFixture; import java.util.Optional; import org.junit.jupiter.api.DisplayNameGeneration; diff --git a/backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java b/backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java index 1be92b665..0724545a0 100644 --- a/backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java @@ -7,8 +7,8 @@ import com.festago.auth.application.AuthFacadeService; import com.festago.auth.domain.SocialType; import com.festago.auth.dto.LoginRequest; -import com.festago.domain.Member; -import com.festago.domain.MemberRepository; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; import com.festago.support.MemberFixture; import jakarta.persistence.EntityManager; import java.util.List; diff --git a/backend/src/test/java/com/festago/auth/domain/OAuth2ClientsTest.java b/backend/src/test/java/com/festago/auth/domain/OAuth2ClientsTest.java index 58b3d2651..2eadd9f77 100644 --- a/backend/src/test/java/com/festago/auth/domain/OAuth2ClientsTest.java +++ b/backend/src/test/java/com/festago/auth/domain/OAuth2ClientsTest.java @@ -4,12 +4,14 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; -import com.festago.auth.domain.OAuth2Clients.OAuth2ClientsBuilder; +import com.festago.auth.application.OAuth2Client; +import com.festago.auth.application.OAuth2Clients; +import com.festago.auth.application.OAuth2Clients.OAuth2ClientsBuilder; import com.festago.auth.infrastructure.FestagoOAuth2Client; import com.festago.auth.infrastructure.KakaoOAuth2Client; import com.festago.auth.infrastructure.KakaoOAuth2UserInfoClient; -import com.festago.exception.BadRequestException; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.InternalServerException; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; diff --git a/backend/src/test/java/com/festago/auth/infrastructure/HeaderTokenExtractorTest.java b/backend/src/test/java/com/festago/auth/infrastructure/HeaderTokenExtractorTest.java index 0b0804ac9..3f15dc7d2 100644 --- a/backend/src/test/java/com/festago/auth/infrastructure/HeaderTokenExtractorTest.java +++ b/backend/src/test/java/com/festago/auth/infrastructure/HeaderTokenExtractorTest.java @@ -4,7 +4,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.BDDMockito.given; -import com.festago.exception.UnauthorizedException; +import com.festago.common.exception.UnauthorizedException; import jakarta.servlet.http.HttpServletRequest; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/auth/infrastructure/JwtAuthExtractorTest.java b/backend/src/test/java/com/festago/auth/infrastructure/JwtAuthExtractorTest.java index 209ce2558..3be793412 100644 --- a/backend/src/test/java/com/festago/auth/infrastructure/JwtAuthExtractorTest.java +++ b/backend/src/test/java/com/festago/auth/infrastructure/JwtAuthExtractorTest.java @@ -4,8 +4,8 @@ import com.festago.auth.domain.AuthPayload; import com.festago.auth.domain.Role; -import com.festago.exception.InternalServerException; -import com.festago.exception.UnauthorizedException; +import com.festago.common.exception.InternalServerException; +import com.festago.common.exception.UnauthorizedException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; diff --git a/backend/src/test/java/com/festago/auth/infrastructure/KakaoOAuth2UserInfoClientTest.java b/backend/src/test/java/com/festago/auth/infrastructure/KakaoOAuth2UserInfoClientTest.java index e04e0cc6d..d2ef9f418 100644 --- a/backend/src/test/java/com/festago/auth/infrastructure/KakaoOAuth2UserInfoClientTest.java +++ b/backend/src/test/java/com/festago/auth/infrastructure/KakaoOAuth2UserInfoClientTest.java @@ -11,8 +11,8 @@ import com.festago.auth.dto.KakaoUserInfo; import com.festago.auth.dto.KakaoUserInfo.KakaoAccount; import com.festago.auth.dto.KakaoUserInfo.KakaoAccount.Profile; -import com.festago.exception.BadRequestException; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.InternalServerException; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; diff --git a/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java b/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java index 663251e38..281261a03 100644 --- a/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java +++ b/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java @@ -14,6 +14,7 @@ import com.festago.auth.domain.SocialType; import com.festago.auth.dto.LoginRequest; import com.festago.auth.dto.LoginResponse; +import com.festago.presentation.AuthController; import com.festago.support.CustomWebMvcTest; import com.festago.support.WithMockAuth; import org.junit.jupiter.api.DisplayNameGeneration; diff --git a/backend/src/test/java/com/festago/auth/presentation/RoleArgumentResolverTest.java b/backend/src/test/java/com/festago/auth/presentation/RoleArgumentResolverTest.java index ca04824c7..e66c993dd 100644 --- a/backend/src/test/java/com/festago/auth/presentation/RoleArgumentResolverTest.java +++ b/backend/src/test/java/com/festago/auth/presentation/RoleArgumentResolverTest.java @@ -4,7 +4,9 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.festago.auth.domain.Role; -import com.festago.exception.ForbiddenException; +import com.festago.common.exception.ForbiddenException; +import com.festago.presentation.auth.AuthenticateContext; +import com.festago.presentation.auth.RoleArgumentResolver; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/domain/EntryCodeTest.java b/backend/src/test/java/com/festago/domain/EntryCodeTest.java index c7939f962..f8444ca41 100644 --- a/backend/src/test/java/com/festago/domain/EntryCodeTest.java +++ b/backend/src/test/java/com/festago/domain/EntryCodeTest.java @@ -3,7 +3,8 @@ import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.InternalServerException; +import com.festago.entry.domain.EntryCode; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; diff --git a/backend/src/test/java/com/festago/domain/EntryStateTest.java b/backend/src/test/java/com/festago/domain/EntryStateTest.java index e0c6c4602..5060e890d 100644 --- a/backend/src/test/java/com/festago/domain/EntryStateTest.java +++ b/backend/src/test/java/com/festago/domain/EntryStateTest.java @@ -3,7 +3,8 @@ import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.InternalServerException; +import com.festago.ticketing.domain.EntryState; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; diff --git a/backend/src/test/java/com/festago/domain/FestivalTest.java b/backend/src/test/java/com/festago/domain/FestivalTest.java index f2f833b70..98ecd9c57 100644 --- a/backend/src/test/java/com/festago/domain/FestivalTest.java +++ b/backend/src/test/java/com/festago/domain/FestivalTest.java @@ -3,7 +3,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.festago.exception.BadRequestException; +import com.festago.common.exception.BadRequestException; +import com.festago.festival.domain.Festival; import com.festago.support.FestivalFixture; import java.time.LocalDate; import java.time.LocalDateTime; diff --git a/backend/src/test/java/com/festago/domain/MemberRepositoryTest.java b/backend/src/test/java/com/festago/domain/MemberRepositoryTest.java index e5dc68de7..6e6e2e927 100644 --- a/backend/src/test/java/com/festago/domain/MemberRepositoryTest.java +++ b/backend/src/test/java/com/festago/domain/MemberRepositoryTest.java @@ -3,6 +3,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.SoftAssertions.assertSoftly; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; import com.festago.support.MemberFixture; import jakarta.persistence.EntityManager; import org.junit.jupiter.api.DisplayNameGeneration; diff --git a/backend/src/test/java/com/festago/domain/MemberTest.java b/backend/src/test/java/com/festago/domain/MemberTest.java index 74a68c9a1..e88b98641 100644 --- a/backend/src/test/java/com/festago/domain/MemberTest.java +++ b/backend/src/test/java/com/festago/domain/MemberTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.festago.member.domain.Member; import com.festago.support.MemberFixture; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/domain/MemberTicketRepositoryTest.java b/backend/src/test/java/com/festago/domain/MemberTicketRepositoryTest.java index 7a674bad5..0f08a1b2d 100644 --- a/backend/src/test/java/com/festago/domain/MemberTicketRepositoryTest.java +++ b/backend/src/test/java/com/festago/domain/MemberTicketRepositoryTest.java @@ -2,11 +2,21 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.festago.common.domain.BaseTimeEntity; import com.festago.config.JpaAuditingConfig; +import com.festago.festival.domain.Festival; +import com.festago.festival.repository.FestivalRepository; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; +import com.festago.stage.domain.Stage; +import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; import com.festago.support.MemberFixture; import com.festago.support.MemberTicketFixture; import com.festago.support.StageFixture; +import com.festago.ticket.repository.TicketRepository; +import com.festago.ticketing.domain.MemberTicket; +import com.festago.ticketing.repository.MemberTicketRepository; import java.util.ArrayList; import java.util.Comparator; import java.util.List; diff --git a/backend/src/test/java/com/festago/domain/MemberTicketTest.java b/backend/src/test/java/com/festago/domain/MemberTicketTest.java index 3e4ec5a74..9189725ca 100644 --- a/backend/src/test/java/com/festago/domain/MemberTicketTest.java +++ b/backend/src/test/java/com/festago/domain/MemberTicketTest.java @@ -1,13 +1,17 @@ package com.festago.domain; -import static com.festago.domain.EntryState.AFTER_ENTRY; -import static com.festago.domain.EntryState.AWAY; -import static com.festago.domain.EntryState.BEFORE_ENTRY; +import static com.festago.ticketing.domain.EntryState.AFTER_ENTRY; +import static com.festago.ticketing.domain.EntryState.AWAY; +import static com.festago.ticketing.domain.EntryState.BEFORE_ENTRY; import static org.assertj.core.api.Assertions.assertThat; +import com.festago.festival.domain.Festival; +import com.festago.member.domain.Member; +import com.festago.stage.domain.Stage; import com.festago.support.FestivalFixture; import com.festago.support.MemberTicketFixture; import com.festago.support.StageFixture; +import com.festago.ticketing.domain.MemberTicket; import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/domain/RandomVerificationCodeProviderTest.java b/backend/src/test/java/com/festago/domain/RandomVerificationCodeProviderTest.java index 46c413959..1bf3e8a23 100644 --- a/backend/src/test/java/com/festago/domain/RandomVerificationCodeProviderTest.java +++ b/backend/src/test/java/com/festago/domain/RandomVerificationCodeProviderTest.java @@ -2,7 +2,8 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.festago.infrastructure.RandomVerificationCodeProvider; +import com.festago.student.domain.VerificationCode; +import com.festago.student.infrastructure.RandomVerificationCodeProvider; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; diff --git a/backend/src/test/java/com/festago/domain/StageRepositoryTest.java b/backend/src/test/java/com/festago/domain/StageRepositoryTest.java index 05f1014d9..088d15562 100644 --- a/backend/src/test/java/com/festago/domain/StageRepositoryTest.java +++ b/backend/src/test/java/com/festago/domain/StageRepositoryTest.java @@ -3,9 +3,16 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.SoftAssertions.assertSoftly; +import com.festago.festival.domain.Festival; +import com.festago.festival.repository.FestivalRepository; +import com.festago.stage.domain.Stage; +import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; import com.festago.support.StageFixture; import com.festago.support.TicketFixture; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketType; +import com.festago.ticket.repository.TicketRepository; import jakarta.persistence.EntityManager; import java.util.List; import org.junit.jupiter.api.DisplayNameGeneration; diff --git a/backend/src/test/java/com/festago/domain/StageTest.java b/backend/src/test/java/com/festago/domain/StageTest.java index ce788de69..b1873ef1d 100644 --- a/backend/src/test/java/com/festago/domain/StageTest.java +++ b/backend/src/test/java/com/festago/domain/StageTest.java @@ -3,7 +3,8 @@ import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.festago.exception.BadRequestException; +import com.festago.common.exception.BadRequestException; +import com.festago.festival.domain.Festival; import com.festago.support.FestivalFixture; import com.festago.support.StageFixture; import java.time.LocalDateTime; diff --git a/backend/src/test/java/com/festago/domain/TicketAmountTest.java b/backend/src/test/java/com/festago/domain/TicketAmountTest.java index 632263ff9..5260a1889 100644 --- a/backend/src/test/java/com/festago/domain/TicketAmountTest.java +++ b/backend/src/test/java/com/festago/domain/TicketAmountTest.java @@ -2,7 +2,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.festago.exception.BadRequestException; +import com.festago.common.exception.BadRequestException; +import com.festago.ticket.domain.TicketAmount; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; diff --git a/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java b/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java index e1c283290..647042a4f 100644 --- a/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java +++ b/backend/src/test/java/com/festago/domain/TicketEntryTimeTest.java @@ -2,7 +2,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.festago.exception.BadRequestException; +import com.festago.common.exception.BadRequestException; +import com.festago.ticket.domain.TicketEntryTime; import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/domain/TicketRepositoryTest.java b/backend/src/test/java/com/festago/domain/TicketRepositoryTest.java index 4f58ef697..bb92b7494 100644 --- a/backend/src/test/java/com/festago/domain/TicketRepositoryTest.java +++ b/backend/src/test/java/com/festago/domain/TicketRepositoryTest.java @@ -2,9 +2,16 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.festago.festival.domain.Festival; +import com.festago.festival.repository.FestivalRepository; +import com.festago.stage.domain.Stage; +import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; import com.festago.support.StageFixture; import com.festago.support.TicketFixture; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketType; +import com.festago.ticket.repository.TicketRepository; import java.util.List; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/domain/TicketTest.java b/backend/src/test/java/com/festago/domain/TicketTest.java index 476c02d8c..e972aa9d4 100644 --- a/backend/src/test/java/com/festago/domain/TicketTest.java +++ b/backend/src/test/java/com/festago/domain/TicketTest.java @@ -4,11 +4,16 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import static org.assertj.core.api.SoftAssertions.assertSoftly; -import com.festago.exception.BadRequestException; +import com.festago.common.exception.BadRequestException; +import com.festago.festival.domain.Festival; +import com.festago.member.domain.Member; +import com.festago.stage.domain.Stage; import com.festago.support.FestivalFixture; import com.festago.support.MemberFixture; import com.festago.support.StageFixture; import com.festago.support.TicketFixture; +import com.festago.ticket.domain.Ticket; +import com.festago.ticketing.domain.MemberTicket; import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/domain/VerificationCodeTest.java b/backend/src/test/java/com/festago/domain/VerificationCodeTest.java index cfc7e4771..4cccf3fc4 100644 --- a/backend/src/test/java/com/festago/domain/VerificationCodeTest.java +++ b/backend/src/test/java/com/festago/domain/VerificationCodeTest.java @@ -3,7 +3,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.InternalServerException; +import com.festago.student.domain.VerificationCode; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; diff --git a/backend/src/test/java/com/festago/dto/FestivalCreateRequestTest.java b/backend/src/test/java/com/festago/dto/FestivalCreateRequestTest.java index 90212404e..723a5ecb4 100644 --- a/backend/src/test/java/com/festago/dto/FestivalCreateRequestTest.java +++ b/backend/src/test/java/com/festago/dto/FestivalCreateRequestTest.java @@ -2,7 +2,8 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.festago.domain.Festival; +import com.festago.festival.domain.Festival; +import com.festago.festival.dto.FestivalCreateRequest; import java.time.LocalDate; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/exception/FestaGoExceptionTest.java b/backend/src/test/java/com/festago/exception/FestaGoExceptionTest.java index c0c07eeb6..b71a58dea 100644 --- a/backend/src/test/java/com/festago/exception/FestaGoExceptionTest.java +++ b/backend/src/test/java/com/festago/exception/FestaGoExceptionTest.java @@ -2,6 +2,9 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.FestaGoException; +import com.festago.common.exception.InternalServerException; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; import org.junit.jupiter.api.Test; diff --git a/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeExtractorTest.java b/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeExtractorTest.java index da4a31c1b..45fb0f6bf 100644 --- a/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeExtractorTest.java +++ b/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeExtractorTest.java @@ -3,9 +3,10 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.SoftAssertions.assertSoftly; -import com.festago.domain.EntryCodePayload; -import com.festago.exception.BadRequestException; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.BadRequestException; +import com.festago.common.exception.InternalServerException; +import com.festago.entry.domain.EntryCodePayload; +import com.festago.entry.infrastructure.JwtEntryCodeExtractor; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; diff --git a/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeProviderTest.java b/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeProviderTest.java index dc6d4557c..6152092ae 100644 --- a/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeProviderTest.java +++ b/backend/src/test/java/com/festago/infrastructure/JwtEntryCodeProviderTest.java @@ -3,11 +3,12 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.SoftAssertions.assertSoftly; -import com.festago.domain.EntryCodePayload; -import com.festago.domain.EntryCodeProvider; -import com.festago.domain.MemberTicket; -import com.festago.exception.InternalServerException; +import com.festago.common.exception.InternalServerException; +import com.festago.entry.application.EntryCodeProvider; +import com.festago.entry.domain.EntryCodePayload; +import com.festago.entry.infrastructure.JwtEntryCodeProvider; import com.festago.support.MemberTicketFixture; +import com.festago.ticketing.domain.MemberTicket; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import java.util.Date; diff --git a/backend/src/test/java/com/festago/presentation/AdminControllerTest.java b/backend/src/test/java/com/festago/presentation/AdminControllerTest.java index 17137726d..a0fd0f50f 100644 --- a/backend/src/test/java/com/festago/presentation/AdminControllerTest.java +++ b/backend/src/test/java/com/festago/presentation/AdminControllerTest.java @@ -10,26 +10,26 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.application.AdminService; -import com.festago.application.FestivalService; -import com.festago.application.StageService; -import com.festago.application.TicketService; +import com.festago.admin.application.AdminService; import com.festago.auth.application.AdminAuthService; -import com.festago.auth.domain.AuthExtractor; +import com.festago.auth.application.AuthExtractor; import com.festago.auth.domain.Role; -import com.festago.domain.TicketType; -import com.festago.dto.ErrorResponse; -import com.festago.dto.FestivalCreateRequest; -import com.festago.dto.FestivalResponse; -import com.festago.dto.StageCreateRequest; -import com.festago.dto.StageResponse; -import com.festago.dto.TicketCreateRequest; -import com.festago.dto.TicketCreateResponse; -import com.festago.exception.ErrorCode; -import com.festago.exception.NotFoundException; -import com.festago.exception.UnauthorizedException; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.NotFoundException; +import com.festago.common.exception.UnauthorizedException; +import com.festago.common.exception.dto.ErrorResponse; +import com.festago.festival.application.FestivalService; +import com.festago.festival.dto.FestivalCreateRequest; +import com.festago.festival.dto.FestivalResponse; +import com.festago.stage.application.StageService; +import com.festago.stage.dto.StageCreateRequest; +import com.festago.stage.dto.StageResponse; import com.festago.support.CustomWebMvcTest; import com.festago.support.WithMockAuth; +import com.festago.ticket.application.TicketService; +import com.festago.ticket.domain.TicketType; +import com.festago.ticket.dto.TicketCreateRequest; +import com.festago.ticket.dto.TicketCreateResponse; import jakarta.servlet.http.Cookie; import java.nio.charset.StandardCharsets; import java.time.LocalDate; diff --git a/backend/src/test/java/com/festago/presentation/FestivalControllerTest.java b/backend/src/test/java/com/festago/presentation/FestivalControllerTest.java index 4d8a3bc4a..4959c32c6 100644 --- a/backend/src/test/java/com/festago/presentation/FestivalControllerTest.java +++ b/backend/src/test/java/com/festago/presentation/FestivalControllerTest.java @@ -8,10 +8,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.application.FestivalService; -import com.festago.dto.FestivalDetailResponse; -import com.festago.dto.FestivalResponse; -import com.festago.dto.FestivalsResponse; +import com.festago.festival.application.FestivalService; +import com.festago.festival.dto.FestivalDetailResponse; +import com.festago.festival.dto.FestivalResponse; +import com.festago.festival.dto.FestivalsResponse; import com.festago.support.CustomWebMvcTest; import java.nio.charset.StandardCharsets; import java.time.LocalDate; diff --git a/backend/src/test/java/com/festago/presentation/MemberControllerTest.java b/backend/src/test/java/com/festago/presentation/MemberControllerTest.java index b6c8d5ad4..741ac7220 100644 --- a/backend/src/test/java/com/festago/presentation/MemberControllerTest.java +++ b/backend/src/test/java/com/festago/presentation/MemberControllerTest.java @@ -8,11 +8,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.application.MemberService; -import com.festago.application.MemberTicketService; -import com.festago.dto.MemberProfileResponse; +import com.festago.member.application.MemberService; +import com.festago.member.dto.MemberProfileResponse; import com.festago.support.CustomWebMvcTest; import com.festago.support.WithMockAuth; +import com.festago.ticketing.application.MemberTicketService; import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/presentation/MemberTicketControllerTest.java b/backend/src/test/java/com/festago/presentation/MemberTicketControllerTest.java index c0a933f49..bcdd823f6 100644 --- a/backend/src/test/java/com/festago/presentation/MemberTicketControllerTest.java +++ b/backend/src/test/java/com/festago/presentation/MemberTicketControllerTest.java @@ -13,19 +13,19 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.application.EntryService; -import com.festago.application.MemberTicketService; -import com.festago.application.TicketingService; -import com.festago.domain.EntryState; -import com.festago.dto.EntryCodeResponse; -import com.festago.dto.MemberTicketFestivalResponse; -import com.festago.dto.MemberTicketResponse; -import com.festago.dto.MemberTicketsResponse; -import com.festago.dto.StageResponse; -import com.festago.dto.TicketingRequest; -import com.festago.dto.TicketingResponse; +import com.festago.entry.application.EntryService; +import com.festago.entry.dto.EntryCodeResponse; +import com.festago.stage.dto.StageResponse; import com.festago.support.CustomWebMvcTest; import com.festago.support.WithMockAuth; +import com.festago.ticketing.application.MemberTicketService; +import com.festago.ticketing.application.TicketingService; +import com.festago.ticketing.domain.EntryState; +import com.festago.ticketing.dto.MemberTicketFestivalResponse; +import com.festago.ticketing.dto.MemberTicketResponse; +import com.festago.ticketing.dto.MemberTicketsResponse; +import com.festago.ticketing.dto.TicketingRequest; +import com.festago.ticketing.dto.TicketingResponse; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.stream.LongStream; diff --git a/backend/src/test/java/com/festago/presentation/SchoolControllerTest.java b/backend/src/test/java/com/festago/presentation/SchoolControllerTest.java index f9584d02c..c92297567 100644 --- a/backend/src/test/java/com/festago/presentation/SchoolControllerTest.java +++ b/backend/src/test/java/com/festago/presentation/SchoolControllerTest.java @@ -7,9 +7,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.application.SchoolService; -import com.festago.dto.SchoolResponse; -import com.festago.dto.SchoolsResponse; +import com.festago.school.application.SchoolService; +import com.festago.school.dto.SchoolResponse; +import com.festago.school.dto.SchoolsResponse; import com.festago.support.CustomWebMvcTest; import java.nio.charset.StandardCharsets; import java.util.List; diff --git a/backend/src/test/java/com/festago/presentation/StaffMemberTicketControllerTest.java b/backend/src/test/java/com/festago/presentation/StaffMemberTicketControllerTest.java index b36df0ebe..0bcdd1a26 100644 --- a/backend/src/test/java/com/festago/presentation/StaffMemberTicketControllerTest.java +++ b/backend/src/test/java/com/festago/presentation/StaffMemberTicketControllerTest.java @@ -7,11 +7,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.application.EntryService; -import com.festago.domain.EntryState; -import com.festago.dto.TicketValidationRequest; -import com.festago.dto.TicketValidationResponse; +import com.festago.entry.application.EntryService; +import com.festago.entry.dto.TicketValidationRequest; +import com.festago.entry.dto.TicketValidationResponse; import com.festago.support.CustomWebMvcTest; +import com.festago.ticketing.domain.EntryState; import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; diff --git a/backend/src/test/java/com/festago/presentation/StageControllerTest.java b/backend/src/test/java/com/festago/presentation/StageControllerTest.java index 90499dc8e..341f584a4 100644 --- a/backend/src/test/java/com/festago/presentation/StageControllerTest.java +++ b/backend/src/test/java/com/festago/presentation/StageControllerTest.java @@ -8,11 +8,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.application.TicketService; -import com.festago.domain.TicketType; -import com.festago.dto.StageTicketResponse; -import com.festago.dto.StageTicketsResponse; import com.festago.support.CustomWebMvcTest; +import com.festago.ticket.application.TicketService; +import com.festago.ticket.domain.TicketType; +import com.festago.ticket.dto.StageTicketResponse; +import com.festago.ticket.dto.StageTicketsResponse; import java.nio.charset.StandardCharsets; import java.util.List; import org.junit.jupiter.api.DisplayNameGeneration; diff --git a/backend/src/test/java/com/festago/presentation/StudentControllerTest.java b/backend/src/test/java/com/festago/presentation/StudentControllerTest.java index 19322565d..541d79f40 100644 --- a/backend/src/test/java/com/festago/presentation/StudentControllerTest.java +++ b/backend/src/test/java/com/festago/presentation/StudentControllerTest.java @@ -4,9 +4,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import com.festago.application.StudentService; -import com.festago.dto.StudentSendMailRequest; -import com.festago.dto.StudentVerificateRequest; +import com.festago.student.application.StudentService; +import com.festago.student.dto.StudentSendMailRequest; +import com.festago.student.dto.StudentVerificateRequest; import com.festago.support.CustomWebMvcTest; import com.festago.support.WithMockAuth; import org.junit.jupiter.api.DisplayNameGeneration; diff --git a/backend/src/test/java/com/festago/support/FestivalFixture.java b/backend/src/test/java/com/festago/support/FestivalFixture.java index aa92fae0f..39693181d 100644 --- a/backend/src/test/java/com/festago/support/FestivalFixture.java +++ b/backend/src/test/java/com/festago/support/FestivalFixture.java @@ -1,6 +1,6 @@ package com.festago.support; -import com.festago.domain.Festival; +import com.festago.festival.domain.Festival; import java.time.LocalDate; public class FestivalFixture { diff --git a/backend/src/test/java/com/festago/support/MemberFixture.java b/backend/src/test/java/com/festago/support/MemberFixture.java index 71b111875..ebc4f8f1d 100644 --- a/backend/src/test/java/com/festago/support/MemberFixture.java +++ b/backend/src/test/java/com/festago/support/MemberFixture.java @@ -1,7 +1,7 @@ package com.festago.support; import com.festago.auth.domain.SocialType; -import com.festago.domain.Member; +import com.festago.member.domain.Member; public class MemberFixture { diff --git a/backend/src/test/java/com/festago/support/MemberTicketFixture.java b/backend/src/test/java/com/festago/support/MemberTicketFixture.java index a2f9c83a1..784c59abd 100644 --- a/backend/src/test/java/com/festago/support/MemberTicketFixture.java +++ b/backend/src/test/java/com/festago/support/MemberTicketFixture.java @@ -1,9 +1,9 @@ package com.festago.support; -import com.festago.domain.Member; -import com.festago.domain.MemberTicket; -import com.festago.domain.Stage; -import com.festago.domain.TicketType; +import com.festago.member.domain.Member; +import com.festago.stage.domain.Stage; +import com.festago.ticket.domain.TicketType; +import com.festago.ticketing.domain.MemberTicket; import java.time.LocalDateTime; public class MemberTicketFixture { diff --git a/backend/src/test/java/com/festago/support/MockAuthExtractor.java b/backend/src/test/java/com/festago/support/MockAuthExtractor.java index 43c432dd8..cd88b0aed 100644 --- a/backend/src/test/java/com/festago/support/MockAuthExtractor.java +++ b/backend/src/test/java/com/festago/support/MockAuthExtractor.java @@ -1,8 +1,8 @@ package com.festago.support; -import com.festago.auth.domain.AuthExtractor; +import com.festago.auth.application.AuthExtractor; import com.festago.auth.domain.AuthPayload; -import com.festago.auth.presentation.AuthenticateContext; +import com.festago.presentation.auth.AuthenticateContext; public class MockAuthExtractor implements AuthExtractor { diff --git a/backend/src/test/java/com/festago/support/MockAuthTestExecutionListener.java b/backend/src/test/java/com/festago/support/MockAuthTestExecutionListener.java index 8f7a9e9e0..5cf14879c 100644 --- a/backend/src/test/java/com/festago/support/MockAuthTestExecutionListener.java +++ b/backend/src/test/java/com/festago/support/MockAuthTestExecutionListener.java @@ -1,7 +1,7 @@ package com.festago.support; import com.festago.auth.domain.Role; -import com.festago.auth.presentation.AuthenticateContext; +import com.festago.presentation.auth.AuthenticateContext; import java.lang.reflect.Method; import org.springframework.context.ApplicationContext; import org.springframework.test.context.TestContext; diff --git a/backend/src/test/java/com/festago/support/StageFixture.java b/backend/src/test/java/com/festago/support/StageFixture.java index 8435c5180..5c13eda00 100644 --- a/backend/src/test/java/com/festago/support/StageFixture.java +++ b/backend/src/test/java/com/festago/support/StageFixture.java @@ -1,7 +1,7 @@ package com.festago.support; -import com.festago.domain.Festival; -import com.festago.domain.Stage; +import com.festago.festival.domain.Festival; +import com.festago.stage.domain.Stage; import java.time.LocalDateTime; public class StageFixture { diff --git a/backend/src/test/java/com/festago/support/TestAuthConfig.java b/backend/src/test/java/com/festago/support/TestAuthConfig.java index f716d7a9c..c0a384dee 100644 --- a/backend/src/test/java/com/festago/support/TestAuthConfig.java +++ b/backend/src/test/java/com/festago/support/TestAuthConfig.java @@ -1,7 +1,7 @@ package com.festago.support; -import com.festago.auth.domain.AuthExtractor; -import com.festago.auth.presentation.AuthenticateContext; +import com.festago.auth.application.AuthExtractor; +import com.festago.presentation.auth.AuthenticateContext; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; diff --git a/backend/src/test/java/com/festago/support/TicketFixture.java b/backend/src/test/java/com/festago/support/TicketFixture.java index be548f099..d84b18f25 100644 --- a/backend/src/test/java/com/festago/support/TicketFixture.java +++ b/backend/src/test/java/com/festago/support/TicketFixture.java @@ -1,8 +1,8 @@ package com.festago.support; -import com.festago.domain.Stage; -import com.festago.domain.Ticket; -import com.festago.domain.TicketType; +import com.festago.stage.domain.Stage; +import com.festago.ticket.domain.Ticket; +import com.festago.ticket.domain.TicketType; public class TicketFixture { From fd94534ea53b54ebd4c2dd2fa2dd6182fb381232 Mon Sep 17 00:00:00 2001 From: SeongHoonC <108349655+SeongHoonC@users.noreply.github.com> Date: Fri, 15 Sep 2023 13:53:02 +0900 Subject: [PATCH 26/74] =?UTF-8?q?[AN/USER]=20feat:=20=ED=95=99=EC=83=9D=20?= =?UTF-8?q?=EC=9D=B8=EC=A6=9D=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?(#370)=20(#429)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 학생 인증 레포지토리 정의 * feat: 학교 레포지토리 임시 정의 * feat: 학교 인증 화면 뷰모델 구현 * test: 학생 인증 화면 뷰모델 테스트 작성 * refactor: LiveData stateFlow 로 리팩터링 * feat: StudentVerificationActivity 생성 * feat: 학생 인증 화면 xml 그리기 * feat: 재사용 가능한 문장 검증 로직 생성 및 테스트 * feat: 학생 인증 검증 로직 생성 및 테스트 * feat: SchoolId Long 으로 변경 * feat: 인증 코드 확인 요청 기능 작성 * feat: 코드 형식 확인 인증 * feat: 임시 학교 인증 화면 이동 * refator: ktlint check * refator: 클래스 및 변수 명 변경 * fix: 화면 회전 시 학교 이메일을 재요청하지 않음 * refactor: 사용하지않는 코드 주석 제거 * refactor: repeatOnStartedState util 추가 * refactor: StudentVerificationActivity 전체 리팩터링 * refactor: Students 를 Student 로 통일 * refactor: State 성공 시 처리 함수 분리 및 네이밍 변경 * refactor: 글자 30개까지 입력으로 변경 * feat: sealed interface 학생 인증 이벤트 추가 * refactor: 학생 인증 ViewModel 리팩터링 * test: 학생 인증 이벤트 테스트 추가 * refactor: 사용하지 않는 뷰 제거 * test: 학생 인증 코드 예외 테스트 추가 * feat: Event observing 추가 * refactor: 테스트 리팩터링 * refactor: 테스트 네이밍 리팩터링 * refactor: turbine 추가 및 sharedFlow 테스트 리팩터링 * refactor: Text 검증 테스트 네이밍 및 구조 리팩터링 * refactor: TextValidator 생성 로직 통일 * refactor: given when 함수 분리 및 테스트 리팩터링 * refactor: seal interface 는 isExactlyInstanceOf 로 테스트 --- android/festago/app/build.gradle.kts | 3 + .../festago/app/src/main/AndroidManifest.xml | 10 +- .../data/dto/SendVerificationRequest.kt | 9 + .../repository/SchoolDefaultRepository.kt | 11 + .../StudentVerificationDefaultRepository.kt | 20 ++ .../StudentVerificationRetrofitService.kt | 13 + .../festago/di/AuthServiceContainer.kt | 5 + .../festago/festago/di/RepositoryContainer.kt | 12 + .../presentation/ui/ViewModelFactory.kt | 7 + .../ui/home/mypage/MyPageFragment.kt | 5 + .../StudentVerificationActivity.kt | 99 +++++++ .../StudentVerificationEvent.kt | 7 + .../StudentVerificationUiState.kt | 17 ++ .../StudentVerificationViewModel.kt | 149 ++++++++++ .../presentation/util/LifecycleOwnerUtil.kt | 15 + .../layout/activity_student_verification.xml | 151 ++++++++++ .../app/src/main/res/values/strings.xml | 10 + .../StudentVerificationViewModelTest.kt | 276 ++++++++++++++++++ .../festago/model/StudentVerificationCode.kt | 17 ++ .../festago/festago/model/TextValidator.kt | 19 ++ .../festago/repository/SchoolRepository.kt | 5 + .../StudentVerificationRepository.kt | 8 + .../model/StudentVerificationCodeTest.kt | 33 +++ .../festago/model/TextValidatorTest.kt | 50 ++++ 24 files changed, 946 insertions(+), 5 deletions(-) create mode 100644 android/festago/app/src/main/java/com/festago/festago/data/dto/SendVerificationRequest.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/data/repository/SchoolDefaultRepository.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/data/repository/StudentVerificationDefaultRepository.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/data/service/StudentVerificationRetrofitService.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationActivity.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationEvent.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationUiState.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationViewModel.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/util/LifecycleOwnerUtil.kt create mode 100644 android/festago/app/src/main/res/layout/activity_student_verification.xml create mode 100644 android/festago/app/src/test/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationViewModelTest.kt create mode 100644 android/festago/domain/src/main/java/com/festago/festago/model/StudentVerificationCode.kt create mode 100644 android/festago/domain/src/main/java/com/festago/festago/model/TextValidator.kt create mode 100644 android/festago/domain/src/main/java/com/festago/festago/repository/SchoolRepository.kt create mode 100644 android/festago/domain/src/main/java/com/festago/festago/repository/StudentVerificationRepository.kt create mode 100644 android/festago/domain/src/test/java/com/festago/festago/model/StudentVerificationCodeTest.kt create mode 100644 android/festago/domain/src/test/java/com/festago/festago/model/TextValidatorTest.kt diff --git a/android/festago/app/build.gradle.kts b/android/festago/app/build.gradle.kts index 1bc94749f..8429e2e94 100644 --- a/android/festago/app/build.gradle.kts +++ b/android/festago/app/build.gradle.kts @@ -137,6 +137,9 @@ dependencies { // Encrypted SharedPreference implementation("androidx.security:security-crypto-ktx:1.1.0-alpha06") + // turbine + testImplementation("app.cash.turbine:turbine:1.0.0") + // domain implementation(project(":domain")) } diff --git a/android/festago/app/src/main/AndroidManifest.xml b/android/festago/app/src/main/AndroidManifest.xml index d066f411c..d4f74b841 100644 --- a/android/festago/app/src/main/AndroidManifest.xml +++ b/android/festago/app/src/main/AndroidManifest.xml @@ -3,7 +3,6 @@ xmlns:tools="http://schemas.android.com/tools"> - + @@ -54,11 +56,9 @@ android:scheme="@string/kakao_redirection_scheme" /> - - + android:exported="false" /> - + \ No newline at end of file diff --git a/android/festago/app/src/main/java/com/festago/festago/data/dto/SendVerificationRequest.kt b/android/festago/app/src/main/java/com/festago/festago/data/dto/SendVerificationRequest.kt new file mode 100644 index 000000000..005d9f021 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/data/dto/SendVerificationRequest.kt @@ -0,0 +1,9 @@ +package com.festago.festago.data.dto + +import kotlinx.serialization.Serializable + +@Serializable +data class SendVerificationRequest( + val userName: String, + val schoolId: Int, +) diff --git a/android/festago/app/src/main/java/com/festago/festago/data/repository/SchoolDefaultRepository.kt b/android/festago/app/src/main/java/com/festago/festago/data/repository/SchoolDefaultRepository.kt new file mode 100644 index 000000000..7ec45167e --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/data/repository/SchoolDefaultRepository.kt @@ -0,0 +1,11 @@ +package com.festago.festago.data.repository + +import com.festago.festago.repository.SchoolRepository + +class SchoolDefaultRepository() : SchoolRepository { + + override suspend fun loadSchoolEmail(schoolId: Long): Result { + // TODO: API 연동 작업 필요 + return Result.success("festago.com") + } +} diff --git a/android/festago/app/src/main/java/com/festago/festago/data/repository/StudentVerificationDefaultRepository.kt b/android/festago/app/src/main/java/com/festago/festago/data/repository/StudentVerificationDefaultRepository.kt new file mode 100644 index 000000000..df79b8793 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/data/repository/StudentVerificationDefaultRepository.kt @@ -0,0 +1,20 @@ +package com.festago.festago.data.repository + +import com.festago.festago.data.service.StudentVerificationRetrofitService +import com.festago.festago.model.StudentVerificationCode +import com.festago.festago.repository.StudentVerificationRepository + +class StudentVerificationDefaultRepository( + private val studentVerificationRetrofitService: StudentVerificationRetrofitService, +) : StudentVerificationRepository { + + override suspend fun sendVerificationCode(userName: String, schoolId: Long): Result { + // TODO: API 연동 작업 필요 + return Result.success(Unit) + } + + override suspend fun requestVerificationCodeConfirm(code: StudentVerificationCode): Result { + // TODO: API 연동 작업 필요 + return Result.success(Unit) + } +} diff --git a/android/festago/app/src/main/java/com/festago/festago/data/service/StudentVerificationRetrofitService.kt b/android/festago/app/src/main/java/com/festago/festago/data/service/StudentVerificationRetrofitService.kt new file mode 100644 index 000000000..7b0ccaba2 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/data/service/StudentVerificationRetrofitService.kt @@ -0,0 +1,13 @@ +package com.festago.festago.data.service + +import com.festago.festago.data.dto.SendVerificationRequest +import retrofit2.Response +import retrofit2.http.Body +import retrofit2.http.POST + +interface StudentVerificationRetrofitService { + @POST("/students/send-verification") + suspend fun sendVerificationCode( + @Body sendVerificationRequest: SendVerificationRequest, + ): Response +} diff --git a/android/festago/app/src/main/java/com/festago/festago/di/AuthServiceContainer.kt b/android/festago/app/src/main/java/com/festago/festago/di/AuthServiceContainer.kt index 05e512157..496232581 100644 --- a/android/festago/app/src/main/java/com/festago/festago/di/AuthServiceContainer.kt +++ b/android/festago/app/src/main/java/com/festago/festago/di/AuthServiceContainer.kt @@ -1,6 +1,7 @@ package com.festago.festago.di import com.festago.festago.data.retrofit.AuthInterceptor +import com.festago.festago.data.service.StudentVerificationRetrofitService import com.festago.festago.data.service.TicketRetrofitService import com.festago.festago.data.service.UserRetrofitService import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory @@ -29,4 +30,8 @@ class AuthServiceContainer(baseUrl: String, tokenContainer: TokenContainer) { val userRetrofitService: UserRetrofitService by lazy { authRetrofit.create(UserRetrofitService::class.java) } + + val studentVerificationRetrofitService: StudentVerificationRetrofitService by lazy { + authRetrofit.create(StudentVerificationRetrofitService::class.java) + } } diff --git a/android/festago/app/src/main/java/com/festago/festago/di/RepositoryContainer.kt b/android/festago/app/src/main/java/com/festago/festago/di/RepositoryContainer.kt index 886a0d2e0..3b655a30f 100644 --- a/android/festago/app/src/main/java/com/festago/festago/di/RepositoryContainer.kt +++ b/android/festago/app/src/main/java/com/festago/festago/di/RepositoryContainer.kt @@ -3,11 +3,15 @@ package com.festago.festago.di import com.festago.festago.data.repository.AuthDefaultRepository import com.festago.festago.data.repository.FestivalDefaultRepository import com.festago.festago.data.repository.ReservationTicketDefaultRepository +import com.festago.festago.data.repository.SchoolDefaultRepository +import com.festago.festago.data.repository.StudentVerificationDefaultRepository import com.festago.festago.data.repository.TicketDefaultRepository import com.festago.festago.data.repository.UserDefaultRepository import com.festago.festago.repository.AuthRepository import com.festago.festago.repository.FestivalRepository import com.festago.festago.repository.ReservationTicketRepository +import com.festago.festago.repository.SchoolRepository +import com.festago.festago.repository.StudentVerificationRepository import com.festago.festago.repository.TicketRepository import com.festago.festago.repository.UserRepository @@ -40,4 +44,12 @@ class RepositoryContainer( get() = ReservationTicketDefaultRepository( reservationTicketRetrofitService = normalServiceContainer.reservationTicketRetrofitService, ) + + val studentVerificationRepository: StudentVerificationRepository + get() = StudentVerificationDefaultRepository( + studentVerificationRetrofitService = authServiceContainer.studentVerificationRetrofitService, + ) + + val schoolRepository: SchoolRepository + get() = SchoolDefaultRepository() } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ViewModelFactory.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ViewModelFactory.kt index b7a1888d5..3b541c35f 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ViewModelFactory.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/ViewModelFactory.kt @@ -8,6 +8,7 @@ import com.festago.festago.presentation.ui.home.festivallist.FestivalListViewMod import com.festago.festago.presentation.ui.home.mypage.MyPageViewModel import com.festago.festago.presentation.ui.home.ticketlist.TicketListViewModel import com.festago.festago.presentation.ui.signin.SignInViewModel +import com.festago.festago.presentation.ui.studentverification.StudentVerificationViewModel import com.festago.festago.presentation.ui.ticketentry.TicketEntryViewModel import com.festago.festago.presentation.ui.tickethistory.TicketHistoryViewModel import com.festago.festago.presentation.ui.ticketreserve.TicketReserveViewModel @@ -63,6 +64,12 @@ val FestagoViewModelFactory: ViewModelProvider.Factory = object : ViewModelProvi analyticsHelper = analysisContainer.analyticsHelper, ) + modelClass.isAssignableFrom(StudentVerificationViewModel::class.java) -> StudentVerificationViewModel( + schoolRepository = repositoryContainer.schoolRepository, + studentVerificationRepository = repositoryContainer.studentVerificationRepository, + analyticsHelper = analysisContainer.analyticsHelper, + ) + else -> throw IllegalArgumentException("ViewModelFactory에 정의되지않은 뷰모델을 생성하였습니다 : ${modelClass.name}") } as T } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt index a0dac3641..6c8c95fff 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt @@ -12,6 +12,7 @@ import com.festago.festago.databinding.FragmentMyPageBinding import com.festago.festago.presentation.ui.FestagoViewModelFactory import com.festago.festago.presentation.ui.home.HomeActivity import com.festago.festago.presentation.ui.signin.SignInActivity +import com.festago.festago.presentation.ui.studentverification.StudentVerificationActivity import com.festago.festago.presentation.ui.tickethistory.TicketHistoryActivity class MyPageFragment : Fragment(R.layout.fragment_my_page) { @@ -102,6 +103,10 @@ class MyPageFragment : Fragment(R.layout.fragment_my_page) { binding.srlMyPage.setOnRefreshListener { vm.loadUserInfo() } + // TODO: 학교 선택 화면 변경 필요 + binding.tvSchoolAuthorization.setOnClickListener { + startActivity(StudentVerificationActivity.getIntent(requireContext(), 1L)) + } } private fun handleSuccess(uiState: MyPageUiState.Success) { diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationActivity.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationActivity.kt new file mode 100644 index 000000000..ee22e982d --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationActivity.kt @@ -0,0 +1,99 @@ +package com.festago.festago.presentation.ui.studentverification + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import com.festago.festago.R +import com.festago.festago.databinding.ActivityStudentVerificationBinding +import com.festago.festago.presentation.ui.FestagoViewModelFactory +import com.festago.festago.presentation.util.repeatOnStarted +import java.time.LocalTime +import java.time.format.DateTimeFormatter + +class StudentVerificationActivity : AppCompatActivity() { + + private val binding: ActivityStudentVerificationBinding by lazy { + ActivityStudentVerificationBinding.inflate(layoutInflater) + } + + private val vm: StudentVerificationViewModel by viewModels { FestagoViewModelFactory } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + initBinding() + initView() + initObserve() + } + + private fun initBinding() { + setContentView(binding.root) + binding.lifecycleOwner = this + binding.vm = vm + } + + private fun initView() { + val schoolId = intent.getLongExtra(KEY_SCHOOL_ID, -1L) + vm.loadSchoolEmail(schoolId) + initRequestVerificationCodeBtn(schoolId) + } + + private fun initRequestVerificationCodeBtn(schoolId: Long) { + binding.btnRequestVerificationCode.setOnClickListener { + vm.sendVerificationCode(binding.tieVerificationCode.text.toString(), schoolId) + } + } + + private fun initObserve() { + repeatOnStarted { + vm.uiState.collect { uiState -> + handleUiState(uiState) + } + } + repeatOnStarted { + vm.event.collect { event -> + handleEvent(event) + } + } + } + + private fun handleUiState(uiState: StudentVerificationUiState) { + binding.uiState = uiState + when (uiState) { + is StudentVerificationUiState.Success -> handleSuccess(uiState) + is StudentVerificationUiState.Loading, StudentVerificationUiState.Error -> Unit + } + } + + private fun handleSuccess(uiState: StudentVerificationUiState.Success) { + binding.tvSchoolEmail.text = + getString(R.string.student_verification_tv_email_format, uiState.schoolEmail) + + val format = + DateTimeFormatter.ofPattern(getString(R.string.student_verification_tv_timer_format)) + binding.tvTimerVerificationCode.text = LocalTime.ofSecondOfDay(uiState.remainTime.toLong()) + .format(format) + + binding.btnVerificationConfirm.isEnabled = uiState.isValidateCode + } + + private fun handleEvent(event: StudentVerificationEvent) { + when (event) { + is StudentVerificationEvent.VerificationSuccess -> Unit + is StudentVerificationEvent.VerificationFailure -> Unit + is StudentVerificationEvent.CodeTimeOut -> Unit + } + } + + companion object { + + private const val KEY_SCHOOL_ID = "KEY_SCHOOL_ID" + + fun getIntent(context: Context, schoolId: Long): Intent { + return Intent(context, StudentVerificationActivity::class.java).apply { + putExtra(KEY_SCHOOL_ID, schoolId) + } + } + } +} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationEvent.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationEvent.kt new file mode 100644 index 000000000..a7e7e8899 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationEvent.kt @@ -0,0 +1,7 @@ +package com.festago.festago.presentation.ui.studentverification + +sealed interface StudentVerificationEvent { + object CodeTimeOut : StudentVerificationEvent + object VerificationFailure : StudentVerificationEvent + object VerificationSuccess : StudentVerificationEvent +} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationUiState.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationUiState.kt new file mode 100644 index 000000000..ca650fa02 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationUiState.kt @@ -0,0 +1,17 @@ +package com.festago.festago.presentation.ui.studentverification + +sealed interface StudentVerificationUiState { + object Loading : StudentVerificationUiState + + data class Success( + val schoolEmail: String, + val remainTime: Int, + val isValidateCode: Boolean = false, + ) : StudentVerificationUiState + + object Error : StudentVerificationUiState + + val shouldShowSuccess get() = this is Success + val shouldShowLoading get() = this is Loading + val shouldShowError get() = this is Error +} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationViewModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationViewModel.kt new file mode 100644 index 000000000..8df23b16e --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/studentverification/StudentVerificationViewModel.kt @@ -0,0 +1,149 @@ +package com.festago.festago.presentation.ui.studentverification + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.festago.festago.analytics.AnalyticsHelper +import com.festago.festago.analytics.logNetworkFailure +import com.festago.festago.model.StudentVerificationCode +import com.festago.festago.model.timer.Timer +import com.festago.festago.model.timer.TimerListener +import com.festago.festago.repository.SchoolRepository +import com.festago.festago.repository.StudentVerificationRepository +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch + +class StudentVerificationViewModel( + private val schoolRepository: SchoolRepository, + private val studentVerificationRepository: StudentVerificationRepository, + private val analyticsHelper: AnalyticsHelper, +) : ViewModel() { + + private val _uiState = + MutableStateFlow(StudentVerificationUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _event = MutableSharedFlow() + val event: SharedFlow = _event.asSharedFlow() + + val verificationCode = MutableStateFlow("") + + private val timer: Timer = Timer() + + init { + initObserveVerificationCode() + } + + private fun initObserveVerificationCode() { + viewModelScope.launch { + verificationCode.collect { code -> + handleOnUiStateSuccess { + validateCode(code, it) + } + } + } + } + + private inline fun handleOnUiStateSuccess(action: (state: StudentVerificationUiState.Success) -> Unit) { + val state = uiState.value as? StudentVerificationUiState.Success ?: return + action(state) + } + + private fun validateCode(verificationCode: String, state: StudentVerificationUiState.Success) { + runCatching { + StudentVerificationCode(verificationCode) + }.onSuccess { + _uiState.value = state.copy(isValidateCode = true) + }.onFailure { + _uiState.value = state.copy(isValidateCode = false) + } + } + + fun loadSchoolEmail(schoolId: Long) { + if (uiState.value is StudentVerificationUiState.Success) return + + viewModelScope.launch { + schoolRepository.loadSchoolEmail(schoolId) + .onSuccess { email -> + _uiState.value = StudentVerificationUiState.Success( + schoolEmail = email, + remainTime = MIN_REMAIN_TIME, + ) + } + .onFailure { + _uiState.value = StudentVerificationUiState.Error + analyticsHelper.logNetworkFailure( + KEY_LOAD_SCHOOL_EMAIL_LOG, + it.message.toString(), + ) + } + } + } + + fun sendVerificationCode(userName: String, schoolId: Long) { + viewModelScope.launch { + studentVerificationRepository.sendVerificationCode(userName, schoolId) + .onSuccess { + handleOnUiStateSuccess { state -> + _uiState.value = state.copy(remainTime = TIMER_PERIOD) + } + setTimer() + } + .onFailure { + analyticsHelper.logNetworkFailure( + KEY_SEND_VERIFICATION_CODE_LOG, + it.message.toString(), + ) + } + } + } + + private suspend fun setTimer() { + timer.timerListener = createTimerListener() + timer.start(TIMER_PERIOD) + } + + private fun createTimerListener(): TimerListener = object : TimerListener { + override fun onTick(current: Int) { + handleOnUiStateSuccess { state -> + _uiState.value = state.copy(remainTime = current) + } + } + + override fun onFinish() { + handleOnUiStateSuccess { state -> + _uiState.value = state.copy(remainTime = MIN_REMAIN_TIME) + } + } + } + + fun confirmVerificationCode() { + viewModelScope.launch { + val state = uiState.value as? StudentVerificationUiState.Success ?: return@launch + + if (state.remainTime == MIN_REMAIN_TIME) { + _event.emit(StudentVerificationEvent.CodeTimeOut) + return@launch + } + + studentVerificationRepository.requestVerificationCodeConfirm( + StudentVerificationCode(verificationCode.value), + ).onSuccess { + _event.emit(StudentVerificationEvent.VerificationSuccess) + }.onFailure { + _event.emit(StudentVerificationEvent.VerificationFailure) + } + } + } + + companion object { + private const val KEY_LOAD_SCHOOL_EMAIL_LOG = "load_school_email" + private const val KEY_SEND_VERIFICATION_CODE_LOG = "send_verification_code" + private const val MIN_REMAIN_TIME = 0 + private const val TIMER_PERIOD = 300 + } +} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/util/LifecycleOwnerUtil.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/util/LifecycleOwnerUtil.kt new file mode 100644 index 000000000..a5ca4e949 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/util/LifecycleOwnerUtil.kt @@ -0,0 +1,15 @@ +package com.festago.festago.presentation.util + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.launch + +fun LifecycleOwner.repeatOnStarted(action: suspend () -> Unit) { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + action() + } + } +} diff --git a/android/festago/app/src/main/res/layout/activity_student_verification.xml b/android/festago/app/src/main/res/layout/activity_student_verification.xml new file mode 100644 index 000000000..b17524eef --- /dev/null +++ b/android/festago/app/src/main/res/layout/activity_student_verification.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

축제 생성 요청

@@ -22,6 +35,9 @@

축제 생성 요청


+ +
+
diff --git a/backend/src/test/java/com/festago/application/FestivalServiceTest.java b/backend/src/test/java/com/festago/application/FestivalServiceTest.java index edd5cab95..cbd460b26 100644 --- a/backend/src/test/java/com/festago/application/FestivalServiceTest.java +++ b/backend/src/test/java/com/festago/application/FestivalServiceTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; import com.festago.common.exception.BadRequestException; @@ -15,9 +16,12 @@ import com.festago.festival.dto.FestivalResponse; import com.festago.festival.dto.FestivalsResponse; import com.festago.festival.repository.FestivalRepository; +import com.festago.school.domain.School; +import com.festago.school.repository.SchoolRepository; import com.festago.stage.domain.Stage; import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; +import com.festago.support.SchoolFixture; import com.festago.support.StageFixture; import java.time.LocalDate; import java.time.LocalDateTime; @@ -43,6 +47,9 @@ class FestivalServiceTest { @Mock StageRepository stageRepository; + @Mock + SchoolRepository schoolRepository; + @InjectMocks FestivalService festivalService; @@ -65,12 +72,31 @@ class FestivalServiceTest { @Nested class 축제_생성 { + @Test + void 학교가_없으면_예외() { + // given + LocalDate today = LocalDate.now(); + Long schoolId = 1L; + FestivalCreateRequest request = new FestivalCreateRequest("테코대학교", today, today, "http://image.png", 1L); + + given(schoolRepository.findById(schoolId)) + .willReturn(Optional.empty()); + + // when & then + assertThatThrownBy(() -> festivalService.create(request)) + .isInstanceOf(NotFoundException.class) + .hasMessage("존재하지 않는 학교입니다."); + } + @Test void 축제_생성시_시작일자가_과거이면_예외() { // given LocalDate today = LocalDate.now(); + School school = SchoolFixture.school().build(); FestivalCreateRequest request = new FestivalCreateRequest("테코대학교", today.minusDays(1), today, - "http://image.png"); + "http://image.png", 1L); + given(schoolRepository.findById(anyLong())) + .willReturn(Optional.of(school)); // when & then assertThatThrownBy(() -> festivalService.create(request)) @@ -84,9 +110,13 @@ class 축제_생성 { LocalDate today = LocalDate.now(); String name = "테코대학교"; String thumbnail = "http://image.png"; - FestivalCreateRequest request = new FestivalCreateRequest(name, today, today, thumbnail); - Festival festival = new Festival(1L, name, today, today, thumbnail); + Long schoolId = 1L; + School school = SchoolFixture.school().id(schoolId).build(); + FestivalCreateRequest request = new FestivalCreateRequest(name, today, today, thumbnail, schoolId); + Festival festival = new Festival(1L, name, today, today, thumbnail, school); FestivalResponse expected = new FestivalResponse(1L, name, today, today, thumbnail); + given(schoolRepository.findById(schoolId)) + .willReturn(Optional.of(school)); given(festivalRepository.save(any())) .willReturn(festival); diff --git a/backend/src/test/java/com/festago/application/integration/FestivalServiceIntegrationTest.java b/backend/src/test/java/com/festago/application/integration/FestivalServiceIntegrationTest.java index 7b863ef60..d7d850f87 100644 --- a/backend/src/test/java/com/festago/application/integration/FestivalServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/application/integration/FestivalServiceIntegrationTest.java @@ -10,9 +10,12 @@ import com.festago.festival.dto.FestivalDetailTicketResponse; import com.festago.festival.dto.FestivalResponse; import com.festago.festival.repository.FestivalRepository; +import com.festago.school.domain.School; +import com.festago.school.repository.SchoolRepository; import com.festago.stage.domain.Stage; import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; +import com.festago.support.SchoolFixture; import com.festago.support.StageFixture; import com.festago.support.TicketFixture; import com.festago.ticket.domain.Ticket; @@ -43,12 +46,17 @@ class FestivalServiceIntegrationTest extends ApplicationIntegrationTest { @Autowired TicketRepository ticketRepository; + @Autowired + SchoolRepository schoolRepository; + + @Test void 축제를_생성한다() { // given + School school = schoolRepository.save(SchoolFixture.school().build()); LocalDate today = LocalDate.now(); FestivalCreateRequest request = new FestivalCreateRequest("테코 대학교 축제", today, today.plusDays(1), - "thumbnail.png"); + "thumbnail.png", school.getId()); // when FestivalResponse festivalResponse = festivalService.create(request); @@ -60,7 +68,8 @@ class FestivalServiceIntegrationTest extends ApplicationIntegrationTest { @Test void 축제_상세_정보를_조회한다() { // given - Festival festival = festivalRepository.save(FestivalFixture.festival().build()); + School school = schoolRepository.save(SchoolFixture.school().build()); + Festival festival = festivalRepository.save(FestivalFixture.festival().school(school).build()); Stage stage = stageRepository.save(StageFixture.stage().festival(festival).build()); Ticket ticket1 = ticketRepository.save( TicketFixture.ticket().stage(stage).ticketType(TicketType.VISITOR).build()); diff --git a/backend/src/test/java/com/festago/application/integration/MemberTicketIntegrationTest.java b/backend/src/test/java/com/festago/application/integration/MemberTicketIntegrationTest.java index b4e719f72..275dc210b 100644 --- a/backend/src/test/java/com/festago/application/integration/MemberTicketIntegrationTest.java +++ b/backend/src/test/java/com/festago/application/integration/MemberTicketIntegrationTest.java @@ -6,11 +6,14 @@ import com.festago.festival.repository.FestivalRepository; import com.festago.member.domain.Member; import com.festago.member.repository.MemberRepository; +import com.festago.school.domain.School; +import com.festago.school.repository.SchoolRepository; import com.festago.stage.domain.Stage; import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; import com.festago.support.MemberFixture; import com.festago.support.MemberTicketFixture; +import com.festago.support.SchoolFixture; import com.festago.support.StageFixture; import com.festago.ticket.repository.TicketRepository; import com.festago.ticketing.application.MemberTicketService; @@ -44,11 +47,15 @@ class MemberTicketIntegrationTest extends ApplicationIntegrationTest { @Autowired TicketRepository ticketRepository; + @Autowired + SchoolRepository schoolRepository; + @Test void 예매한_티켓_조회시_Pageable_적용() { // given + School school = schoolRepository.save(SchoolFixture.school().build()); Member member = memberRepository.save(MemberFixture.member().build()); - Festival festival = festivalRepository.save(FestivalFixture.festival().build()); + Festival festival = festivalRepository.save(FestivalFixture.festival().school(school).build()); Stage stage = stageRepository.save(StageFixture.stage().festival(festival).build()); for (int i = 0; i < 20; i++) { memberTicketRepository.save(MemberTicketFixture.memberTicket() diff --git a/backend/src/test/java/com/festago/application/integration/TicketServiceIntegrationTest.java b/backend/src/test/java/com/festago/application/integration/TicketServiceIntegrationTest.java index a0d755858..a53181663 100644 --- a/backend/src/test/java/com/festago/application/integration/TicketServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/application/integration/TicketServiceIntegrationTest.java @@ -7,9 +7,12 @@ import com.festago.common.exception.NotFoundException; import com.festago.festival.domain.Festival; import com.festago.festival.repository.FestivalRepository; +import com.festago.school.domain.School; +import com.festago.school.repository.SchoolRepository; import com.festago.stage.domain.Stage; import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; +import com.festago.support.SchoolFixture; import com.festago.support.StageFixture; import com.festago.ticket.application.TicketService; import com.festago.ticket.domain.TicketAmount; @@ -46,6 +49,9 @@ class TicketServiceIntegrationTest extends ApplicationIntegrationTest { @Autowired TicketAmountRepository ticketAmountRepository; + @Autowired + SchoolRepository schoolRepository; + @SpyBean Clock clock; @@ -72,7 +78,9 @@ class TicketServiceIntegrationTest extends ApplicationIntegrationTest { doReturn(stageStartTime.minusWeeks(1).toInstant(ZoneOffset.UTC)) .when(clock) .instant(); + School school = schoolRepository.save(SchoolFixture.school().build()); Festival festival = festivalRepository.save(FestivalFixture.festival() + .school(school) .startDate(stageStartTime.toLocalDate()) .endDate(stageStartTime.toLocalDate()) .build()); @@ -99,7 +107,9 @@ class TicketServiceIntegrationTest extends ApplicationIntegrationTest { doReturn(stageStartTime.minusWeeks(1).toInstant(ZoneOffset.UTC)) .when(clock) .instant(); + School school = schoolRepository.save(SchoolFixture.school().build()); Festival festival = festivalRepository.save(FestivalFixture.festival() + .school(school) .startDate(stageStartTime.toLocalDate()) .endDate(stageStartTime.toLocalDate()) .build()); diff --git a/backend/src/test/java/com/festago/application/integration/TicketingServiceIntegrationTest.java b/backend/src/test/java/com/festago/application/integration/TicketingServiceIntegrationTest.java index 5b57991bb..f2560661f 100644 --- a/backend/src/test/java/com/festago/application/integration/TicketingServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/application/integration/TicketingServiceIntegrationTest.java @@ -8,6 +8,7 @@ import com.festago.common.exception.BadRequestException; import com.festago.member.domain.Member; import com.festago.member.repository.MemberRepository; +import com.festago.school.repository.SchoolRepository; import com.festago.stage.domain.Stage; import com.festago.support.MemberFixture; import com.festago.ticketing.application.TicketingService; @@ -37,6 +38,9 @@ class TicketingServiceIntegrationTest extends ApplicationIntegrationTest { @Autowired TicketingService ticketingService; + @Autowired + SchoolRepository schoolRepository; + @SpyBean MemberTicketRepository memberTicketRepository; diff --git a/backend/src/test/java/com/festago/domain/FestivalTest.java b/backend/src/test/java/com/festago/domain/FestivalTest.java index 98ecd9c57..90d3a36f7 100644 --- a/backend/src/test/java/com/festago/domain/FestivalTest.java +++ b/backend/src/test/java/com/festago/domain/FestivalTest.java @@ -5,7 +5,9 @@ import com.festago.common.exception.BadRequestException; import com.festago.festival.domain.Festival; +import com.festago.school.domain.School; import com.festago.support.FestivalFixture; +import com.festago.support.SchoolFixture; import java.time.LocalDate; import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayNameGeneration; @@ -21,9 +23,10 @@ class FestivalTest { void 시작일자가_종료일자_이전이면_예외() { // given LocalDate today = LocalDate.now(); + School school = SchoolFixture.school().build(); // when & then - assertThatThrownBy(() -> new Festival("테코대학교", today.plusDays(1), today)) + assertThatThrownBy(() -> new Festival("테코대학교", today.plusDays(1), today, school)) .isInstanceOf(BadRequestException.class) .hasMessage("축제 시작 일자는 종료일자 이전이어야합니다."); } diff --git a/backend/src/test/java/com/festago/domain/MemberTicketRepositoryTest.java b/backend/src/test/java/com/festago/domain/MemberTicketRepositoryTest.java index 1351cd40a..bafb2b838 100644 --- a/backend/src/test/java/com/festago/domain/MemberTicketRepositoryTest.java +++ b/backend/src/test/java/com/festago/domain/MemberTicketRepositoryTest.java @@ -8,11 +8,14 @@ import com.festago.festival.repository.FestivalRepository; import com.festago.member.domain.Member; import com.festago.member.repository.MemberRepository; +import com.festago.school.domain.School; +import com.festago.school.repository.SchoolRepository; import com.festago.stage.domain.Stage; import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; import com.festago.support.MemberFixture; import com.festago.support.MemberTicketFixture; +import com.festago.support.SchoolFixture; import com.festago.support.StageFixture; import com.festago.ticket.repository.TicketRepository; import com.festago.ticketing.domain.MemberTicket; @@ -52,6 +55,9 @@ class MemberTicketRepositoryTest { @Autowired FestivalRepository festivalRepository; + @Autowired + SchoolRepository schoolRepository; + @Nested class 회원의_ID로_에매한_티켓을_모두_조회 { @@ -61,7 +67,8 @@ class 회원의_ID로_에매한_티켓을_모두_조회 { Member member1 = memberRepository.save(MemberFixture.member().socialId("abc").build()); Member member2 = memberRepository.save(MemberFixture.member().socialId("def").build()); - Festival festival = festivalRepository.save(FestivalFixture.festival().build()); + School school = schoolRepository.save(SchoolFixture.school().build()); + Festival festival = festivalRepository.save(FestivalFixture.festival().school(school).build()); Stage stage1 = stageRepository.save(StageFixture.stage().festival(festival).build()); Stage stage2 = stageRepository.save(StageFixture.stage().festival(festival).build()); @@ -83,7 +90,8 @@ class 회원의_ID로_에매한_티켓을_모두_조회 { int expected = 10; Member member = memberRepository.save(MemberFixture.member().build()); - Festival festival = festivalRepository.save(FestivalFixture.festival().build()); + School school = schoolRepository.save(SchoolFixture.school().build()); + Festival festival = festivalRepository.save(FestivalFixture.festival().school(school).build()); Stage stage = stageRepository.save(StageFixture.stage().festival(festival).build()); for (int i = 0; i < 20; i++) { @@ -103,7 +111,8 @@ class 회원의_ID로_에매한_티켓을_모두_조회 { // given Member member = memberRepository.save(MemberFixture.member().build()); - Festival festival = festivalRepository.save(FestivalFixture.festival().build()); + School school = schoolRepository.save(SchoolFixture.school().build()); + Festival festival = festivalRepository.save(FestivalFixture.festival().school(school).build()); Stage stage = stageRepository.save(StageFixture.stage().festival(festival).build()); List memberTickets = new ArrayList<>(); diff --git a/backend/src/test/java/com/festago/domain/StageRepositoryTest.java b/backend/src/test/java/com/festago/domain/StageRepositoryTest.java index 088d15562..c88bb4cf9 100644 --- a/backend/src/test/java/com/festago/domain/StageRepositoryTest.java +++ b/backend/src/test/java/com/festago/domain/StageRepositoryTest.java @@ -5,9 +5,12 @@ import com.festago.festival.domain.Festival; import com.festago.festival.repository.FestivalRepository; +import com.festago.school.domain.School; +import com.festago.school.repository.SchoolRepository; import com.festago.stage.domain.Stage; import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; +import com.festago.support.SchoolFixture; import com.festago.support.StageFixture; import com.festago.support.TicketFixture; import com.festago.ticket.domain.Ticket; @@ -35,13 +38,17 @@ class StageRepositoryTest { @Autowired TicketRepository ticketRepository; + @Autowired + SchoolRepository schoolRepository; + @Autowired EntityManager entityManager; @Test void 티켓이_존재하지_않을때도_무대가_조회된다() { // given - Festival festival = festivalRepository.save(FestivalFixture.festival().build()); + School school = schoolRepository.save(SchoolFixture.school().build()); + Festival festival = festivalRepository.save(FestivalFixture.festival().school(school).build()); Stage stage1 = stageRepository.save(StageFixture.stage().festival(festival).build()); Stage stage2 = stageRepository.save(StageFixture.stage().festival(festival).build()); @@ -58,7 +65,8 @@ class StageRepositoryTest { @Test void 해당_축제의_무대가_모두_조회된다() { // given - Festival festival = festivalRepository.save(FestivalFixture.festival().build()); + School school = schoolRepository.save(SchoolFixture.school().build()); + Festival festival = festivalRepository.save(FestivalFixture.festival().school(school).build()); stageRepository.save(StageFixture.stage().festival(festival).build()); // when @@ -71,7 +79,8 @@ class StageRepositoryTest { @Test void 티켓_정보까지_모두_조회된다() { // given - Festival festival = festivalRepository.save(FestivalFixture.festival().build()); + School school = schoolRepository.save(SchoolFixture.school().build()); + Festival festival = festivalRepository.save(FestivalFixture.festival().school(school).build()); Stage stage = stageRepository.save(StageFixture.stage().festival(festival).build()); Ticket ticket1 = ticketRepository.save( TicketFixture.ticket().ticketType(TicketType.STUDENT).stage(stage).build()); diff --git a/backend/src/test/java/com/festago/domain/TicketRepositoryTest.java b/backend/src/test/java/com/festago/domain/TicketRepositoryTest.java index bb92b7494..9c9361b71 100644 --- a/backend/src/test/java/com/festago/domain/TicketRepositoryTest.java +++ b/backend/src/test/java/com/festago/domain/TicketRepositoryTest.java @@ -4,9 +4,12 @@ import com.festago.festival.domain.Festival; import com.festago.festival.repository.FestivalRepository; +import com.festago.school.domain.School; +import com.festago.school.repository.SchoolRepository; import com.festago.stage.domain.Stage; import com.festago.stage.repository.StageRepository; import com.festago.support.FestivalFixture; +import com.festago.support.SchoolFixture; import com.festago.support.StageFixture; import com.festago.support.TicketFixture; import com.festago.ticket.domain.Ticket; @@ -33,10 +36,14 @@ class TicketRepositoryTest { @Autowired StageRepository stageRepository; + @Autowired + SchoolRepository schoolRepository; + @Test void 공연의_ID로_티켓을_모두_조회() { // given - Festival festival = festivalRepository.save(FestivalFixture.festival().build()); + School school = schoolRepository.save(SchoolFixture.school().build()); + Festival festival = festivalRepository.save(FestivalFixture.festival().school(school).build()); Stage stage = stageRepository.save(StageFixture.stage().festival(festival).build()); Stage otherStage = stageRepository.save(StageFixture.stage().festival(festival).build()); diff --git a/backend/src/test/java/com/festago/dto/FestivalCreateRequestTest.java b/backend/src/test/java/com/festago/dto/FestivalCreateRequestTest.java index 723a5ecb4..9252f0d1c 100644 --- a/backend/src/test/java/com/festago/dto/FestivalCreateRequestTest.java +++ b/backend/src/test/java/com/festago/dto/FestivalCreateRequestTest.java @@ -4,6 +4,8 @@ import com.festago.festival.domain.Festival; import com.festago.festival.dto.FestivalCreateRequest; +import com.festago.school.domain.School; +import com.festago.support.SchoolFixture; import java.time.LocalDate; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; @@ -20,10 +22,12 @@ class FestivalCreateRequestTest { "name", LocalDate.now(), LocalDate.now().plusDays(2L), - ""); + "", + 1L); + School school = SchoolFixture.school().build(); // when - Festival festival = request.toEntity(); + Festival festival = request.toEntity(school); // then assertThat(festival.getThumbnail()).isEqualTo("https://picsum.photos/536/354"); @@ -36,10 +40,12 @@ class FestivalCreateRequestTest { "name", LocalDate.now(), LocalDate.now().plusDays(2L), - "img"); + "img", + 1L); + School school = SchoolFixture.school().build(); // when - Festival festival = request.toEntity(); + Festival festival = request.toEntity(school); // then assertThat(festival.getThumbnail()).isEqualTo("img"); diff --git a/backend/src/test/java/com/festago/presentation/AdminControllerTest.java b/backend/src/test/java/com/festago/presentation/AdminControllerTest.java index a0fd0f50f..fa9f70c09 100644 --- a/backend/src/test/java/com/festago/presentation/AdminControllerTest.java +++ b/backend/src/test/java/com/festago/presentation/AdminControllerTest.java @@ -21,6 +21,9 @@ import com.festago.festival.application.FestivalService; import com.festago.festival.dto.FestivalCreateRequest; import com.festago.festival.dto.FestivalResponse; +import com.festago.school.application.SchoolService; +import com.festago.school.dto.SchoolCreateRequest; +import com.festago.school.dto.SchoolResponse; import com.festago.stage.application.StageService; import com.festago.stage.dto.StageCreateRequest; import com.festago.stage.dto.StageResponse; @@ -69,6 +72,9 @@ class AdminControllerTest { @MockBean AdminAuthService adminAuthService; + @MockBean + SchoolService schoolService; + @SpyBean AuthExtractor authExtractor; @@ -108,6 +114,34 @@ class AdminControllerTest { .andExpect(status().isOk()); } + @Test + @WithMockAuth(role = Role.ADMIN) + void 학교_생성() throws Exception { + // given + String domain = "festago.com"; + String name = "페스타고 대학교"; + + SchoolCreateRequest request = new SchoolCreateRequest(name, domain); + + SchoolResponse expected = new SchoolResponse(1L, domain, name); + + given(schoolService.create(any(SchoolCreateRequest.class))) + .willReturn(expected); + + // when && then + String content = mockMvc.perform(post("/admin/schools") + .content(objectMapper.writeValueAsString(request)) + .contentType(MediaType.APPLICATION_JSON) + .cookie(new Cookie("token", "token"))) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(StandardCharsets.UTF_8); + SchoolResponse actual = objectMapper.readValue(content, SchoolResponse.class); + assertThat(actual).isEqualTo(expected); + } + @Test @WithMockAuth(role = Role.ADMIN) void 축제_생성() throws Exception { @@ -121,7 +155,8 @@ class AdminControllerTest { festivalName, LocalDate.parse(startDate), LocalDate.parse(endDate), - ""); + "", + 1L); FestivalResponse expected = new FestivalResponse( 1L, diff --git a/backend/src/test/java/com/festago/support/FestivalFixture.java b/backend/src/test/java/com/festago/support/FestivalFixture.java index 39693181d..5e69ee864 100644 --- a/backend/src/test/java/com/festago/support/FestivalFixture.java +++ b/backend/src/test/java/com/festago/support/FestivalFixture.java @@ -1,6 +1,7 @@ package com.festago.support; import com.festago.festival.domain.Festival; +import com.festago.school.domain.School; import java.time.LocalDate; public class FestivalFixture { @@ -10,6 +11,7 @@ public class FestivalFixture { private LocalDate startDate = LocalDate.now(); private LocalDate endDate = LocalDate.now().plusDays(3L); private String thumbnail = "https://picsum.photos/536/354"; + private School school = SchoolFixture.school().build(); private FestivalFixture() { } @@ -43,7 +45,12 @@ public FestivalFixture thumbnail(String thumbnail) { return this; } + public FestivalFixture school(School school) { + this.school = school; + return this; + } + public Festival build() { - return new Festival(id, name, startDate, endDate, thumbnail); + return new Festival(id, name, startDate, endDate, thumbnail, school); } } diff --git a/backend/src/test/java/com/festago/support/SchoolFixture.java b/backend/src/test/java/com/festago/support/SchoolFixture.java new file mode 100644 index 000000000..357eb4a67 --- /dev/null +++ b/backend/src/test/java/com/festago/support/SchoolFixture.java @@ -0,0 +1,39 @@ +package com.festago.support; + +import com.festago.school.domain.School; + +public class SchoolFixture { + + private Long id; + + private String domain = "festago.com"; + + private String name = "페스타고 대학교"; + + private SchoolFixture() { + } + + public static SchoolFixture school() { + return new SchoolFixture(); + } + + public SchoolFixture id(Long id) { + this.id = id; + return this; + } + + public SchoolFixture domain(String domain) { + this.domain = domain; + return this; + } + + public SchoolFixture name(String name) { + this.name = name; + return this; + } + + public School build() { + return new School(id, domain, name); + } + +} diff --git a/backend/src/test/java/com/festago/support/TicketFixture.java b/backend/src/test/java/com/festago/support/TicketFixture.java index d84b18f25..266ab00be 100644 --- a/backend/src/test/java/com/festago/support/TicketFixture.java +++ b/backend/src/test/java/com/festago/support/TicketFixture.java @@ -9,6 +9,7 @@ public class TicketFixture { private Long id; private Stage stage = StageFixture.stage().build(); private TicketType ticketType = TicketType.VISITOR; + private Long schoolId = 1L; private TicketFixture() { } @@ -32,7 +33,12 @@ public TicketFixture ticketType(TicketType ticketType) { return this; } + public TicketFixture schoolId(Long schoolId) { + this.schoolId = schoolId; + return this; + } + public Ticket build() { - return new Ticket(id, stage, ticketType); + return new Ticket(id, stage, ticketType, schoolId); } } diff --git a/backend/src/test/java/com/festago/ticketing/application/TicketingServiceTest.java b/backend/src/test/java/com/festago/ticketing/application/TicketingServiceTest.java new file mode 100644 index 000000000..87a62e0e1 --- /dev/null +++ b/backend/src/test/java/com/festago/ticketing/application/TicketingServiceTest.java @@ -0,0 +1,82 @@ +package com.festago.ticketing.application; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; + +import com.festago.common.exception.BadRequestException; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; +import com.festago.stage.domain.Stage; +import com.festago.student.repository.StudentRepository; +import com.festago.support.MemberFixture; +import com.festago.support.TicketFixture; +import com.festago.ticket.domain.TicketType; +import com.festago.ticket.repository.TicketAmountRepository; +import com.festago.ticket.repository.TicketRepository; +import com.festago.ticketing.dto.TicketingRequest; +import com.festago.ticketing.repository.MemberTicketRepository; +import java.time.Clock; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +@DisplayNameGeneration(ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class TicketingServiceTest { + + @Mock + MemberTicketRepository memberTicketRepository; + + @Mock + TicketAmountRepository ticketAmountRepository; + + @Mock + TicketRepository ticketRepository; + + @Mock + MemberRepository memberRepository; + + @Mock + StudentRepository studentRepository; + + @Spy + Clock clock = Clock.systemDefaultZone(); + + @InjectMocks + TicketingService ticketingService; + + @BeforeEach + void setUp() { + + } + + @Test + void 재학생용_티켓인데_학생인증이_되지_않았으면_예외() { + // given + TicketingRequest request = new TicketingRequest(1L); + given(memberRepository.findById(anyLong())) + .willReturn(Optional.of(MemberFixture.member().build())); + given(memberTicketRepository.existsByOwnerAndStage(any(Member.class), any(Stage.class))) + .willReturn(false); + + given(ticketRepository.findByIdWithFetch(anyLong())) + .willReturn(Optional.of(TicketFixture.ticket().ticketType(TicketType.STUDENT).build())); + given(studentRepository.existsByMemberAndSchoolId(any(Member.class), anyLong())) + .willReturn(false); + + // when & then + assertThatThrownBy(() -> ticketingService.ticketing(1L, request)) + .isInstanceOf(BadRequestException.class) + .hasMessage("학생 인증이 필요합니다."); + } +} diff --git a/backend/src/test/resources/ticketing-test-data.sql b/backend/src/test/resources/ticketing-test-data.sql index a84d215d1..58a8894dc 100644 --- a/backend/src/test/resources/ticketing-test-data.sql +++ b/backend/src/test/resources/ticketing-test-data.sql @@ -1,11 +1,14 @@ -insert into festival (end_date, name, start_date, thumbnail) -values ('2023-07-30', '테코 대학교', '2023-08-02', ''); +insert into school (domain, name) +values ('festago.com', '페스타고 대학교'); + +insert into festival (school_id, end_date, name, start_date, thumbnail) +values (1, '2023-07-30', '테코 대학교', '2023-08-02', ''); insert into stage (festival_id, line_up, start_time, ticket_open_time) values (1, '', '2023-07-30T03:21:31.964676', '2023-07-23T03:21:31.964676'); -insert into ticket (stage_id, ticket_type) -values (1, 'VISITOR'); +insert into ticket (school_id, stage_id, ticket_type) +values (1, 1, 'VISITOR'); insert into ticket_amount (ticket_id, reserved_amount, total_amount) values (1, 0, 50); From 8f0ca1b68a28fd0b32a49b1f0efb7b6ff27dc96d Mon Sep 17 00:00:00 2001 From: xxeol2 Date: Tue, 26 Sep 2023 18:29:04 +0900 Subject: [PATCH 30/74] =?UTF-8?q?[BE]=20refactor:=20Ticket=EC=9D=98=20scho?= =?UTF-8?q?ol=20not=20null=20=EC=A0=9C=EC=95=BD=EC=A1=B0=EA=B1=B4=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20(#465)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Ticket의 school not null 제약조건 제거 * refactor: Ticket의 school not null 제약조건 제거 * refactor: Festival의 school not null 제약조건 제거 --- .../src/main/java/com/festago/festival/domain/Festival.java | 1 - backend/src/main/java/com/festago/ticket/domain/Ticket.java | 1 - backend/src/main/resources/db/migration/V4__add_school_fk.sql | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/festago/festival/domain/Festival.java b/backend/src/main/java/com/festago/festival/domain/Festival.java index 4d2a013d2..64602cc87 100644 --- a/backend/src/main/java/com/festago/festival/domain/Festival.java +++ b/backend/src/main/java/com/festago/festival/domain/Festival.java @@ -39,7 +39,6 @@ public class Festival extends BaseTimeEntity { @Size(max = 255) private String thumbnail; - @NotNull @ManyToOne(fetch = FetchType.LAZY) private School school; diff --git a/backend/src/main/java/com/festago/ticket/domain/Ticket.java b/backend/src/main/java/com/festago/ticket/domain/Ticket.java index 67f1604cf..fe873d0ff 100644 --- a/backend/src/main/java/com/festago/ticket/domain/Ticket.java +++ b/backend/src/main/java/com/festago/ticket/domain/Ticket.java @@ -39,7 +39,6 @@ public class Ticket extends BaseTimeEntity { @ManyToOne(fetch = FetchType.LAZY) private Stage stage; - @NotNull private Long schoolId; @NotNull diff --git a/backend/src/main/resources/db/migration/V4__add_school_fk.sql b/backend/src/main/resources/db/migration/V4__add_school_fk.sql index 42a816f19..bcdb2f62a 100644 --- a/backend/src/main/resources/db/migration/V4__add_school_fk.sql +++ b/backend/src/main/resources/db/migration/V4__add_school_fk.sql @@ -1,5 +1,5 @@ alter table ticket - add column school_id bigint not null; + add column school_id bigint; alter table ticket add constraint fk_ticket__school @@ -7,7 +7,7 @@ alter table ticket references school (id); alter table festival - add column school_id bigint not null; + add column school_id bigint; alter table festival add constraint fk_festival__school From 0a1f23783a949c84fa77e871315fe3dbe02e16b3 Mon Sep 17 00:00:00 2001 From: Guga Date: Tue, 26 Sep 2023 19:13:49 +0900 Subject: [PATCH 31/74] =?UTF-8?q?[BE]=20feat:=20=EC=8A=A4=ED=83=9C?= =?UTF-8?q?=ED=94=84=20=EC=9D=B8=EC=A6=9D=20=EC=B2=98=EB=A6=AC=EC=8B=9C=20?= =?UTF-8?q?FCM=20=EC=9D=84=20=ED=86=B5=ED=95=B4=20=EC=9C=A0=EC=A0=80=20?= =?UTF-8?q?=ED=95=B8=EB=93=9C=ED=8F=B0=EC=97=90=20=EC=9E=85=EC=9E=A5=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=99=84=EB=A3=8C=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20=EB=B3=B4=EB=82=B8=EB=8B=A4(#444)=20(#449)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: FCMConfig 생성 * chore: FCMConfig 패키지 이동 * feat: MemberFCM 생성 * feat: MemberFCMService 생성 * feat: NotificationFacade 생성 * feat: 로그인 시 fcm 을 등록한다. * feat: 입장 처리 시 EntryProcessEvent 를 발행한다. * feat: 유저 탈퇴시 유저의 FCM 을 모두 삭제한다. * feat: 테스트 환경에서 FirebaseMessaging 을 MockBean 으로 등록한다 * chore: 테스트 컨벤션 적용 * chore: Notification -> FCMNotificationFacade 네이밍 변견 * feat: flyway 추가 * chore: 마지막 줄 개행 추가 * feat: submodule 업데이트 * refactor: 메서드 네이밍, 메서드 순서, 파라미터 순서 변경 * refactor: fcm bean 을 테스트에서 제외 * feat: EventListener phase 명시 * chore: FCMEventListener 네이밍 변경 * feat: MemberFCM 의 Member 의존성 제거 * chore: EntryProcessEvent 패키지 분리 * refactor: AuthService 가 MemberFCM 을 의존하지 않도록 변경 * feat: MemberFCM 빈 생성자 추가 * chore: flyway version 변경 * feat: FCMChannel 을 Enum 으로 관리 * chore: 메서드 접근자 및 네이밍 변경, log 메세지 변경 * feat: local prod, dev 환경에서만 FCM Bean 들이 생성되도록 변경 * refactor: eventListen 로직을 비동기적으로 처리한다 * refactor: LoginService 와 MemberFCMService 를 분리한다 * chore: 파라미터 네이밍 변경 * chore: logger -> log 네이밍 변경 * chore: log 메시지 변경 * chore: flyway 버전 변경 --- backend/build.gradle | 3 + .../auth/application/AuthFacadeService.java | 13 +-- .../festago/auth/application/AuthService.java | 19 ++-- .../com/festago/auth/dto/LoginRequest.java | 3 +- .../festago/common/exception/ErrorCode.java | 3 +- .../entry/application/EntryService.java | 8 +- .../entry/dto/event/EntryProcessEvent.java | 6 ++ .../FCMNotificationEventListener.java | 90 +++++++++++++++++++ .../fcm/application/MemberFCMService.java | 48 ++++++++++ .../com/festago/fcm/config/FCMConfig.java | 58 ++++++++++++ .../com/festago/fcm/domain/FCMChannel.java | 5 ++ .../com/festago/fcm/domain/MemberFCM.java | 56 ++++++++++++ .../festago/fcm/dto/MemberFCMResponse.java | 18 ++++ .../festago/fcm/dto/MemberFCMsResponse.java | 17 ++++ .../fcm/repository/MemberFCMRepository.java | 10 +++ .../festago/presentation/AuthController.java | 8 +- .../db/migration/V5__MembeFCM_Added.sql | 16 ++++ .../festago/application/EntryServiceTest.java | 8 ++ .../application/AuthFacadeServiceTest.java | 5 +- .../AuthFacadeServiceIntegrationTest.java | 6 +- .../auth/presentation/AuthControllerTest.java | 8 +- .../FCMNotificationEventListenerTest.java | 75 ++++++++++++++++ .../fcm/application/MemberFCMServiceTest.java | 72 +++++++++++++++ .../repository/MemberFCMRepositoryTest.java | 36 ++++++++ 24 files changed, 564 insertions(+), 27 deletions(-) create mode 100644 backend/src/main/java/com/festago/entry/dto/event/EntryProcessEvent.java create mode 100644 backend/src/main/java/com/festago/fcm/application/FCMNotificationEventListener.java create mode 100644 backend/src/main/java/com/festago/fcm/application/MemberFCMService.java create mode 100644 backend/src/main/java/com/festago/fcm/config/FCMConfig.java create mode 100644 backend/src/main/java/com/festago/fcm/domain/FCMChannel.java create mode 100644 backend/src/main/java/com/festago/fcm/domain/MemberFCM.java create mode 100644 backend/src/main/java/com/festago/fcm/dto/MemberFCMResponse.java create mode 100644 backend/src/main/java/com/festago/fcm/dto/MemberFCMsResponse.java create mode 100644 backend/src/main/java/com/festago/fcm/repository/MemberFCMRepository.java create mode 100644 backend/src/main/resources/db/migration/V5__MembeFCM_Added.sql create mode 100644 backend/src/test/java/com/festago/fcm/application/FCMNotificationEventListenerTest.java create mode 100644 backend/src/test/java/com/festago/fcm/application/MemberFCMServiceTest.java create mode 100644 backend/src/test/java/com/festago/fcm/repository/MemberFCMRepositoryTest.java diff --git a/backend/build.gradle b/backend/build.gradle index d36481f4e..54a71cbfe 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -47,6 +47,9 @@ dependencies { // Flyway implementation 'org.flywaydb:flyway-core' implementation 'org.flywaydb:flyway-mysql' + + // Firebase + implementation 'com.google.firebase:firebase-admin:8.1.0' } tasks.named('test') { diff --git a/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java b/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java index b87ffea85..3e8a22347 100644 --- a/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java +++ b/backend/src/main/java/com/festago/auth/application/AuthFacadeService.java @@ -2,9 +2,9 @@ import com.festago.auth.domain.AuthPayload; import com.festago.auth.domain.Role; +import com.festago.auth.domain.SocialType; import com.festago.auth.domain.UserInfo; import com.festago.auth.dto.LoginMemberDto; -import com.festago.auth.dto.LoginRequest; import com.festago.auth.dto.LoginResponse; import org.springframework.stereotype.Service; @@ -22,8 +22,9 @@ public AuthFacadeService(AuthService authService, OAuth2Clients oAuth2Clients, this.authProvider = authProvider; } - public LoginResponse login(LoginRequest request) { - LoginMemberDto loginMember = authService.login(getUserInfo(request)); + public LoginResponse login(SocialType socialType, String oAuthToken) { + UserInfo userInfo = getUserInfo(socialType, oAuthToken); + LoginMemberDto loginMember = authService.login(userInfo); String accessToken = getAccessToken(loginMember.memberId()); return LoginResponse.of(accessToken, loginMember); } @@ -32,9 +33,9 @@ private String getAccessToken(Long memberId) { return authProvider.provide(new AuthPayload(memberId, Role.MEMBER)); } - private UserInfo getUserInfo(LoginRequest request) { - OAuth2Client oAuth2Client = oAuth2Clients.getClient(request.socialType()); - return oAuth2Client.getUserInfo(request.accessToken()); + private UserInfo getUserInfo(SocialType socialType, String oAuthToken) { + OAuth2Client oAuth2Client = oAuth2Clients.getClient(socialType); + return oAuth2Client.getUserInfo(oAuthToken); } public void deleteMember(Long memberId) { diff --git a/backend/src/main/java/com/festago/auth/application/AuthService.java b/backend/src/main/java/com/festago/auth/application/AuthService.java index f559d219b..63101e914 100644 --- a/backend/src/main/java/com/festago/auth/application/AuthService.java +++ b/backend/src/main/java/com/festago/auth/application/AuthService.java @@ -6,6 +6,7 @@ import com.festago.common.exception.NotFoundException; import com.festago.member.domain.Member; import com.festago.member.repository.MemberRepository; +import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -24,12 +25,18 @@ public AuthService(MemberRepository memberRepository) { } public LoginMemberDto login(UserInfo userInfo) { - return memberRepository.findBySocialIdAndSocialType(userInfo.socialId(), userInfo.socialType()) - .map(LoginMemberDto::isExists) - .orElseGet(() -> { - Member member = signUp(userInfo); - return LoginMemberDto.isNew(member); - }); + LoginMemberDto loginMemberDto = handleLoginRequest(userInfo); + return loginMemberDto; + } + + public LoginMemberDto handleLoginRequest(UserInfo userInfo) { + Optional originMember = memberRepository.findBySocialIdAndSocialType(userInfo.socialId(), userInfo.socialType()); + if (originMember.isPresent()) { + Member member = originMember.get(); + return LoginMemberDto.isExists(member); + } + Member newMember = signUp(userInfo); + return LoginMemberDto.isNew(newMember); } private Member signUp(UserInfo userInfo) { diff --git a/backend/src/main/java/com/festago/auth/dto/LoginRequest.java b/backend/src/main/java/com/festago/auth/dto/LoginRequest.java index 8f82722aa..d05066b51 100644 --- a/backend/src/main/java/com/festago/auth/dto/LoginRequest.java +++ b/backend/src/main/java/com/festago/auth/dto/LoginRequest.java @@ -5,6 +5,7 @@ public record LoginRequest( @NotNull(message = "socialType 은 null 일 수 없습니다.") SocialType socialType, - @NotNull(message = "acessToken 은 null 일 수 없습니다.") String accessToken) { + @NotNull(message = "acessToken 은 null 일 수 없습니다.") String accessToken, + @NotNull(message = "fcmToken 은 null 일 수 없습니다.") String fcmToken) { } diff --git a/backend/src/main/java/com/festago/common/exception/ErrorCode.java b/backend/src/main/java/com/festago/common/exception/ErrorCode.java index e143257d8..bd3708054 100644 --- a/backend/src/main/java/com/festago/common/exception/ErrorCode.java +++ b/backend/src/main/java/com/festago/common/exception/ErrorCode.java @@ -58,7 +58,8 @@ public enum ErrorCode { INVALID_ENTRY_CODE_OFFSET("올바르지 않은 입장코드 오프셋입니다."), INVALID_ROLE_NAME("해당하는 Role이 없습니다."), FOR_TEST_ERROR("테스트용 에러입니다."), - ; + FAIL_SEND_FCM_MESSAGE("FCM Message 전송에 실패했습니다."), + FCM_NOT_FOUND("유효하지 않은 MemberFCM 이 감지 되었습니다."); private final String message; diff --git a/backend/src/main/java/com/festago/entry/application/EntryService.java b/backend/src/main/java/com/festago/entry/application/EntryService.java index 1e2f23ec3..68602f67e 100644 --- a/backend/src/main/java/com/festago/entry/application/EntryService.java +++ b/backend/src/main/java/com/festago/entry/application/EntryService.java @@ -8,10 +8,12 @@ import com.festago.entry.dto.EntryCodeResponse; import com.festago.entry.dto.TicketValidationRequest; import com.festago.entry.dto.TicketValidationResponse; +import com.festago.entry.dto.event.EntryProcessEvent; import com.festago.ticketing.domain.MemberTicket; import com.festago.ticketing.repository.MemberTicketRepository; import java.time.Clock; import java.time.LocalDateTime; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -21,11 +23,14 @@ public class EntryService { private final EntryCodeManager entryCodeManager; private final MemberTicketRepository memberTicketRepository; + private final ApplicationEventPublisher publisher; private final Clock clock; - public EntryService(EntryCodeManager entryCodeManager, MemberTicketRepository memberTicketRepository, Clock clock) { + public EntryService(EntryCodeManager entryCodeManager, MemberTicketRepository memberTicketRepository, + ApplicationEventPublisher publisher, Clock clock) { this.entryCodeManager = entryCodeManager; this.memberTicketRepository = memberTicketRepository; + this.publisher = publisher; this.clock = clock; } @@ -50,6 +55,7 @@ public TicketValidationResponse validate(TicketValidationRequest request) { EntryCodePayload entryCodePayload = entryCodeManager.extract(request.code()); MemberTicket memberTicket = findMemberTicket(entryCodePayload.getMemberTicketId()); memberTicket.changeState(entryCodePayload.getEntryState()); + publisher.publishEvent(new EntryProcessEvent(memberTicket.getOwner().getId())); return TicketValidationResponse.from(memberTicket); } } diff --git a/backend/src/main/java/com/festago/entry/dto/event/EntryProcessEvent.java b/backend/src/main/java/com/festago/entry/dto/event/EntryProcessEvent.java new file mode 100644 index 000000000..d94ac71d9 --- /dev/null +++ b/backend/src/main/java/com/festago/entry/dto/event/EntryProcessEvent.java @@ -0,0 +1,6 @@ +package com.festago.entry.dto.event; + +public record EntryProcessEvent( + Long memberId) { + +} diff --git a/backend/src/main/java/com/festago/fcm/application/FCMNotificationEventListener.java b/backend/src/main/java/com/festago/fcm/application/FCMNotificationEventListener.java new file mode 100644 index 000000000..1de6c5418 --- /dev/null +++ b/backend/src/main/java/com/festago/fcm/application/FCMNotificationEventListener.java @@ -0,0 +1,90 @@ +package com.festago.fcm.application; + +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; +import com.festago.entry.dto.event.EntryProcessEvent; +import com.festago.fcm.domain.FCMChannel; +import com.festago.fcm.dto.MemberFCMResponse; +import com.google.firebase.messaging.AndroidConfig; +import com.google.firebase.messaging.AndroidNotification; +import com.google.firebase.messaging.BatchResponse; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.FirebaseMessagingException; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.SendResponse; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; + +@Component +@Profile({"dev", "prod"}) +public class FCMNotificationEventListener { + + private static final Logger log = LoggerFactory.getLogger(FCMNotificationEventListener.class); + + private final FirebaseMessaging firebaseMessaging; + private final MemberFCMService memberFCMService; + + public FCMNotificationEventListener(FirebaseMessaging firebaseMessaging, MemberFCMService memberFCMService) { + this.firebaseMessaging = firebaseMessaging; + this.memberFCMService = memberFCMService; + } + + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) + @Async + public void sendFcmNotification(EntryProcessEvent event) { + List messages = createMessages(getMemberFCMToken(event.memberId()), FCMChannel.NOT_DEFINED.name()); + try { + BatchResponse batchResponse = firebaseMessaging.sendAll(messages); + checkAllSuccess(batchResponse, event.memberId()); + } catch (FirebaseMessagingException e) { + log.error("fail send FCM message", e); + throw new InternalServerException(ErrorCode.FAIL_SEND_FCM_MESSAGE); + } + } + + private List getMemberFCMToken(Long memberId) { + return memberFCMService.findMemberFCM(memberId).memberFCMs().stream() + .map(MemberFCMResponse::fcmToken) + .toList(); + } + + private List createMessages(List tokens, String channelId) { + return tokens.stream() + .map(token -> createMessage(token, channelId)) + .toList(); + } + + private Message createMessage(String token, String channelId) { + return Message.builder() + .setAndroidConfig(createAndroidConfig(channelId)) + .setToken(token) + .build(); + } + + private AndroidConfig createAndroidConfig(String channelId) { + return AndroidConfig.builder() + .setNotification(createAndroidNotification(channelId)) + .build(); + } + + private AndroidNotification createAndroidNotification(String channelId) { + return AndroidNotification.builder() + .setChannelId(channelId) + .build(); + } + + private void checkAllSuccess(BatchResponse batchResponse, Long memberId) { + List failSend = batchResponse.getResponses().stream() + .filter(sendResponse -> !sendResponse.isSuccessful()) + .toList(); + + log.warn("member {} 에 대한 다음 요청들이 실패했습니다. {}", memberId, failSend); + throw new InternalServerException(ErrorCode.FAIL_SEND_FCM_MESSAGE); + } +} diff --git a/backend/src/main/java/com/festago/fcm/application/MemberFCMService.java b/backend/src/main/java/com/festago/fcm/application/MemberFCMService.java new file mode 100644 index 000000000..e044feb7a --- /dev/null +++ b/backend/src/main/java/com/festago/fcm/application/MemberFCMService.java @@ -0,0 +1,48 @@ +package com.festago.fcm.application; + +import com.festago.auth.application.AuthExtractor; +import com.festago.auth.domain.AuthPayload; +import com.festago.common.exception.ErrorCode; +import com.festago.common.exception.InternalServerException; +import com.festago.fcm.domain.MemberFCM; +import com.festago.fcm.dto.MemberFCMsResponse; +import com.festago.fcm.repository.MemberFCMRepository; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class MemberFCMService { + + private static final Logger log = LoggerFactory.getLogger(MemberFCMService.class); + private static final int LEAST_MEMBER_FCM = 1; + + private final MemberFCMRepository memberFCMRepository; + private final AuthExtractor authExtractor; + + public MemberFCMService(MemberFCMRepository memberFCMRepository, AuthExtractor authExtractor) { + this.memberFCMRepository = memberFCMRepository; + this.authExtractor = authExtractor; + } + + @Transactional(readOnly = true) + public MemberFCMsResponse findMemberFCM(Long memberId) { + List memberFCM = memberFCMRepository.findByMemberId(memberId); + if (memberFCM.size() < LEAST_MEMBER_FCM) { + log.error("member {} 의 FCM 토큰이 발급되지 않았습니다.", memberId); + throw new InternalServerException(ErrorCode.FCM_NOT_FOUND); + } + return MemberFCMsResponse.from(memberFCM); + } + + @Async + public void saveMemberFCM(String accessToken, String fcmToken) { + AuthPayload authPayload = authExtractor.extract(accessToken); + Long memberId = authPayload.getMemberId(); + memberFCMRepository.save(new MemberFCM(memberId, fcmToken)); + } +} diff --git a/backend/src/main/java/com/festago/fcm/config/FCMConfig.java b/backend/src/main/java/com/festago/fcm/config/FCMConfig.java new file mode 100644 index 000000000..93b3dfab2 --- /dev/null +++ b/backend/src/main/java/com/festago/fcm/config/FCMConfig.java @@ -0,0 +1,58 @@ +package com.festago.fcm.config; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.messaging.FirebaseMessaging; +import java.io.IOException; +import java.util.List; +import java.util.Optional; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.io.ClassPathResource; + +@Configuration +@Profile({"prod", "dev"}) +public class FCMConfig { + + @Value("${fcm.key.path}") + private String fcmPrivateKeyPath; + + @Value("${fcm.key.scope}") + private String fireBaseScope; + + @Bean + public FirebaseMessaging firebaseMessaging() throws IOException { + Optional defaultFirebaseApp = defaultFirebaseApp(); + if (defaultFirebaseApp.isPresent()) { + return FirebaseMessaging.getInstance(defaultFirebaseApp.get()); + } + return FirebaseMessaging.getInstance( + FirebaseApp.initializeApp(createFirebaseOption()) + ); + } + + private Optional defaultFirebaseApp() { + List firebaseAppList = FirebaseApp.getApps(); + if (firebaseAppList == null || firebaseAppList.isEmpty()) { + return Optional.empty(); + } + return firebaseAppList.stream() + .filter(firebaseApp -> firebaseApp.getName().equals(FirebaseApp.DEFAULT_APP_NAME)) + .findAny(); + } + + private FirebaseOptions createFirebaseOption() throws IOException { + return FirebaseOptions.builder() + .setCredentials(createGoogleCredentials()) + .build(); + } + + private GoogleCredentials createGoogleCredentials() throws IOException { + return GoogleCredentials + .fromStream(new ClassPathResource(fcmPrivateKeyPath).getInputStream()) + .createScoped(fireBaseScope); + } +} diff --git a/backend/src/main/java/com/festago/fcm/domain/FCMChannel.java b/backend/src/main/java/com/festago/fcm/domain/FCMChannel.java new file mode 100644 index 000000000..836622edf --- /dev/null +++ b/backend/src/main/java/com/festago/fcm/domain/FCMChannel.java @@ -0,0 +1,5 @@ +package com.festago.fcm.domain; + +public enum FCMChannel { + NOT_DEFINED; +} diff --git a/backend/src/main/java/com/festago/fcm/domain/MemberFCM.java b/backend/src/main/java/com/festago/fcm/domain/MemberFCM.java new file mode 100644 index 000000000..8a97f7f07 --- /dev/null +++ b/backend/src/main/java/com/festago/fcm/domain/MemberFCM.java @@ -0,0 +1,56 @@ +package com.festago.fcm.domain; + +import com.festago.common.domain.BaseTimeEntity; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; + +@Entity +@Table(name = "member_fcm") +public class MemberFCM extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + private Long memberId; + + @NotNull + private String fcmToken; + + protected MemberFCM() { + } + + public MemberFCM(Long memberId, String fcmToken) { + this(null, memberId, fcmToken); + } + + public MemberFCM(Long id, Long memberId, String fcmToken) { + validate(memberId, fcmToken); + this.id = id; + this.memberId = memberId; + this.fcmToken = fcmToken; + } + + private void validate(Long memberId, String fcmToken) { + if (memberId == null || fcmToken == null) { + throw new IllegalArgumentException("MemberFCM 은 허용되지 않은 null 값으로 생성할 수 없습니다."); + } + } + + public Long getId() { + return id; + } + + public Long getMemberId() { + return memberId; + } + + public String getFcmToken() { + return fcmToken; + } +} diff --git a/backend/src/main/java/com/festago/fcm/dto/MemberFCMResponse.java b/backend/src/main/java/com/festago/fcm/dto/MemberFCMResponse.java new file mode 100644 index 000000000..61f252a9b --- /dev/null +++ b/backend/src/main/java/com/festago/fcm/dto/MemberFCMResponse.java @@ -0,0 +1,18 @@ +package com.festago.fcm.dto; + +import com.festago.fcm.domain.MemberFCM; + +public record MemberFCMResponse( + Long id, + Long memberId, + String fcmToken +) { + + public static MemberFCMResponse from(MemberFCM memberFCM) { + return new MemberFCMResponse( + memberFCM.getId(), + memberFCM.getMemberId(), + memberFCM.getFcmToken() + ); + } +} diff --git a/backend/src/main/java/com/festago/fcm/dto/MemberFCMsResponse.java b/backend/src/main/java/com/festago/fcm/dto/MemberFCMsResponse.java new file mode 100644 index 000000000..80df8a602 --- /dev/null +++ b/backend/src/main/java/com/festago/fcm/dto/MemberFCMsResponse.java @@ -0,0 +1,17 @@ +package com.festago.fcm.dto; + +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.toList; + +import com.festago.fcm.domain.MemberFCM; +import java.util.List; + +public record MemberFCMsResponse(List memberFCMs +) { + + public static MemberFCMsResponse from(List memberFCMs) { + return memberFCMs.stream() + .map(MemberFCMResponse::from) + .collect(collectingAndThen(toList(), MemberFCMsResponse::new)); + } +} diff --git a/backend/src/main/java/com/festago/fcm/repository/MemberFCMRepository.java b/backend/src/main/java/com/festago/fcm/repository/MemberFCMRepository.java new file mode 100644 index 000000000..e5bee3719 --- /dev/null +++ b/backend/src/main/java/com/festago/fcm/repository/MemberFCMRepository.java @@ -0,0 +1,10 @@ +package com.festago.fcm.repository; + +import com.festago.fcm.domain.MemberFCM; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberFCMRepository extends JpaRepository { + + List findByMemberId(Long memberId); +} diff --git a/backend/src/main/java/com/festago/presentation/AuthController.java b/backend/src/main/java/com/festago/presentation/AuthController.java index 9d0e83f6f..36038cdbf 100644 --- a/backend/src/main/java/com/festago/presentation/AuthController.java +++ b/backend/src/main/java/com/festago/presentation/AuthController.java @@ -4,6 +4,7 @@ import com.festago.auth.application.AuthFacadeService; import com.festago.auth.dto.LoginRequest; import com.festago.auth.dto.LoginResponse; +import com.festago.fcm.application.MemberFCMService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; @@ -20,15 +21,18 @@ public class AuthController { private final AuthFacadeService authFacadeService; + private final MemberFCMService memberFCMService; - public AuthController(AuthFacadeService authFacadeService) { + public AuthController(AuthFacadeService authFacadeService, MemberFCMService memberFCMService) { this.authFacadeService = authFacadeService; + this.memberFCMService = memberFCMService; } @PostMapping("/oauth2") @Operation(description = "소셜 엑세스 토큰을 기반으로 로그인 요청을 보낸다.", summary = "OAuth2 로그인") public ResponseEntity login(@RequestBody LoginRequest request) { - LoginResponse response = authFacadeService.login(request); + LoginResponse response = authFacadeService.login(request.socialType(), request.accessToken()); + memberFCMService.saveMemberFCM(response.accessToken(), request.fcmToken()); return ResponseEntity.ok() .body(response); } diff --git a/backend/src/main/resources/db/migration/V5__MembeFCM_Added.sql b/backend/src/main/resources/db/migration/V5__MembeFCM_Added.sql new file mode 100644 index 000000000..f71564c9d --- /dev/null +++ b/backend/src/main/resources/db/migration/V5__MembeFCM_Added.sql @@ -0,0 +1,16 @@ +create table if not exists member_fcm +( + id bigint not null auto_increment, + created_at datetime(6), + updated_at datetime(6), + member_id bigint, + fcm_token varchar(255), + primary key (id) +) engine innodb + default charset = utf8mb4 + collate = utf8mb4_0900_ai_ci; + +alter table member_fcm + add constraint fk_member_fcm__member + foreign key (member_id) + references member (id); diff --git a/backend/src/test/java/com/festago/application/EntryServiceTest.java b/backend/src/test/java/com/festago/application/EntryServiceTest.java index 962c1a3af..4da22514a 100644 --- a/backend/src/test/java/com/festago/application/EntryServiceTest.java +++ b/backend/src/test/java/com/festago/application/EntryServiceTest.java @@ -6,6 +6,8 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.anyLong; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import com.festago.common.exception.BadRequestException; import com.festago.common.exception.NotFoundException; @@ -16,6 +18,7 @@ import com.festago.entry.dto.EntryCodeResponse; import com.festago.entry.dto.TicketValidationRequest; import com.festago.entry.dto.TicketValidationResponse; +import com.festago.entry.dto.event.EntryProcessEvent; import com.festago.festival.domain.Festival; import com.festago.member.domain.Member; import com.festago.stage.domain.Stage; @@ -42,6 +45,7 @@ import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ApplicationEventPublisher; @ExtendWith(MockitoExtension.class) @DisplayNameGeneration(ReplaceUnderscores.class) @@ -54,6 +58,9 @@ class EntryServiceTest { @Mock MemberTicketRepository memberTicketRepository; + @Mock + ApplicationEventPublisher publisher; + @Spy Clock clock = Clock.systemDefaultZone(); @@ -246,6 +253,7 @@ class 티켓_검사 { softly.assertThat(memberTicket.getEntryState()).isEqualTo(EntryState.BEFORE_ENTRY); softly.assertThat(expect.updatedState()).isEqualTo(EntryState.BEFORE_ENTRY); }); + verify(publisher, times(1)).publishEvent(any(EntryProcessEvent.class)); } } } diff --git a/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java b/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java index e953d8e06..f2f51ef1a 100644 --- a/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java +++ b/backend/src/test/java/com/festago/auth/application/AuthFacadeServiceTest.java @@ -9,7 +9,6 @@ import com.festago.auth.domain.SocialType; import com.festago.auth.domain.UserInfo; import com.festago.auth.dto.LoginMemberDto; -import com.festago.auth.dto.LoginRequest; import com.festago.auth.dto.LoginResponse; import com.festago.auth.infrastructure.FestagoOAuth2Client; import com.festago.member.domain.Member; @@ -45,8 +44,6 @@ void setUp() { @Test void 로그인() { - LoginRequest request = new LoginRequest(SocialType.FESTAGO, "1"); - Member member = MemberFixture.member() .id(1L) .build(); @@ -58,7 +55,7 @@ void setUp() { .willReturn(new LoginMemberDto(false, member.getId(), member.getNickname())); // when - LoginResponse response = authFacadeService.login(request); + LoginResponse response = authFacadeService.login(SocialType.FESTAGO, "1"); // then assertThat(response) diff --git a/backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java b/backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java index 0724545a0..4024fe487 100644 --- a/backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java +++ b/backend/src/test/java/com/festago/auth/application/integration/AuthFacadeServiceIntegrationTest.java @@ -6,7 +6,6 @@ import com.festago.application.integration.ApplicationIntegrationTest; import com.festago.auth.application.AuthFacadeService; import com.festago.auth.domain.SocialType; -import com.festago.auth.dto.LoginRequest; import com.festago.member.domain.Member; import com.festago.member.repository.MemberRepository; import com.festago.support.MemberFixture; @@ -33,13 +32,12 @@ class AuthFacadeServiceIntegrationTest extends ApplicationIntegrationTest { @Test void 회원이_탈퇴하고_재가입하면_새로운_계정으로_가입() { // given - LoginRequest request = new LoginRequest(SocialType.FESTAGO, "1"); - authFacadeService.login(request); + authFacadeService.login(SocialType.FESTAGO, "1"); Member member = memberRepository.findBySocialIdAndSocialType("1", SocialType.FESTAGO).get(); // when memberRepository.delete(member); - authFacadeService.login(request); + authFacadeService.login(SocialType.FESTAGO, "1"); // then assertThat(memberRepository.count()).isEqualTo(1); diff --git a/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java b/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java index 281261a03..19c22eb68 100644 --- a/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java +++ b/backend/src/test/java/com/festago/auth/presentation/AuthControllerTest.java @@ -14,6 +14,7 @@ import com.festago.auth.domain.SocialType; import com.festago.auth.dto.LoginRequest; import com.festago.auth.dto.LoginResponse; +import com.festago.fcm.application.MemberFCMService; import com.festago.presentation.AuthController; import com.festago.support.CustomWebMvcTest; import com.festago.support.WithMockAuth; @@ -39,13 +40,16 @@ class AuthControllerTest { @MockBean AuthFacadeService authFacadeService; + @MockBean + MemberFCMService memberFCMService; + @Test void OAuth2_로그인을_한다() throws Exception { // given LoginResponse expected = new LoginResponse("accesstoken", "nickname", true); - given(authFacadeService.login(any(LoginRequest.class))) + given(authFacadeService.login(any(), any())) .willReturn(expected); - LoginRequest request = new LoginRequest(SocialType.FESTAGO, "code"); + LoginRequest request = new LoginRequest(SocialType.FESTAGO, "code", "fcmToken"); // when & then String response = mockMvc.perform(post("/auth/oauth2") diff --git a/backend/src/test/java/com/festago/fcm/application/FCMNotificationEventListenerTest.java b/backend/src/test/java/com/festago/fcm/application/FCMNotificationEventListenerTest.java new file mode 100644 index 000000000..795aa245c --- /dev/null +++ b/backend/src/test/java/com/festago/fcm/application/FCMNotificationEventListenerTest.java @@ -0,0 +1,75 @@ +package com.festago.fcm.application; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.festago.common.exception.InternalServerException; +import com.festago.entry.dto.event.EntryProcessEvent; +import com.festago.fcm.dto.MemberFCMResponse; +import com.festago.fcm.dto.MemberFCMsResponse; +import com.google.firebase.messaging.BatchResponse; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.FirebaseMessagingException; +import com.google.firebase.messaging.SendResponse; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@DisplayNameGeneration(ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +@ExtendWith(MockitoExtension.class) +class FCMNotificationEventListenerTest { + + @Mock + FirebaseMessaging firebaseMessaging; + + @Mock + MemberFCMService memberFCMService; + + @InjectMocks + FCMNotificationEventListener FCMNotificationEventListener; + + @Test + void 유저의_FCM_요청_중_하나라도_실패하면_예외() throws FirebaseMessagingException { + // given + given(memberFCMService.findMemberFCM(anyLong())).willReturn( + new MemberFCMsResponse(List.of(new MemberFCMResponse(1L, 1L, "token1"), new MemberFCMResponse(2L, 1L, "token2")))); + + given(firebaseMessaging.sendAll(any())).willReturn(new MockBatchResponse()); + + EntryProcessEvent event = new EntryProcessEvent(1L); + + // when & then + Assertions.assertThatThrownBy(() -> FCMNotificationEventListener.sendFcmNotification(event)) + .isInstanceOf(InternalServerException.class); + } + + private static class MockBatchResponse implements BatchResponse { + + @Override + public List getResponses() { + SendResponse mockResponse = mock(SendResponse.class); + when(mockResponse.isSuccessful()).thenReturn(false); + return List.of(mockResponse, mockResponse); + } + + @Override + public int getSuccessCount() { + return 0; + } + + @Override + public int getFailureCount() { + return 0; + } + } +} diff --git a/backend/src/test/java/com/festago/fcm/application/MemberFCMServiceTest.java b/backend/src/test/java/com/festago/fcm/application/MemberFCMServiceTest.java new file mode 100644 index 000000000..dd8eb7d46 --- /dev/null +++ b/backend/src/test/java/com/festago/fcm/application/MemberFCMServiceTest.java @@ -0,0 +1,72 @@ +package com.festago.fcm.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.festago.auth.application.AuthExtractor; +import com.festago.auth.domain.AuthPayload; +import com.festago.auth.domain.Role; +import com.festago.fcm.domain.MemberFCM; +import com.festago.fcm.dto.MemberFCMResponse; +import com.festago.fcm.repository.MemberFCMRepository; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class MemberFCMServiceTest { + + @Mock + MemberFCMRepository memberFCMRepository; + + @Mock + AuthExtractor authExtractor; + + @InjectMocks + MemberFCMService memberFCMService; + + @Test + void 유저의_FCM_정보를_가져온다() { + // given + List memberFCMS = List.of( + new MemberFCM(1L, 1L, "token"), + new MemberFCM(2L, 1L, "token2") + ); + given(memberFCMRepository.findByMemberId(anyLong())) + .willReturn(memberFCMS); + + List expect = memberFCMS.stream() + .map(MemberFCMResponse::from) + .collect(Collectors.toList()); + + // when + List actual = memberFCMService.findMemberFCM(1L).memberFCMs(); + + // then + assertThat(actual).isEqualTo(expect); + } + + @Test + void 유저의_FCM_저장() { + // given + String accessToken = "accessToken"; + String fcmToken = "fcmToken"; + given(authExtractor.extract(any())) + .willReturn(new AuthPayload(1L, Role.MEMBER)); + + // when + memberFCMService.saveMemberFCM(accessToken, fcmToken); + + // then + verify(memberFCMRepository, times(1)) + .save(any(MemberFCM.class)); + } +} diff --git a/backend/src/test/java/com/festago/fcm/repository/MemberFCMRepositoryTest.java b/backend/src/test/java/com/festago/fcm/repository/MemberFCMRepositoryTest.java new file mode 100644 index 000000000..3ea135724 --- /dev/null +++ b/backend/src/test/java/com/festago/fcm/repository/MemberFCMRepositoryTest.java @@ -0,0 +1,36 @@ +package com.festago.fcm.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.festago.auth.domain.SocialType; +import com.festago.fcm.domain.MemberFCM; +import com.festago.member.domain.Member; +import com.festago.member.repository.MemberRepository; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +@DataJpaTest +class MemberFCMRepositoryTest { + + @Autowired + MemberFCMRepository memberFCMRepository; + + @Autowired + MemberRepository memberRepository; + + @Test + void member_의_MemberFCM_을_찾을_수_있다() { + // given + Member member = memberRepository.save(new Member("socialId", SocialType.FESTAGO, "nickname", "image.jpg")); + Long memberId = member.getId(); + MemberFCM expect = memberFCMRepository.save(new MemberFCM(memberId, "fcmToken")); + + // when + List actual = memberFCMRepository.findByMemberId(memberId); + + // then + assertThat(actual).contains(expect); + } +} From b0f8788358b328ca584fb4436e3c0c2db64d8d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=95=B4=EC=8B=9C?= <67777523+EmilyCh0@users.noreply.github.com> Date: Wed, 27 Sep 2023 11:22:03 +0900 Subject: [PATCH 32/74] =?UTF-8?q?[AN/USER]=20feat:=20=ED=95=99=EA=B5=90=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84(#3?= =?UTF-8?q?74)=20(#461)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 학교 선택 화면 구현 * feat: 학교 조회 api 연결 * feat: 학교 선택 화면 이동 * refactor: 뷰모델 init 대신 액티비티에서 호출하도록 수정 * test: 학교 선택 화면 테스트 작성 * refactor: SchoolUiState 제거 * feat: 로딩, 에러 화면 처리 * refactor: 불필요한 프로퍼티 제거 * feat: 학교 선택 상단 제목 추가 * test: analyticsHelper relaxed true 설정 * refactor: 파라미터 순서 변경 * fix: 화면 회전 시 schoolSelected 값 유지되도록 수정 --- .../festago/app/src/main/AndroidManifest.xml | 5 +- .../festago/data/di/ViewModelScopeModule.kt | 8 +- .../di/singletonscope/RepositoryModule.kt | 6 - .../data/di/singletonscope/ServiceModule.kt | 9 ++ .../festago/data/dto/SchoolResponse.kt | 17 +++ .../festago/data/dto/SchoolsResponse.kt | 11 ++ .../repository/SchoolDefaultRepository.kt | 14 +- .../data/service/SchoolRetrofitService.kt | 11 ++ .../ui/home/mypage/MyPageFragment.kt | 6 +- .../ui/selectschool/SelectSchoolActivity.kt | 87 ++++++++++++ .../ui/selectschool/SelectSchoolEvent.kt | 5 + .../ui/selectschool/SelectSchoolUiState.kt | 21 +++ .../ui/selectschool/SelectSchoolViewModel.kt | 71 ++++++++++ .../res/layout/activity_select_school.xml | 96 +++++++++++++ .../main/res/layout/item_select_school.xml | 7 + .../app/src/main/res/values/strings.xml | 6 + .../selectschool/SelectSchoolViewModelTest.kt | 134 ++++++++++++++++++ .../java/com/festago/festago/model/School.kt | 7 + .../festago/repository/SchoolRepository.kt | 3 + 19 files changed, 512 insertions(+), 12 deletions(-) create mode 100644 android/festago/app/src/main/java/com/festago/festago/data/dto/SchoolResponse.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/data/dto/SchoolsResponse.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/data/service/SchoolRetrofitService.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolActivity.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolEvent.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolUiState.kt create mode 100644 android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolViewModel.kt create mode 100644 android/festago/app/src/main/res/layout/activity_select_school.xml create mode 100644 android/festago/app/src/main/res/layout/item_select_school.xml create mode 100644 android/festago/app/src/test/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolViewModelTest.kt create mode 100644 android/festago/domain/src/main/java/com/festago/festago/model/School.kt diff --git a/android/festago/app/src/main/AndroidManifest.xml b/android/festago/app/src/main/AndroidManifest.xml index d4f74b841..6d80b0e80 100644 --- a/android/festago/app/src/main/AndroidManifest.xml +++ b/android/festago/app/src/main/AndroidManifest.xml @@ -17,6 +17,9 @@ android:theme="@style/Theme.Festago" android:usesCleartextTraffic="true" tools:targetApi="31"> + @@ -61,4 +64,4 @@ android:exported="false" /> - \ No newline at end of file + diff --git a/android/festago/app/src/main/java/com/festago/festago/data/di/ViewModelScopeModule.kt b/android/festago/app/src/main/java/com/festago/festago/data/di/ViewModelScopeModule.kt index 403a4f89f..abe7d2efe 100644 --- a/android/festago/app/src/main/java/com/festago/festago/data/di/ViewModelScopeModule.kt +++ b/android/festago/app/src/main/java/com/festago/festago/data/di/ViewModelScopeModule.kt @@ -1,9 +1,11 @@ package com.festago.festago.data.di import com.festago.festago.data.repository.ReservationTicketDefaultRepository +import com.festago.festago.data.repository.SchoolDefaultRepository import com.festago.festago.data.repository.StudentVerificationDefaultRepository import com.festago.festago.data.repository.UserDefaultRepository import com.festago.festago.repository.ReservationTicketRepository +import com.festago.festago.repository.SchoolRepository import com.festago.festago.repository.StudentVerificationRepository import com.festago.festago.repository.UserRepository import dagger.Binds @@ -26,5 +28,9 @@ interface ViewModelScopeModule { @Binds @ViewModelScoped - fun binsUserDefaultRepository(userRepository: UserDefaultRepository): UserRepository + fun bindsUserDefaultRepository(userRepository: UserDefaultRepository): UserRepository + + @Binds + @ViewModelScoped + fun bindsSelectSchoolRepository(schoolRepository: SchoolDefaultRepository): SchoolRepository } diff --git a/android/festago/app/src/main/java/com/festago/festago/data/di/singletonscope/RepositoryModule.kt b/android/festago/app/src/main/java/com/festago/festago/data/di/singletonscope/RepositoryModule.kt index fe922bbc4..1229d7c15 100644 --- a/android/festago/app/src/main/java/com/festago/festago/data/di/singletonscope/RepositoryModule.kt +++ b/android/festago/app/src/main/java/com/festago/festago/data/di/singletonscope/RepositoryModule.kt @@ -2,12 +2,10 @@ package com.festago.festago.data.di.singletonscope import com.festago.festago.data.repository.AuthDefaultRepository import com.festago.festago.data.repository.FestivalDefaultRepository -import com.festago.festago.data.repository.SchoolDefaultRepository import com.festago.festago.data.repository.TicketDefaultRepository import com.festago.festago.data.repository.TokenDefaultRepository import com.festago.festago.repository.AuthRepository import com.festago.festago.repository.FestivalRepository -import com.festago.festago.repository.SchoolRepository import com.festago.festago.repository.TicketRepository import com.festago.festago.repository.TokenRepository import dagger.Binds @@ -30,10 +28,6 @@ interface RepositoryModule { @Singleton fun bindsFestivalDefaultRepository(festivalRepository: FestivalDefaultRepository): FestivalRepository - @Binds - @Singleton - fun bindsSchoolDefaultRepository(schoolRepository: SchoolDefaultRepository): SchoolRepository - @Binds @Singleton fun bindsTicketDefaultRepository(ticketRepository: TicketDefaultRepository): TicketRepository diff --git a/android/festago/app/src/main/java/com/festago/festago/data/di/singletonscope/ServiceModule.kt b/android/festago/app/src/main/java/com/festago/festago/data/di/singletonscope/ServiceModule.kt index a1154dc05..3cbb12e5e 100644 --- a/android/festago/app/src/main/java/com/festago/festago/data/di/singletonscope/ServiceModule.kt +++ b/android/festago/app/src/main/java/com/festago/festago/data/di/singletonscope/ServiceModule.kt @@ -2,6 +2,7 @@ package com.festago.festago.data.di.singletonscope import com.festago.festago.data.service.FestivalRetrofitService import com.festago.festago.data.service.ReservationTicketRetrofitService +import com.festago.festago.data.service.SchoolRetrofitService import com.festago.festago.data.service.StudentVerificationRetrofitService import com.festago.festago.data.service.TicketRetrofitService import com.festago.festago.data.service.TokenRetrofitService @@ -64,4 +65,12 @@ object ServiceModule { ): StudentVerificationRetrofitService { return retrofit.create(StudentVerificationRetrofitService::class.java) } + + @Provides + @Singleton + fun providesSchoolRetrofitService( + @NormalRetrofitQualifier retrofit: Retrofit + ): SchoolRetrofitService { + return retrofit.create(SchoolRetrofitService::class.java) + } } diff --git a/android/festago/app/src/main/java/com/festago/festago/data/dto/SchoolResponse.kt b/android/festago/app/src/main/java/com/festago/festago/data/dto/SchoolResponse.kt new file mode 100644 index 000000000..52646b6d5 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/data/dto/SchoolResponse.kt @@ -0,0 +1,17 @@ +package com.festago.festago.data.dto + +import com.festago.festago.model.School +import kotlinx.serialization.Serializable + +@Serializable +data class SchoolResponse( + val id: Int, + val domain: String, + val name: String +) { + fun toDomain(): School = School( + id = id.toLong(), + domain = domain, + name = name + ) +} diff --git a/android/festago/app/src/main/java/com/festago/festago/data/dto/SchoolsResponse.kt b/android/festago/app/src/main/java/com/festago/festago/data/dto/SchoolsResponse.kt new file mode 100644 index 000000000..72e2d61ec --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/data/dto/SchoolsResponse.kt @@ -0,0 +1,11 @@ +package com.festago.festago.data.dto + +import com.festago.festago.model.School +import kotlinx.serialization.Serializable + +@Serializable +data class SchoolsResponse( + val schools: List +) { + fun toDomain(): List = schools.map { it.toDomain() } +} diff --git a/android/festago/app/src/main/java/com/festago/festago/data/repository/SchoolDefaultRepository.kt b/android/festago/app/src/main/java/com/festago/festago/data/repository/SchoolDefaultRepository.kt index 86d2ac26b..c0b5f93f3 100644 --- a/android/festago/app/src/main/java/com/festago/festago/data/repository/SchoolDefaultRepository.kt +++ b/android/festago/app/src/main/java/com/festago/festago/data/repository/SchoolDefaultRepository.kt @@ -1,9 +1,21 @@ package com.festago.festago.data.repository +import com.festago.festago.data.service.SchoolRetrofitService +import com.festago.festago.data.util.runCatchingWithErrorHandler +import com.festago.festago.model.School import com.festago.festago.repository.SchoolRepository import javax.inject.Inject -class SchoolDefaultRepository @Inject constructor() : SchoolRepository { +class SchoolDefaultRepository @Inject constructor( + private val schoolRetrofitService: SchoolRetrofitService +) : SchoolRepository { + + override suspend fun loadSchools(): Result> { + schoolRetrofitService.getSchools() + .runCatchingWithErrorHandler() + .getOrElse { error -> return Result.failure(error) } + .let { return Result.success(it.toDomain()) } + } override suspend fun loadSchoolEmail(schoolId: Long): Result { // TODO: API 연동 작업 필요 diff --git a/android/festago/app/src/main/java/com/festago/festago/data/service/SchoolRetrofitService.kt b/android/festago/app/src/main/java/com/festago/festago/data/service/SchoolRetrofitService.kt new file mode 100644 index 000000000..b21234535 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/data/service/SchoolRetrofitService.kt @@ -0,0 +1,11 @@ +package com.festago.festago.data.service + +import com.festago.festago.data.dto.SchoolsResponse +import retrofit2.Response +import retrofit2.http.GET + +interface SchoolRetrofitService { + + @GET("/schools") + suspend fun getSchools(): Response +} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt index 478d0fdd1..13d8f1afe 100644 --- a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/home/mypage/MyPageFragment.kt @@ -10,8 +10,8 @@ import androidx.fragment.app.viewModels import com.festago.festago.R import com.festago.festago.databinding.FragmentMyPageBinding import com.festago.festago.presentation.ui.home.HomeActivity +import com.festago.festago.presentation.ui.selectschool.SelectSchoolActivity import com.festago.festago.presentation.ui.signin.SignInActivity -import com.festago.festago.presentation.ui.studentverification.StudentVerificationActivity import com.festago.festago.presentation.ui.tickethistory.TicketHistoryActivity import dagger.hilt.android.AndroidEntryPoint @@ -104,9 +104,9 @@ class MyPageFragment : Fragment(R.layout.fragment_my_page) { binding.srlMyPage.setOnRefreshListener { vm.loadUserInfo() } - // TODO: 학교 선택 화면 변경 필요 + binding.tvSchoolAuthorization.setOnClickListener { - startActivity(StudentVerificationActivity.getIntent(requireContext(), 1L)) + startActivity(SelectSchoolActivity.getIntent(requireContext())) } } diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolActivity.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolActivity.kt new file mode 100644 index 000000000..46c0c76a0 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolActivity.kt @@ -0,0 +1,87 @@ +package com.festago.festago.presentation.ui.selectschool + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.widget.ArrayAdapter +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import com.festago.festago.R +import com.festago.festago.databinding.ActivitySelectSchoolBinding +import com.festago.festago.presentation.ui.studentverification.StudentVerificationActivity +import com.festago.festago.presentation.util.repeatOnStarted +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class SelectSchoolActivity : AppCompatActivity() { + + private val binding: ActivitySelectSchoolBinding by lazy { + ActivitySelectSchoolBinding.inflate(layoutInflater) + } + + private val vm: SelectSchoolViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + initBinding() + initObserve() + initView() + } + + private fun initBinding() { + setContentView(binding.root) + binding.lifecycleOwner = this + binding.vm = vm + } + + private fun initObserve() { + repeatOnStarted { + vm.uiState.collect { uiState -> + handleUiState(uiState) + } + } + repeatOnStarted { + vm.event.collect { event -> + handleEvent(event) + } + } + } + + private fun initView() { + vm.loadSchools() + } + + private fun handleUiState(uiState: SelectSchoolUiState) { + binding.uiState = uiState + when (uiState) { + is SelectSchoolUiState.Loading, is SelectSchoolUiState.Error -> Unit + is SelectSchoolUiState.Success -> handleSuccess(uiState) + } + } + + private fun handleSuccess(uiState: SelectSchoolUiState.Success) { + val adapter = + ArrayAdapter(this, R.layout.item_select_school, uiState.schools.map { it.name }) + binding.actvSelectSchool.setAdapter(adapter) + binding.actvSelectSchool.setOnItemClickListener { _, _, position, _ -> + val selectedSchool = uiState.schools.firstOrNull { + it.name == adapter.getItem(position) + } + selectedSchool?.let { vm.selectSchool(it.id) } + } + } + + private fun handleEvent(event: SelectSchoolEvent) { + when (event) { + is SelectSchoolEvent.ShowStudentVerification -> { + startActivity(StudentVerificationActivity.getIntent(this, event.schoolId)) + } + } + } + + companion object { + fun getIntent(context: Context): Intent { + return Intent(context, SelectSchoolActivity::class.java) + } + } +} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolEvent.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolEvent.kt new file mode 100644 index 000000000..3464fe3e4 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolEvent.kt @@ -0,0 +1,5 @@ +package com.festago.festago.presentation.ui.selectschool + +interface SelectSchoolEvent { + class ShowStudentVerification(val schoolId: Long) : SelectSchoolEvent +} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolUiState.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolUiState.kt new file mode 100644 index 000000000..e71f6c70b --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolUiState.kt @@ -0,0 +1,21 @@ +package com.festago.festago.presentation.ui.selectschool + +import com.festago.festago.model.School + +interface SelectSchoolUiState { + object Loading : SelectSchoolUiState + + data class Success( + val schools: List, + val selectedSchoolId: Long? = null + ) : SelectSchoolUiState { + val schoolSelected = selectedSchoolId != null + } + + object Error : SelectSchoolUiState + + val enableNext get() = (this is Success) && schoolSelected + val shouldShowSuccess get() = this is Success + val shouldShowLoading get() = this is Loading + val shouldShowError get() = this is Error +} diff --git a/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolViewModel.kt b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolViewModel.kt new file mode 100644 index 000000000..e49b07764 --- /dev/null +++ b/android/festago/app/src/main/java/com/festago/festago/presentation/ui/selectschool/SelectSchoolViewModel.kt @@ -0,0 +1,71 @@ +package com.festago.festago.presentation.ui.selectschool + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.festago.festago.analytics.AnalyticsHelper +import com.festago.festago.analytics.logNetworkFailure +import com.festago.festago.repository.SchoolRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class SelectSchoolViewModel @Inject constructor( + private val schoolRepository: SchoolRepository, + private val analyticsHelper: AnalyticsHelper +) : ViewModel() { + + private val _uiState = MutableStateFlow(SelectSchoolUiState.Loading) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _event = MutableSharedFlow() + val event: SharedFlow = _event.asSharedFlow() + + fun loadSchools() { + viewModelScope.launch { + schoolRepository.loadSchools() + .onSuccess { schools -> + if (uiState.value is SelectSchoolUiState.Success) { + val successState = (uiState.value as SelectSchoolUiState.Success) + _uiState.value = successState.copy(schools = schools) + } else { + _uiState.value = SelectSchoolUiState.Success(schools) + } + } + .onFailure { + _uiState.value = SelectSchoolUiState.Error + analyticsHelper.logNetworkFailure(KEY_LOAD_SCHOOLS_LOG, it.message.toString()) + } + } + } + + fun selectSchool(schoolId: Long) { + if (uiState.value is SelectSchoolUiState.Success) { + _uiState.value = + (uiState.value as SelectSchoolUiState.Success).copy(selectedSchoolId = schoolId) + } + } + + fun showStudentVerification() { + viewModelScope.launch { + if (uiState.value is SelectSchoolUiState.Success) { + val success = uiState.value as SelectSchoolUiState.Success + success.selectedSchoolId?.let { schoolId -> + _event.emit( + SelectSchoolEvent.ShowStudentVerification(schoolId) + ) + } + } + } + } + + companion object { + private const val KEY_LOAD_SCHOOLS_LOG = "load_schools" + } +} diff --git a/android/festago/app/src/main/res/layout/activity_select_school.xml b/android/festago/app/src/main/res/layout/activity_select_school.xml new file mode 100644 index 000000000..41739185b --- /dev/null +++ b/android/festago/app/src/main/res/layout/activity_select_school.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +