From d2cd9c97c51e0d39a896aa4f6852c17fbedcef17 Mon Sep 17 00:00:00 2001 From: jun02160 Date: Thu, 8 Feb 2024 00:22:07 +0900 Subject: [PATCH 1/8] =?UTF-8?q?[FEAT]=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20API=20=EA=B5=AC=ED=98=84=20#117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/controller/qna/QnAController.java | 8 ++++ .../dto/response/MyUserInfoResponseDto.java | 45 +++++++++++++++++++ .../sopt/org/umbba/api/service/example.txt | 1 + .../org/umbba/api/service/qna/QnAService.java | 21 ++++++++- .../umbba/common/exception/SuccessType.java | 1 + .../parentchild/ParentchildRelation.java | 11 +++++ 6 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java create mode 100644 umbba-api/src/main/java/sopt/org/umbba/api/service/example.txt diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/QnAController.java b/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/QnAController.java index 85c0b3b6..dd68046e 100644 --- a/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/QnAController.java +++ b/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/QnAController.java @@ -1,5 +1,7 @@ package sopt.org.umbba.api.controller.qna; +import static sopt.org.umbba.api.config.jwt.JwtProvider.*; + import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @@ -84,4 +86,10 @@ public ApiResponse invitation(Principal principal) { return ApiResponse.success(SuccessType.GET_INVITE_CODE_SUCCESS, qnAService.getInvitation(JwtProvider.getUserFromPrincial(principal))); } + @GetMapping("/user/me") + @ResponseStatus(HttpStatus.OK) + public ApiResponse getMyUserInfo(Principal principal) { + return ApiResponse.success(SuccessType.GET_MY_USER_INFO_SUCCESS, qnAService.getUserInfo(getUserFromPrincial(principal))); + } + } diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java b/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java new file mode 100644 index 00000000..b99f64d9 --- /dev/null +++ b/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java @@ -0,0 +1,45 @@ +package sopt.org.umbba.api.controller.qna.dto.response; + +import static sopt.org.umbba.domain.domain.parentchild.ParentchildRelation.*; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import lombok.Builder; +import lombok.Getter; +import sopt.org.umbba.domain.domain.parentchild.Parentchild; +import sopt.org.umbba.domain.domain.parentchild.ParentchildRelation; +import sopt.org.umbba.domain.domain.qna.QnA; +import sopt.org.umbba.domain.domain.user.User; + +@Getter +@Builder +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +public class MyUserInfoResponseDto { + + private String myUsername; + private String myUserType; + private String opponentUsername; + private String opponentUserType; + + private String parentchildRelation; + private Boolean isMeChild; + + private String section; + private Integer qnaDate; + private Integer qnaCnt; + + public static MyUserInfoResponseDto of(User myUser, User opponentUser, Parentchild parentchild, QnA qnA, int qnaCnt) { + + return MyUserInfoResponseDto.builder() + .myUsername(myUser.getUsername()) + .myUserType(getUserType(parentchild.getRelation(), myUser.isMeChild())) + .opponentUsername(opponentUser.getUsername()) + .opponentUserType(getUserType(parentchild.getRelation(), opponentUser.isMeChild())) + .parentchildRelation(parentchild.getRelation().getValue()) + .isMeChild(myUser.isMeChild()) + .section(qnA.getQuestion().getSection().getValue()) + .qnaDate(parentchild.getCount()) // 일수와 문답 수는 다를 수 있음 + .qnaCnt(qnaCnt).build(); + } +} diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/service/example.txt b/umbba-api/src/main/java/sopt/org/umbba/api/service/example.txt new file mode 100644 index 00000000..945c9b46 --- /dev/null +++ b/umbba-api/src/main/java/sopt/org/umbba/api/service/example.txt @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java b/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java index db4092b0..d9ca0817 100644 --- a/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java +++ b/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java @@ -4,7 +4,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import sopt.org.umbba.api.config.sqs.producer.SqsProducer; + +import sopt.org.umbba.api.controller.qna.dto.response.MyUserInfoResponseDto; import sopt.org.umbba.api.controller.qna.dto.request.TodayAnswerRequestDto; import sopt.org.umbba.api.controller.qna.dto.response.*; import sopt.org.umbba.api.service.notification.NotificationService; @@ -204,6 +205,22 @@ public void filterAllQuestion(Long userId) { } } + // 마이페이지 - 부모자식 관계 정보 조회 + public MyUserInfoResponseDto getUserInfo(final Long userId) { + + User myUser = getUserById(userId); + Parentchild parentchild = getParentchildByUser(myUser); + QnA todayQnA = getTodayQnAByParentchild(parentchild); + User opponentUser = getOpponentByParentchild(parentchild, userId); + + int qnaCnt = parentchild.getCount(); + if (!todayQnA.isChildAnswer() || !todayQnA.isParentAnswer()) { + qnaCnt -= 1; + } + + return MyUserInfoResponseDto.of(myUser, opponentUser, parentchild, todayQnA, qnaCnt); + } + /* 리팩토링을 위해 아래로 뺀 메서드들 */ @@ -231,7 +248,7 @@ private List getQnAListByParentchild(Parentchild parentchild) { return qnaList; } - private QnA getTodayQnAByParentchild(Parentchild parentchild) { + protected QnA getTodayQnAByParentchild(Parentchild parentchild) { List qnaList = parentchild.getQnaList(); if (qnaList == null || qnaList.isEmpty()) { throw new CustomException(ErrorType.PARENTCHILD_HAVE_NO_QNALIST); diff --git a/umbba-common/src/main/java/sopt/org/umbba/common/exception/SuccessType.java b/umbba-common/src/main/java/sopt/org/umbba/common/exception/SuccessType.java index 9c0b18d2..b4421785 100644 --- a/umbba-common/src/main/java/sopt/org/umbba/common/exception/SuccessType.java +++ b/umbba-common/src/main/java/sopt/org/umbba/common/exception/SuccessType.java @@ -25,6 +25,7 @@ public enum SuccessType { PUSH_ALARM_SUCCESS(HttpStatus.OK, "푸시알림 전송에 성공했습니다."), PUSH_ALARM_PERIODIC_SUCCESS(HttpStatus.OK, "오늘의 질문 푸시알림 활성에 성공했습니다."), REMIND_QUESTION_SUCCESS(HttpStatus.OK, "상대방에게 질문을 리마인드 하는 데 성공했습니다."), + GET_MY_USER_INFO_SUCCESS(HttpStatus.OK, "마이페이지 내 정보 조회에 성공했습니다."), TEST_SUCCESS(HttpStatus.OK, "데모데이 테스트용 API 호출에 성공했습니다."), diff --git a/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/ParentchildRelation.java b/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/ParentchildRelation.java index 39a84dc2..2ed9b1c6 100644 --- a/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/ParentchildRelation.java +++ b/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/ParentchildRelation.java @@ -59,6 +59,17 @@ public static ParentchildRelation relation(String gender, String relationInfo, b throw new CustomException(ErrorType.INVALID_PARENT_CHILD_RELATION_INFO); } + // 아들 | 딸 | 엄마 | 아빠 구분 + public static String getUserType(ParentchildRelation relation, boolean isChild) { + if (relation.childGender.equals("여자")) { + if (isChild) return "딸"; + else return "엄마"; + } else { + if (isChild) return "아들"; + else return "아빠"; + } + } + // 자식 유저와 부모 유저의 gender와 isMeChild 필드를 통해 ParentchildRelation을 구분하는 로직 public static boolean validate(List parentChildUsers, ParentchildRelation relation) { From 72c97dbfca34333f5cb1d4b737d1b82d3300b5ec Mon Sep 17 00:00:00 2001 From: jun02160 Date: Thu, 8 Feb 2024 00:48:25 +0900 Subject: [PATCH 2/8] =?UTF-8?q?[FEAT]=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20API=20=EB=A7=A4=EC=B9=AD=20=EB=82=A0?= =?UTF-8?q?=EC=A7=9C=20=ED=95=84=EB=93=9C=20=EC=88=98=EC=A0=95=20#117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qna/dto/response/MyUserInfoResponseDto.java | 6 +++--- .../java/sopt/org/umbba/api/service/qna/QnAService.java | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java b/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java index b99f64d9..04973b72 100644 --- a/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java +++ b/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java @@ -26,10 +26,10 @@ public class MyUserInfoResponseDto { private Boolean isMeChild; private String section; - private Integer qnaDate; + private Long matchedDate; private Integer qnaCnt; - public static MyUserInfoResponseDto of(User myUser, User opponentUser, Parentchild parentchild, QnA qnA, int qnaCnt) { + public static MyUserInfoResponseDto of(User myUser, User opponentUser, Parentchild parentchild, QnA qnA, long date, int qnaCnt) { return MyUserInfoResponseDto.builder() .myUsername(myUser.getUsername()) @@ -39,7 +39,7 @@ public static MyUserInfoResponseDto of(User myUser, User opponentUser, Parentchi .parentchildRelation(parentchild.getRelation().getValue()) .isMeChild(myUser.isMeChild()) .section(qnA.getQuestion().getSection().getValue()) - .qnaDate(parentchild.getCount()) // 일수와 문답 수는 다를 수 있음 + .matchedDate(date) // 일수와 문답 수는 다를 수 있음 .qnaCnt(qnaCnt).build(); } } diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java b/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java index d9ca0817..2758051f 100644 --- a/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java +++ b/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java @@ -23,6 +23,9 @@ import sopt.org.umbba.domain.domain.user.repository.UserRepository; import javax.validation.constraints.NotNull; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -218,7 +221,10 @@ public MyUserInfoResponseDto getUserInfo(final Long userId) { qnaCnt -= 1; } - return MyUserInfoResponseDto.of(myUser, opponentUser, parentchild, todayQnA, qnaCnt); + LocalDateTime firstQnADate = parentchild.getQnaList().get(0).getCreatedAt(); + long qnaDate = ChronoUnit.DAYS.between(firstQnADate, LocalDateTime.now()); + + return MyUserInfoResponseDto.of(myUser, opponentUser, parentchild, todayQnA, qnaDate, qnaCnt); } /* From c46bf1aed34cd429e7fca712dd242671479c17e1 Mon Sep 17 00:00:00 2001 From: jun02160 Date: Sat, 10 Feb 2024 16:51:14 +0900 Subject: [PATCH 3/8] =?UTF-8?q?[CHORE]=20WhiteList=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?#117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/sopt/org/umbba/api/config/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/config/SecurityConfig.java b/umbba-api/src/main/java/sopt/org/umbba/api/config/SecurityConfig.java index 76254bd2..20fdfdc5 100644 --- a/umbba-api/src/main/java/sopt/org/umbba/api/config/SecurityConfig.java +++ b/umbba-api/src/main/java/sopt/org/umbba/api/config/SecurityConfig.java @@ -21,7 +21,7 @@ public class SecurityConfig { private static final String[] AUTH_WHITELIST = { "/kakao/**", "/login", "/reissue", - "/qna/**", "onboard/**", "/home", "/dummy", + "/qna/**", "onboard/**", "/home", "/dummy", "/user/me", // "/log-out", "/test", "/profile", "/health", "/actuator/health", "/alarm/qna", "/alarm/drink", From 932178d060b407c6f2d4c8f4c160fda26c3efbbc Mon Sep 17 00:00:00 2001 From: jun02160 Date: Sat, 10 Feb 2024 17:02:05 +0900 Subject: [PATCH 4/8] =?UTF-8?q?[MERGE]=20=EB=B3=91=ED=95=A9=20=EC=B6=A9?= =?UTF-8?q?=EB=8F=8C=20=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0=20#117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/api-CD.yml | 105 ------------------ .github/workflows/api-CI.yml | 68 ------------ .github/workflows/notification-CD.yml | 105 ------------------ .github/workflows/notification-CI.yml | 68 ------------ .gitignore | 2 + scripts/umbba-api/appspec.yml | 22 ---- scripts/umbba-api/deploy.sh | 86 -------------- scripts/umbba-api/switch.sh | 30 ----- scripts/umbba-notification/appspec.yml | 19 ---- scripts/umbba-notification/deploy.sh | 19 ---- .../advice/ControllerExceptionAdvice.java | 12 +- .../api/controller/qna/QnAController.java | 8 ++ .../src/main/resources/application-set1.yml | 54 --------- .../src/main/resources/application-set2.yml | 54 --------- .../org/umbba/common/exception/ErrorType.java | 7 +- .../umbba/common/exception/SuccessType.java | 1 + .../domain/parentchild/Parentchild.java | 14 ++- .../qna/repository/QuestionRepository.java | 2 + .../service/fcm/FCMController.java | 3 +- .../notification/service/fcm/FCMService.java | 77 ++++++++++++- 20 files changed, 108 insertions(+), 648 deletions(-) delete mode 100644 .github/workflows/api-CD.yml delete mode 100644 .github/workflows/api-CI.yml delete mode 100644 .github/workflows/notification-CD.yml delete mode 100644 .github/workflows/notification-CI.yml delete mode 100644 scripts/umbba-api/appspec.yml delete mode 100644 scripts/umbba-api/deploy.sh delete mode 100644 scripts/umbba-api/switch.sh delete mode 100644 scripts/umbba-notification/appspec.yml delete mode 100644 scripts/umbba-notification/deploy.sh delete mode 100644 umbba-api/src/main/resources/application-set1.yml delete mode 100644 umbba-api/src/main/resources/application-set2.yml diff --git a/.github/workflows/api-CD.yml b/.github/workflows/api-CD.yml deleted file mode 100644 index 358142ad..00000000 --- a/.github/workflows/api-CD.yml +++ /dev/null @@ -1,105 +0,0 @@ -# 워크플로우의 이름 지정 -name: Umbba API Server CD - -# 해당 workflow가 언제 실행될 것인지에 대한 트리거를 지정 -on: - push: - branches: [ "develop" ] - paths: - - umbba-api/** - - umbba-domain/** - - umbba-common/** - - umbba-external/** - - .github/workflows/** - -env: - S3_BUCKET_NAME: umbba-storage - -jobs: - build: - name: Code deployment - - # 실행 환경 - runs-on: ubuntu-latest - - steps: - - # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 - - name: checkout - uses: actions/checkout@v3 - - # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'temurin' - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v2 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} - aws-region: ap-northeast-2 - - # 3) AWS Secrets Manger 환경변수 사용 - - name: Read secrets from AWS Secrets Manager into environment variables - uses: abhilash1in/aws-secrets-manager-action@v1.1.0 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} - aws-region: ap-northeast-2 - secrets: /secret/umbba-secret - parse-json: false - - # 4) FCM secret key 파일 생성 - - name: FCM secret key 파일 생성 - run: | - cd ./umbba-api/src/main/resources - - mkdir ./firebase - cd ./firebase - - aws s3 cp --region ap-northeast-2 s3://${{ secrets.S3_BUCKET_NAME }}/json/umbba-fcm-firebase-adminsdk.json . - - shell: bash - - # 이 워크플로우는 gradle build - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) - run: ./gradlew umbba-api:bootJar -x test - - # 디렉토리 생성 - - name: Make Directory - run: mkdir -p deploy - - # Jar 파일 복사 - - name: Copy Jar - run: cp ./umbba-api/build/libs/*.jar ./deploy - # run: cp -r ./umbba-api/src/main/* ./deploy - - # appspec.yml, script files 파일 복사 - - name: Copy files - run: cp ./scripts/umbba-api/* ./deploy - - - name: Make zip file - run: zip -r ./umbba-api.zip ./deploy - shell: bash - - - name: Upload to S3 - run: aws s3 cp --region ap-northeast-2 ./umbba-api.zip s3://$S3_BUCKET_NAME/ - - # Deploy - - name: Deploy - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }} - run: - aws deploy create-deployment - --application-name umbba-server-codedeploy - --deployment-group-name umbba-api-server-codedeploy-group - --file-exists-behavior OVERWRITE - --s3-location bucket=umbba-storage,bundleType=zip,key=umbba-api.zip - --region ap-northeast-2 diff --git a/.github/workflows/api-CI.yml b/.github/workflows/api-CI.yml deleted file mode 100644 index 32a1a18e..00000000 --- a/.github/workflows/api-CI.yml +++ /dev/null @@ -1,68 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle - -name: Umbba API Server CI - -on: - push: - branches: [ "develop" ] - paths: - - umbba-api/** - - umbba-domain/** - - umbba-common/** - - umbba-external/** - pull_request: - branches: [ "develop" ] - paths: - - umbba-api/** - - umbba-domain/** - - umbba-common/** - - umbba-external/** - -permissions: - contents: read - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 - - name: checkout - uses: actions/checkout@v3 - - # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'temurin' - - # 3) AWS Secrets Manger 환경변수 사용 - - name: Read secrets from AWS Secrets Manager into environment variables - uses: abhilash1in/aws-secrets-manager-action@v1.1.0 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} - aws-region: ap-northeast-2 - secrets: /secret/umbba-secret - parse-json: false - - # 이 워크플로우는 gradle build - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) - run: ./gradlew umbba-api:bootJar -x test diff --git a/.github/workflows/notification-CD.yml b/.github/workflows/notification-CD.yml deleted file mode 100644 index ea8b69c0..00000000 --- a/.github/workflows/notification-CD.yml +++ /dev/null @@ -1,105 +0,0 @@ -# 워크플로우의 이름 지정 -name: Umbba Notification Server CD - -# 해당 workflow가 언제 실행될 것인지에 대한 트리거를 지정 -on: - push: - branches: [ "develop" ] - paths: - - umbba-notification/** - - umbba-domain/** - - umbba-common/** - - umbba-external/** - - .github/workflows/** - -env: - S3_BUCKET_NAME: umbba-storage - -jobs: - build: - name: Code deployment - - # 실행 환경 - runs-on: ubuntu-latest - - steps: - - # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 - - name: checkout - uses: actions/checkout@v3 - - # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'temurin' - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v2 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} - aws-region: ap-northeast-2 - - # 3) AWS Secrets Manger 환경변수 사용 - - name: Read secrets from AWS Secrets Manager into environment variables - uses: abhilash1in/aws-secrets-manager-action@v1.1.0 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} - aws-region: ap-northeast-2 - secrets: /secret/umbba-secret - parse-json: false - - # 4) FCM secret key 파일 생성 - - name: FCM secret key 파일 생성 - run: | - cd ./umbba-notification/src/main/resources - - mkdir ./firebase - cd ./firebase - - aws s3 cp --region ap-northeast-2 s3://${{ secrets.S3_BUCKET_NAME }}/json/umbba-fcm-firebase-adminsdk.json . - - shell: bash - - # 이 워크플로우는 gradle build - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) - run: ./gradlew umbba-notification:bootJar -x test - - # 디렉토리 생성 - - name: Make Directory - run: mkdir -p deploy - - # Jar 파일 복사 - - name: Copy Jar - run: cp ./umbba-notification/build/libs/*.jar ./deploy - # run: cp -r src/main/* ./deploy - - # appspec.yml, script files 파일 복사 - - name: Copy files - run: cp ./scripts/umbba-notification/* ./deploy - - - name: Make zip file - run: zip -r ./umbba-notification.zip ./deploy - shell: bash - - - name: Upload to S3 - run: aws s3 cp --region ap-northeast-2 ./umbba-notification.zip s3://$S3_BUCKET_NAME/ - - # Deploy - - name: Deploy - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }} - run: - aws deploy create-deployment - --application-name umbba-server-codedeploy - --deployment-group-name umbba-notification-server-codedeploy-group - --file-exists-behavior OVERWRITE - --s3-location bucket=umbba-storage,bundleType=zip,key=umbba-notification.zip - --region ap-northeast-2 diff --git a/.github/workflows/notification-CI.yml b/.github/workflows/notification-CI.yml deleted file mode 100644 index 7e2cf6fd..00000000 --- a/.github/workflows/notification-CI.yml +++ /dev/null @@ -1,68 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle - -name: Umbba Notification Server CI - -on: - push: - branches: [ "develop" ] - paths: - - umbba-notification/** - - umbba-domain/** - - umbba-common/** - - umbba-external/** - pull_request: - branches: [ "develop" ] - paths: - - umbba-notification/** - - umbba-domain/** - - umbba-common/** - - umbba-external/** - -permissions: - contents: read - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 - - name: checkout - uses: actions/checkout@v3 - - # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'temurin' - - # 3) AWS Secrets Manger 환경변수 사용 - - name: Read secrets from AWS Secrets Manager into environment variables - uses: abhilash1in/aws-secrets-manager-action@v1.1.0 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} - aws-region: ap-northeast-2 - secrets: /secret/umbba-secret - parse-json: false - - # 이 워크플로우는 gradle build - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) - run: ./gradlew umbba-notification:bootJar -x test diff --git a/.gitignore b/.gitignore index 8ab1ea93..8ad08fda 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ build/ !**/src/main/**/build/ !**/src/test/**/build/ +umbba-test.http + ## Querydsl umbba-domain/src/main/generated diff --git a/scripts/umbba-api/appspec.yml b/scripts/umbba-api/appspec.yml deleted file mode 100644 index 0386a216..00000000 --- a/scripts/umbba-api/appspec.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: 0.0 -os: linux - -files: - - source: / - destination: /home/ubuntu/api-server - overwrite: yes - -permissions: - - object: / - pattern: "**" - owner: ubuntu - group: ubuntu - -hooks: - AfterInstall: - - location: deploy.sh - timeout: 180 - runas: ubuntu - - location: switch.sh - timeout: 180 - runas: ubuntu \ No newline at end of file diff --git a/scripts/umbba-api/deploy.sh b/scripts/umbba-api/deploy.sh deleted file mode 100644 index 70564ac0..00000000 --- a/scripts/umbba-api/deploy.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" - -BUILD_PATH=$(ls /home/ubuntu/api-server/umbba-api-0.0.1-SNAPSHOT.jar) -JAR_NAME=$(basename $BUILD_PATH) -echo "[$NOW_TIME] build 파일명: $JAR_NAME" - -echo "[$NOW_TIME] build 파일 복사" -DEPLOY_PATH=/home/ubuntu/api-server/nonstop/jar/ -cp $BUILD_PATH $DEPLOY_PATH - -echo "[$NOW_TIME] 현재 구동중인 Set 확인" -CURRENT_PROFILE=$(curl -s http://localhost/profile) -echo "[$NOW_TIME] $CURRENT_PROFILE" - -# 쉬고 있는 set 찾기: set1이 사용중이면 set2가 쉬고 있고, 반대면 set1이 쉬고 있음 -if [ $CURRENT_PROFILE == set1 ] -then - IDLE_PROFILE=set2 - IDLE_PORT=8082 -elif [ $CURRENT_PROFILE == set2 ] -then - IDLE_PROFILE=set1 - IDLE_PORT=8081 -else - echo "[$NOW_TIME] 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE" - echo "[$NOW_TIME] set1을 할당합니다. IDLE_PROFILE: set1" - IDLE_PROFILE=set1 - IDLE_PORT=8081 -fi - -echo "[$NOW_TIME] application.jar 교체" -IDLE_APPLICATION=$IDLE_PROFILE-Umbba-API.jar -IDLE_APPLICATION_PATH=$DEPLOY_PATH$IDLE_APPLICATION - -ln -Tfs $DEPLOY_PATH$JAR_NAME $IDLE_APPLICATION_PATH - -echo "[$NOW_TIME] $IDLE_PROFILE 에서 구동중인 애플리케이션 pid 확인" -IDLE_PID=$(pgrep -f $IDLE_APPLICATION) - -if [ -z $IDLE_PID ] -then - echo "[$NOW_TIME] 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다." -else - echo "[$NOW_TIME] kill -15 $IDLE_PID" - kill -15 $IDLE_PID - - while ps -p $IDLE_PID > /dev/null; do - sleep 1 - done - echo "[$NOW_TIME] 애플리케이션이 정상 종료되었습니다." -fi - -echo "[$NOW_TIME] $IDLE_PROFILE 배포" -nohup java -jar -Duser.timezone=Asia/Seoul -Dspring.profiles.active=$IDLE_PROFILE $IDLE_APPLICATION_PATH >> /home/ubuntu/api-server/deploy.log 2>/home/ubuntu/api-server/deploy_err.log & - -################################################################## - -echo "[$NOW_TIME] $IDLE_PROFILE 10초 후 Health check 시작" -echo "[$NOW_TIME] curl -s http://localhost:$IDLE_PORT/health " -sleep 10 - -for retry_count in {1..10} -do - response=$(curl -s http://localhost:$IDLE_PORT/actuator/health) - up_count=$(echo $response | grep 'UP' | wc -l) - - if [ $up_count -ge 1 ] - then # $up_count >= 1 ("UP" 문자열이 있는지 검증) - echo "[$NOW_TIME] Health check 성공" - break - else - echo "[$NOW_TIME] Health check의 응답을 알 수 없거나 혹은 status가 UP이 아닙니다." - echo "[$NOW_TIME] Health check: ${response}" - fi - - if [ $retry_count -eq 10 ] - then - echo "[$NOW_TIME] Health check 실패. " - echo "[$NOW_TIME] Nginx에 연결하지 않고 배포를 종료합니다." - exit 1 - fi - - echo "[$NOW_TIME] Health check 연결 실패. 재시도..." - sleep 10 -done \ No newline at end of file diff --git a/scripts/umbba-api/switch.sh b/scripts/umbba-api/switch.sh deleted file mode 100644 index d2715800..00000000 --- a/scripts/umbba-api/switch.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" - -echo "[$NOW_TIME] 스위칭" -sleep 10 -echo "[$NOW_TIME] 현재 구동중인 Port 확인" -CURRENT_PROFILE=$(curl -s http://localhost/profile) - -# 쉬고 있는 set 찾기: set1이 사용중이면 set2가 쉬고 있고, 반대면 set1이 쉬고 있음 -if [ $CURRENT_PROFILE == set1 ] -then - IDLE_PORT=8082 -elif [ $CURRENT_PROFILE == set2 ] -then - IDLE_PORT=8081 -else - echo "[$NOW_TIME] 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE" - echo "[$NOW_TIME] 8081을 할당합니다." - IDLE_PORT=8081 -fi - -echo "[$NOW_TIME] 전환할 Port: $IDLE_PORT" -echo "[$NOW_TIME] Port 전환" -echo "set \$service_url http://127.0.0.1:${IDLE_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc - -PROXY_PORT=$(curl -s http://localhost/profile) -echo "[$NOW_TIME] Nginx Current Proxy Port: $PROXY_PORT" - -echo "[$NOW_TIME] Nginx Reload" -sudo service nginx reload \ No newline at end of file diff --git a/scripts/umbba-notification/appspec.yml b/scripts/umbba-notification/appspec.yml deleted file mode 100644 index 4a0bf554..00000000 --- a/scripts/umbba-notification/appspec.yml +++ /dev/null @@ -1,19 +0,0 @@ -version: 0.0 -os: linux - -files: - - source: / - destination: /home/ubuntu/notification-server - overwrite: yes - -permissions: - - object: / - pattern: "**" - owner: ubuntu - group: ubuntu - -hooks: - AfterInstall: - - location: deploy.sh - timeout: 180 - runas: ubuntu \ No newline at end of file diff --git a/scripts/umbba-notification/deploy.sh b/scripts/umbba-notification/deploy.sh deleted file mode 100644 index 8024a227..00000000 --- a/scripts/umbba-notification/deploy.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" - -BUILD_PATH=/home/ubuntu/notification-server/umbba-notification-0.0.1-SNAPSHOT.jar -TARGET_PORT=8083 -TARGET_PID=$(lsof -Fp -i TCP:${TARGET_PORT} | grep -Po 'p[0-9]+' | grep -Po '[0-9]+') - -if [ ! -z ${TARGET_PID} ]; then - echo "[$NOW_TIME] Kill WAS running at ${TARGET_PORT}." >> /home/ubuntu/notification-server/deploy.log - sudo kill -15 ${TARGET_PID} - while ps -p $TARGET_PID > /dev/null; do - sleep 1 - done - echo "[$NOW_TIME] 애플리케이션이 정상 종료되었습니다." -fi - -nohup java -jar -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev $BUILD_PATH >> /home/ubuntu/notification-server/deploy.log 2>/home/ubuntu/notification-server/deploy_err.log & -echo "[$NOW_TIME] Now new WAS runs at ${TARGET_PORT}." >> /home/ubuntu/notification-server/deploy.log -exit 0 \ No newline at end of file diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/controller/advice/ControllerExceptionAdvice.java b/umbba-api/src/main/java/sopt/org/umbba/api/controller/advice/ControllerExceptionAdvice.java index 8f2dfe29..c4752718 100644 --- a/umbba-api/src/main/java/sopt/org/umbba/api/controller/advice/ControllerExceptionAdvice.java +++ b/umbba-api/src/main/java/sopt/org/umbba/api/controller/advice/ControllerExceptionAdvice.java @@ -192,11 +192,17 @@ public ApiResponse handlerNullPointerException(final NullPointerExcep * CUSTOM_ERROR */ @ExceptionHandler(CustomException.class) - protected ResponseEntity handleCustomException(CustomException e) { + protected ResponseEntity handleCustomException(CustomException e, final HttpServletRequest request) { log.error("CustomException occured: {}", e.getMessage(), e); - return ResponseEntity.status(e.getHttpStatus()) - .body(ApiResponse.error(e.getErrorType(), e.getMessage())); + if (e.getHttpStatus() == 501) { + notificationService.sendExceptionToSlack(e, request); + return ResponseEntity.status(e.getHttpStatus()) + .body(ApiResponse.error(ErrorType.NEED_MORE_QUESTION)); + } else { + return ResponseEntity.status(e.getHttpStatus()) + .body(ApiResponse.error(e.getErrorType(), e.getMessage())); + } } } diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/QnAController.java b/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/QnAController.java index dd68046e..27918114 100644 --- a/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/QnAController.java +++ b/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/QnAController.java @@ -72,6 +72,14 @@ public ApiResponse getSingleQna( qnAService.getSingleQna(JwtProvider.getUserFromPrincial(principal), qnaId)); } + @PatchMapping("/qna/restart") + @ResponseStatus(HttpStatus.OK) + public ApiResponse restartQna(Principal principal) { + + qnAService.restartQna(JwtProvider.getUserFromPrincial(principal)); + return ApiResponse.success(SuccessType.RESTART_QNA_SUCCESS); + } + @GetMapping("/home") @ResponseStatus(HttpStatus.OK) public ApiResponse home(Principal principal) { diff --git a/umbba-api/src/main/resources/application-set1.yml b/umbba-api/src/main/resources/application-set1.yml deleted file mode 100644 index a924c93f..00000000 --- a/umbba-api/src/main/resources/application-set1.yml +++ /dev/null @@ -1,54 +0,0 @@ -spring: - config: - activate: - on-profile: set1 - - datasource: - driver-class-name: com.mysql.cj.jdbc.Driver - url: ${DB_URL_DEV} - username: ${DB_USER_DEV} - password: ${DB_PWD_DEV} - hikari: - pool-name: Hikari 커넥션 풀 # Pool - connection-timeout: 30000 # 30초(default: 30초) - maximum-pool-size: 10 # default: 10개 - max-lifetime: 600000 # 10분(default: 30분) - leak-detection-threshold: 3500 # default: 0(이용X) - - jpa: - show-sql: false - hibernate: - ddl-auto: update - ejb: - naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy - properties: - hibernate: - format_sql: true - -cloud: - aws: - credentials: - accessKey: ${CLOUD_ACCESS_DEV} - secretKey: ${CLOUD_SECRET_DEV} - region: - static: ${CLOUD_REGION_DEV} - s3: - bucket: ${BUCKET_NAME_DEV} - stack: - auto: false - sqs: - notification: - name: ${SQS_NAME_DEV} - url: ${SQS_URL_DEV} - -server: - port: 8081 - -kakao: - client-id: ${KAKAO_ID} - authorization-grant-type: authorization_code - redirect-uri: ${KAKAO_REDIRECT_DEV} - -slack: - webhook: - url: ${SLACK_URL_DEV} \ No newline at end of file diff --git a/umbba-api/src/main/resources/application-set2.yml b/umbba-api/src/main/resources/application-set2.yml deleted file mode 100644 index 1d537832..00000000 --- a/umbba-api/src/main/resources/application-set2.yml +++ /dev/null @@ -1,54 +0,0 @@ -spring: - config: - activate: - on-profile: set2 - - datasource: - driver-class-name: com.mysql.cj.jdbc.Driver - url: ${DB_URL_DEV} - username: ${DB_USER_DEV} - password: ${DB_PWD_DEV} - hikari: - pool-name: Hikari 커넥션 풀 # Pool - connection-timeout: 30000 # 30초(default: 30초) - maximum-pool-size: 10 # default: 10개 - max-lifetime: 600000 # 10분(default: 30분) - leak-detection-threshold: 3500 # default: 0(이용X) - - jpa: - show-sql: false - hibernate: - ddl-auto: update - ejb: - naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy - properties: - hibernate: - format_sql: true - -cloud: - aws: - credentials: - accessKey: ${CLOUD_ACCESS_DEV} - secretKey: ${CLOUD_SECRET_DEV} - region: - static: ${CLOUD_REGION_DEV} - s3: - bucket: ${BUCKET_NAME_DEV} - stack: - auto: false - sqs: - notification: - name: ${SQS_NAME_DEV} - url: ${SQS_URL_DEV} - -server: - port: 8082 - -kakao: - client-id: ${KAKAO_ID} - authorization-grant-type: authorization_code - redirect-uri: ${KAKAO_REDIRECT_DEV} - -slack: - webhook: - url: ${SLACK_URL_DEV} \ No newline at end of file diff --git a/umbba-common/src/main/java/sopt/org/umbba/common/exception/ErrorType.java b/umbba-common/src/main/java/sopt/org/umbba/common/exception/ErrorType.java index adc0ad08..37bb4846 100644 --- a/umbba-common/src/main/java/sopt/org/umbba/common/exception/ErrorType.java +++ b/umbba-common/src/main/java/sopt/org/umbba/common/exception/ErrorType.java @@ -62,7 +62,6 @@ public enum ErrorType { PARENTCHILD_HAVE_NO_OPPONENT(HttpStatus.NOT_FOUND, "부모자식 관계에 1명만 참여하고 있습니다."), NOT_FOUND_SECTION(HttpStatus.NOT_FOUND, "해당 아이디와 일치하는 섹션이 없습니다."), - /** * About Apple (HttpStatus 고민) */ @@ -82,7 +81,6 @@ public enum ErrorType { FIREBASE_CONNECTION_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "파이어베이스 서버와의 연결에 실패했습니다."), FAIL_TO_SEND_PUSH_ALARM(HttpStatus.INTERNAL_SERVER_ERROR, "푸시 알림 메세지 전송에 실패했습니다."), - // ETC INDEX_OUT_OF_BOUNDS(HttpStatus.INTERNAL_SERVER_ERROR, "인덱스 범위를 초과했습니다."), JWT_SERIALIZE(HttpStatus.INTERNAL_SERVER_ERROR, "JWT 라이브러리 직렬화에 실패했습니다."), @@ -93,7 +91,10 @@ public enum ErrorType { DATA_INTEGRITY_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "데이터 무결성 제약조건을 위반했습니다."), NULL_POINTER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "NULL 포인터를 참조했습니다."), - + /** + * 501 NOT_IMPLEMENTED + */ + NEED_MORE_QUESTION(HttpStatus.NOT_IMPLEMENTED, "남은 질문이 없습니다. 질문을 추가해주세요."), ; diff --git a/umbba-common/src/main/java/sopt/org/umbba/common/exception/SuccessType.java b/umbba-common/src/main/java/sopt/org/umbba/common/exception/SuccessType.java index b4421785..e68ab841 100644 --- a/umbba-common/src/main/java/sopt/org/umbba/common/exception/SuccessType.java +++ b/umbba-common/src/main/java/sopt/org/umbba/common/exception/SuccessType.java @@ -27,6 +27,7 @@ public enum SuccessType { REMIND_QUESTION_SUCCESS(HttpStatus.OK, "상대방에게 질문을 리마인드 하는 데 성공했습니다."), GET_MY_USER_INFO_SUCCESS(HttpStatus.OK, "마이페이지 내 정보 조회에 성공했습니다."), TEST_SUCCESS(HttpStatus.OK, "데모데이 테스트용 API 호출에 성공했습니다."), + RESTART_QNA_SUCCESS(HttpStatus.OK, "7일 이후 문답이 정상적으로 시작되었습니다."), /** diff --git a/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/Parentchild.java b/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/Parentchild.java index 96743556..31a19aa2 100644 --- a/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/Parentchild.java +++ b/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/Parentchild.java @@ -38,10 +38,8 @@ public class Parentchild extends AuditingTimeEntity { private int count; public void addCount() { - if (this.count < 7) { - this.count += 1; - log.info("Parentchild - addCount() 호출: {}", this.count); - } + this.count += 1; + log.info("Parentchild - addCount() 호출: {}", this.count); // 미답변 일수 필드 0으로 초기화 this.remindCnt = 0; } @@ -87,15 +85,19 @@ public void changeParentOnboardingAnswerList(List onboardingAn private boolean deleted = Boolean.FALSE; - public void initQnA() { + public void initQna() { qnaList = new ArrayList<>(); } - public void addQnA(QnA qnA) { + public void setQna(QnA qnA) { if (qnaList.size() >= 7) { throw new CustomException(ErrorType.ALREADY_QNA_LIST_FULL); } qnaList.add(qnA); } + public void addQna(QnA qnA) { + qnaList.add(qnA); + } + } diff --git a/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/qna/repository/QuestionRepository.java b/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/qna/repository/QuestionRepository.java index 1a9d7586..07afe0b8 100644 --- a/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/qna/repository/QuestionRepository.java +++ b/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/qna/repository/QuestionRepository.java @@ -17,6 +17,8 @@ public interface QuestionRepository extends Repository { List findByType(QuestionType type); + List findByTypeInAndIdNotIn(List types, List doneQuestionIds); + default List findBySectionAndTypeRandom(QuestionSection section, QuestionType type, int size) { List matchingQuestions = findBySectionAndType(section, type); List selectedQuestions = new ArrayList<>(); diff --git a/umbba-notification/src/main/java/sopt/org/umbba/notification/service/fcm/FCMController.java b/umbba-notification/src/main/java/sopt/org/umbba/notification/service/fcm/FCMController.java index 5d65b1a9..1fb4345a 100644 --- a/umbba-notification/src/main/java/sopt/org/umbba/notification/service/fcm/FCMController.java +++ b/umbba-notification/src/main/java/sopt/org/umbba/notification/service/fcm/FCMController.java @@ -6,7 +6,7 @@ import sopt.org.umbba.common.exception.SuccessType; import sopt.org.umbba.common.exception.dto.ApiResponse; import sopt.org.umbba.common.sqs.dto.FCMPushRequestDto; -import sopt.org.umbba.notification.service.fcm.FCMService; +import sopt.org.umbba.notification.config.ScheduleConfig; import sopt.org.umbba.notification.service.scheduler.FCMScheduler; import java.io.IOException; @@ -28,6 +28,7 @@ public class FCMController { @PostMapping("/qna") @ResponseStatus(HttpStatus.OK) public ApiResponse sendTopicScheduledTest() { + ScheduleConfig.resetScheduler(); return ApiResponse.success(SuccessType.PUSH_ALARM_PERIODIC_SUCCESS, fcmScheduler.pushTodayQna()); } diff --git a/umbba-notification/src/main/java/sopt/org/umbba/notification/service/fcm/FCMService.java b/umbba-notification/src/main/java/sopt/org/umbba/notification/service/fcm/FCMService.java index 52586d4b..f1a0966b 100644 --- a/umbba-notification/src/main/java/sopt/org/umbba/notification/service/fcm/FCMService.java +++ b/umbba-notification/src/main/java/sopt/org/umbba/notification/service/fcm/FCMService.java @@ -21,11 +21,15 @@ import org.springframework.transaction.support.DefaultTransactionDefinition; import sopt.org.umbba.common.exception.ErrorType; import sopt.org.umbba.common.exception.model.CustomException; -import sopt.org.umbba.common.sqs.dto.PushMessage; import sopt.org.umbba.domain.domain.parentchild.Parentchild; import sopt.org.umbba.domain.domain.parentchild.dao.ParentchildDao; import sopt.org.umbba.domain.domain.parentchild.repository.ParentchildRepository; import sopt.org.umbba.domain.domain.qna.QnA; +import sopt.org.umbba.domain.domain.qna.Question; +import sopt.org.umbba.domain.domain.qna.QuestionSection; +import sopt.org.umbba.domain.domain.qna.QuestionType; +import sopt.org.umbba.domain.domain.qna.repository.QnARepository; +import sopt.org.umbba.domain.domain.qna.repository.QuestionRepository; import sopt.org.umbba.domain.domain.user.SocialPlatform; import sopt.org.umbba.domain.domain.user.User; import sopt.org.umbba.domain.domain.user.repository.UserRepository; @@ -38,7 +42,13 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; +import java.util.Random; import java.util.concurrent.ScheduledFuture; +import java.util.stream.Collectors; + +import static sopt.org.umbba.common.exception.ErrorType.NEED_MORE_QUESTION; +import static sopt.org.umbba.domain.domain.qna.QuestionType.MAIN; +import static sopt.org.umbba.domain.domain.qna.QuestionType.YET; /** * 서버에서 파이어베이스로 전송이 잘 이루어지는지 테스트하기 위한 컨트롤러 @@ -59,6 +69,8 @@ public class FCMService { private final UserRepository userRepository; private final ParentchildRepository parentchildRepository; + private final QnARepository qnARepository; + private final QuestionRepository questionRepository; private final ParentchildDao parentchildDao; private final ObjectMapper objectMapper; private final TaskScheduler taskScheduler; @@ -184,7 +196,6 @@ public void schedulePushAlarm(String cronExpression, Long parentchildId) { scheduledFuture = taskScheduler.schedule(() -> { - try { Thread.sleep(1000); } catch (InterruptedException e) { @@ -247,7 +258,12 @@ public void schedulePushAlarm(String cronExpression, Long parentchildId) { } // 부모와 자식 모두 답변한 경우 - else if (currentQnA.isParentAnswer() && currentQnA.isChildAnswer() && parentchild.getCount() < 7) { + else if (currentQnA.isParentAnswer() && currentQnA.isChildAnswer() && parentchild.getCount() != 7) { + + // 8일 이후 (7일 + 엔딩페이지 API 통신으로 추가된 1일) 에는 스케줄링을 돌며 QnA 직접 추가 + if (parentchild.getCount() >= 8) { + appendQna(parentchild); + } log.info("둘 다 답변함 다음 질문으로 ㄱ {}", parentchild.getCount()); parentchild.addCount(); // 오늘의 질문 UP & 리마인드 카운트 초기화 @@ -269,8 +285,6 @@ else if (currentQnA.isParentAnswer() && currentQnA.isChildAnswer() && parentchil todayQnA.getQuestion().getTopic()), parentchild.getId()); } } - - } transactionManager.commit(transactionStatus); } catch (PessimisticLockingFailureException | PessimisticLockException e) { @@ -294,7 +308,60 @@ public static void clearScheduledTasks() { log.info("ScheduledFuture: {}", scheduledFuture); } + private void appendQna(Parentchild parentchild) { + List qnaList = getQnAListByParentchild(parentchild); + + // 1. 메인 타입과 미사용 타입에 대해서 불러오기 + List types = Arrays.asList(MAIN, YET); + + // 2. 내가 이미 주고받은 질문 제외하기 + List doneQuestionIds = qnaList.stream() + .map(qna -> qna.getQuestion().getId()) + .collect(Collectors.toList()); + + // 5. 이 경우 아예 추가될 질문이 없으므로 예외 발생시킴 + List targetQuestions = questionRepository.findByTypeInAndIdNotIn(types, doneQuestionIds); + if (targetQuestions.isEmpty()) { + // 충실한 유저가 추가될 수 있는 질문을 모두 수행했을 경우, 기획 측에서 알 수 있도록 500 에러로 처리 + throw new CustomException(NEED_MORE_QUESTION); + } + QuestionSection section = qnaList.get(parentchild.getCount() - 1).getQuestion().getSection(); + List differentSectionQuestions = targetQuestions.stream() + .filter(question -> !question.getSection().equals(section)) + .collect(Collectors.toList()); + + Random random = new Random(); + Question randomQuestion; + if (!differentSectionQuestions.isEmpty()) { + // 3. 최근에 주고받은 질문의 section과 다른 질문들 중에서 랜덤하게 추출 + randomQuestion = differentSectionQuestions.get(random.nextInt(differentSectionQuestions.size())); + } else { + // 4. 없다면 동일한 section의 질문 중에서라도 랜덤하게 추출 + List equalSectionQuestions = targetQuestions.stream() + .filter(question -> !question.getSection().equals(section)) + .collect(Collectors.toList()); + randomQuestion = equalSectionQuestions.get(random.nextInt(equalSectionQuestions.size())); + } + + QnA newQnA = QnA.builder() + .question(randomQuestion) + .isParentAnswer(false) + .isChildAnswer(false) + .build(); + + qnARepository.save(newQnA); + parentchild.addQna(newQnA); + } + + private List getQnAListByParentchild(Parentchild parentchild) { + List qnaList = parentchild.getQnaList(); + if (qnaList == null || qnaList.isEmpty()) { + throw new CustomException(ErrorType.PARENTCHILD_HAVE_NO_QNALIST); + } + + return qnaList; + } /** * 사용 안하는 함수들 From 94d61ceb5ee24f48d230f45cc770ff2d5462f8ce Mon Sep 17 00:00:00 2001 From: jun02160 Date: Sat, 10 Feb 2024 17:04:19 +0900 Subject: [PATCH 5/8] =?UTF-8?q?[MERGE]=20=EB=B3=91=ED=95=A9=20=EC=B6=A9?= =?UTF-8?q?=EB=8F=8C=20=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0=20#117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/api-CD-dev.yml | 105 ++++++++++++++++++ .github/workflows/api-CD-prod.yml | 105 ++++++++++++++++++ .github/workflows/api-CI-dev.yml | 55 +++++++++ .github/workflows/api-CI-prod.yml | 55 +++++++++ .github/workflows/notification-CD-dev.yml | 105 ++++++++++++++++++ .github/workflows/notification-CD-prod.yml | 105 ++++++++++++++++++ .github/workflows/notification-CI-dev.yml | 55 +++++++++ .github/workflows/notification-CI-prod.yml | 55 +++++++++ scripts/umbba-api-dev/appspec.yml | 22 ++++ scripts/umbba-api-dev/deploy.sh | 86 ++++++++++++++ scripts/umbba-api-dev/switch.sh | 30 +++++ scripts/umbba-api-prod/appspec.yml | 22 ++++ scripts/umbba-api-prod/deploy.sh | 86 ++++++++++++++ scripts/umbba-api-prod/switch.sh | 30 +++++ scripts/umbba-notification-dev/appspec.yml | 19 ++++ scripts/umbba-notification-dev/deploy.sh | 19 ++++ scripts/umbba-notification-prod/appspec.yml | 19 ++++ scripts/umbba-notification-prod/deploy.sh | 19 ++++ .../src/main/resources/application-dev1.yml | 54 +++++++++ .../src/main/resources/application-dev2.yml | 54 +++++++++ .../src/main/resources/application-prod1.yml | 54 +++++++++ .../src/main/resources/application-prod2.yml | 54 +++++++++ .../src/main/resources/application-prod.yml | 54 +++++++++ 23 files changed, 1262 insertions(+) create mode 100644 .github/workflows/api-CD-dev.yml create mode 100644 .github/workflows/api-CD-prod.yml create mode 100644 .github/workflows/api-CI-dev.yml create mode 100644 .github/workflows/api-CI-prod.yml create mode 100644 .github/workflows/notification-CD-dev.yml create mode 100644 .github/workflows/notification-CD-prod.yml create mode 100644 .github/workflows/notification-CI-dev.yml create mode 100644 .github/workflows/notification-CI-prod.yml create mode 100644 scripts/umbba-api-dev/appspec.yml create mode 100644 scripts/umbba-api-dev/deploy.sh create mode 100644 scripts/umbba-api-dev/switch.sh create mode 100644 scripts/umbba-api-prod/appspec.yml create mode 100644 scripts/umbba-api-prod/deploy.sh create mode 100644 scripts/umbba-api-prod/switch.sh create mode 100644 scripts/umbba-notification-dev/appspec.yml create mode 100644 scripts/umbba-notification-dev/deploy.sh create mode 100644 scripts/umbba-notification-prod/appspec.yml create mode 100644 scripts/umbba-notification-prod/deploy.sh create mode 100644 umbba-api/src/main/resources/application-dev1.yml create mode 100644 umbba-api/src/main/resources/application-dev2.yml create mode 100644 umbba-api/src/main/resources/application-prod1.yml create mode 100644 umbba-api/src/main/resources/application-prod2.yml create mode 100644 umbba-notification/src/main/resources/application-prod.yml diff --git a/.github/workflows/api-CD-dev.yml b/.github/workflows/api-CD-dev.yml new file mode 100644 index 00000000..1d6c9183 --- /dev/null +++ b/.github/workflows/api-CD-dev.yml @@ -0,0 +1,105 @@ +# 워크플로우의 이름 지정 +name: Umbba API Server CD (Develop) + +# 해당 workflow가 언제 실행될 것인지에 대한 트리거를 지정 +on: + push: + branches: [ "develop" ] + paths: + - umbba-api/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + - .github/workflows/** + +env: + S3_BUCKET_NAME: umbba-develop-storage + +jobs: + build: + name: Code deployment + + # 실행 환경 + runs-on: ubuntu-latest + + steps: + + # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 + - name: checkout + uses: actions/checkout@v3 + + # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_DEVELOP_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_DEVELOP_SECRET_KEY }} + aws-region: ap-northeast-2 + + # 3) AWS Secrets Manger 환경변수 사용 + - name: Read secrets from AWS Secrets Manager into environment variables + uses: abhilash1in/aws-secrets-manager-action@v1.1.0 + with: + aws-access-key-id: ${{ secrets.AWS_DEVELOP_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_DEVELOP_SECRET_KEY }} + aws-region: ap-northeast-2 + secrets: /secret/umbba-secret + parse-json: false + + # 4) FCM secret key 파일 생성 + - name: FCM secret key 파일 생성 + run: | + cd ./umbba-api/src/main/resources + + mkdir ./firebase + cd ./firebase + + aws s3 cp --region ap-northeast-2 s3://${{ secrets.S3_DEVELOP_BUCKET_NAME }}/json/umbba-fcm-firebase-adminsdk.json . + + shell: bash + + # 이 워크플로우는 gradle build + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) + run: ./gradlew umbba-api:bootJar -x test + + # 디렉토리 생성 + - name: Make Directory + run: mkdir -p deploy + + # Jar 파일 복사 + - name: Copy Jar + run: cp ./umbba-api/build/libs/*.jar ./deploy + # run: cp -r ./umbba-api/src/main/* ./deploy + + # appspec.yml, script files 파일 복사 + - name: Copy files + run: cp ./scripts/umbba-api-dev/* ./deploy + + - name: Make zip file + run: zip -r ./umbba-api.zip ./deploy + shell: bash + + - name: Upload to S3 + run: aws s3 cp --region ap-northeast-2 ./umbba-api.zip s3://$S3_BUCKET_NAME/ + + # Deploy + - name: Deploy + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_DEVELOP_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_DEVELOP_SECRET_KEY }} + run: + aws deploy create-deployment + --application-name umbba-develop-server-codedeploy + --deployment-group-name umbba-api-server-codedeploy-group + --file-exists-behavior OVERWRITE + --s3-location bucket=umbba-develop-storage,bundleType=zip,key=umbba-api.zip + --region ap-northeast-2 \ No newline at end of file diff --git a/.github/workflows/api-CD-prod.yml b/.github/workflows/api-CD-prod.yml new file mode 100644 index 00000000..abc3ea10 --- /dev/null +++ b/.github/workflows/api-CD-prod.yml @@ -0,0 +1,105 @@ +# 워크플로우의 이름 지정 +name: Umbba API Server CD (Production) + +# 해당 workflow가 언제 실행될 것인지에 대한 트리거를 지정 +on: + push: + branches: [ "main" ] + paths: + - umbba-api/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + - .github/workflows/** + +env: + S3_BUCKET_NAME: umbba-storage + +jobs: + build: + name: Code deployment + + # 실행 환경 + runs-on: ubuntu-latest + + steps: + + # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 + - name: checkout + uses: actions/checkout@v3 + + # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} + aws-region: ap-northeast-2 + + # 3) AWS Secrets Manger 환경변수 사용 + - name: Read secrets from AWS Secrets Manager into environment variables + uses: abhilash1in/aws-secrets-manager-action@v1.1.0 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} + aws-region: ap-northeast-2 + secrets: /secret/umbba-secret + parse-json: false + + # 4) FCM secret key 파일 생성 + - name: FCM secret key 파일 생성 + run: | + cd ./umbba-api/src/main/resources + + mkdir ./firebase + cd ./firebase + + aws s3 cp --region ap-northeast-2 s3://${{ secrets.S3_BUCKET_NAME }}/json/umbba-fcm-firebase-adminsdk.json . + + shell: bash + + # 이 워크플로우는 gradle build + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) + run: ./gradlew umbba-api:bootJar -x test + + # 디렉토리 생성 + - name: Make Directory + run: mkdir -p deploy + + # Jar 파일 복사 + - name: Copy Jar + run: cp ./umbba-api/build/libs/*.jar ./deploy + # run: cp -r ./umbba-api/src/main/* ./deploy + + # appspec.yml, script files 파일 복사 + - name: Copy files + run: cp ./scripts/umbba-api-prod/* ./deploy + + - name: Make zip file + run: zip -r ./umbba-api.zip ./deploy + shell: bash + + - name: Upload to S3 + run: aws s3 cp --region ap-northeast-2 ./umbba-api.zip s3://$S3_BUCKET_NAME/ + + # Deploy + - name: Deploy + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }} + run: + aws deploy create-deployment + --application-name umbba-server-codedeploy + --deployment-group-name umbba-api-server-codedeploy-group + --file-exists-behavior OVERWRITE + --s3-location bucket=umbba-storage,bundleType=zip,key=umbba-api.zip + --region ap-northeast-2 \ No newline at end of file diff --git a/.github/workflows/api-CI-dev.yml b/.github/workflows/api-CI-dev.yml new file mode 100644 index 00000000..e5636bff --- /dev/null +++ b/.github/workflows/api-CI-dev.yml @@ -0,0 +1,55 @@ +name: Umbba API Server CI (Develop) + +on: + push: + branches: [ "develop" ] + paths: + - umbba-api/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + pull_request: + branches: [ "develop" ] + paths: + - umbba-api/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + + # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 + - name: checkout + uses: actions/checkout@v3 + + # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + # 3) AWS Secrets Manger 환경변수 사용 + - name: Read secrets from AWS Secrets Manager into environment variables + uses: abhilash1in/aws-secrets-manager-action@v1.1.0 + with: + aws-access-key-id: ${{ secrets.AWS_DEVELOP_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_DEVELOP_SECRET_KEY }} + aws-region: ap-northeast-2 + secrets: /secret/umbba-secret + parse-json: false + + # 이 워크플로우는 gradle build + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) + run: ./gradlew umbba-api:bootJar -x test diff --git a/.github/workflows/api-CI-prod.yml b/.github/workflows/api-CI-prod.yml new file mode 100644 index 00000000..b4d51d32 --- /dev/null +++ b/.github/workflows/api-CI-prod.yml @@ -0,0 +1,55 @@ +name: Umbba API Server CI (Production) + +on: + push: + branches: [ "main" ] + paths: + - umbba-api/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + pull_request: + branches: [ "main" ] + paths: + - umbba-api/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + + # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 + - name: checkout + uses: actions/checkout@v3 + + # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + # 3) AWS Secrets Manger 환경변수 사용 + - name: Read secrets from AWS Secrets Manager into environment variables + uses: abhilash1in/aws-secrets-manager-action@v1.1.0 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} + aws-region: ap-northeast-2 + secrets: /secret/umbba-secret + parse-json: false + + # 이 워크플로우는 gradle build + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) + run: ./gradlew umbba-api:bootJar -x test \ No newline at end of file diff --git a/.github/workflows/notification-CD-dev.yml b/.github/workflows/notification-CD-dev.yml new file mode 100644 index 00000000..6fe22226 --- /dev/null +++ b/.github/workflows/notification-CD-dev.yml @@ -0,0 +1,105 @@ +# 워크플로우의 이름 지정 +name: Umbba Notification Server CD (Develop) + +# 해당 workflow가 언제 실행될 것인지에 대한 트리거를 지정 +on: + push: + branches: [ "develop" ] + paths: + - umbba-notification/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + - .github/workflows/** + +env: + S3_BUCKET_NAME: umbba-develop-storage + +jobs: + build: + name: Code deployment + + # 실행 환경 + runs-on: ubuntu-latest + + steps: + + # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 + - name: checkout + uses: actions/checkout@v3 + + # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_DEVELOP_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_DEVELOP_SECRET_KEY }} + aws-region: ap-northeast-2 + + # 3) AWS Secrets Manger 환경변수 사용 + - name: Read secrets from AWS Secrets Manager into environment variables + uses: abhilash1in/aws-secrets-manager-action@v1.1.0 + with: + aws-access-key-id: ${{ secrets.AWS_DEVELOP_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_DEVELOP_SECRET_KEY }} + aws-region: ap-northeast-2 + secrets: /secret/umbba-secret + parse-json: false + + # 4) FCM secret key 파일 생성 + - name: FCM secret key 파일 생성 + run: | + cd ./umbba-notification/src/main/resources + + mkdir ./firebase + cd ./firebase + + aws s3 cp --region ap-northeast-2 s3://${{ secrets.S3_DEVELOP_BUCKET_NAME }}/json/umbba-fcm-firebase-adminsdk.json . + + shell: bash + + # 이 워크플로우는 gradle build + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) + run: ./gradlew umbba-notification:bootJar -x test + + # 디렉토리 생성 + - name: Make Directory + run: mkdir -p deploy + + # Jar 파일 복사 + - name: Copy Jar + run: cp ./umbba-notification/build/libs/*.jar ./deploy + # run: cp -r src/main/* ./deploy + + # appspec.yml, script files 파일 복사 + - name: Copy files + run: cp ./scripts/umbba-notification-dev/* ./deploy + + - name: Make zip file + run: zip -r ./umbba-notification.zip ./deploy + shell: bash + + - name: Upload to S3 + run: aws s3 cp --region ap-northeast-2 ./umbba-notification.zip s3://$S3_BUCKET_NAME/ + + # Deploy + - name: Deploy + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_DEVELOP_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_DEVELOP_SECRET_KEY }} + run: + aws deploy create-deployment + --application-name umbba-develop-server-codedeploy + --deployment-group-name umbba-notification-server-codedeploy-group + --file-exists-behavior OVERWRITE + --s3-location bucket=umbba-develop-storage,bundleType=zip,key=umbba-notification.zip + --region ap-northeast-2 diff --git a/.github/workflows/notification-CD-prod.yml b/.github/workflows/notification-CD-prod.yml new file mode 100644 index 00000000..cd9fb8c7 --- /dev/null +++ b/.github/workflows/notification-CD-prod.yml @@ -0,0 +1,105 @@ +# 워크플로우의 이름 지정 +name: Umbba Notification Server CD (Production) + +# 해당 workflow가 언제 실행될 것인지에 대한 트리거를 지정 +on: + push: + branches: [ "main" ] + paths: + - umbba-notification/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + - .github/workflows/** + +env: + S3_BUCKET_NAME: umbba-storage + +jobs: + build: + name: Code deployment + + # 실행 환경 + runs-on: ubuntu-latest + + steps: + + # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 + - name: checkout + uses: actions/checkout@v3 + + # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} + aws-region: ap-northeast-2 + + # 3) AWS Secrets Manger 환경변수 사용 + - name: Read secrets from AWS Secrets Manager into environment variables + uses: abhilash1in/aws-secrets-manager-action@v1.1.0 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} + aws-region: ap-northeast-2 + secrets: /secret/umbba-secret + parse-json: false + + # 4) FCM secret key 파일 생성 + - name: FCM secret key 파일 생성 + run: | + cd ./umbba-notification/src/main/resources + + mkdir ./firebase + cd ./firebase + + aws s3 cp --region ap-northeast-2 s3://${{ secrets.S3_BUCKET_NAME }}/json/umbba-fcm-firebase-adminsdk.json . + + shell: bash + + # 이 워크플로우는 gradle build + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) + run: ./gradlew umbba-notification:bootJar -x test + + # 디렉토리 생성 + - name: Make Directory + run: mkdir -p deploy + + # Jar 파일 복사 + - name: Copy Jar + run: cp ./umbba-notification/build/libs/*.jar ./deploy + # run: cp -r src/main/* ./deploy + + # appspec.yml, script files 파일 복사 + - name: Copy files + run: cp ./scripts/umbba-notification-prod/* ./deploy + + - name: Make zip file + run: zip -r ./umbba-notification.zip ./deploy + shell: bash + + - name: Upload to S3 + run: aws s3 cp --region ap-northeast-2 ./umbba-notification.zip s3://$S3_BUCKET_NAME/ + + # Deploy + - name: Deploy + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }} + run: + aws deploy create-deployment + --application-name umbba-server-codedeploy + --deployment-group-name umbba-notification-server-codedeploy-group + --file-exists-behavior OVERWRITE + --s3-location bucket=umbba-storage,bundleType=zip,key=umbba-notification.zip + --region ap-northeast-2 diff --git a/.github/workflows/notification-CI-dev.yml b/.github/workflows/notification-CI-dev.yml new file mode 100644 index 00000000..cb09fdcd --- /dev/null +++ b/.github/workflows/notification-CI-dev.yml @@ -0,0 +1,55 @@ +name: Umbba Notification Server CI (Develop) + +on: + push: + branches: [ "develop" ] + paths: + - umbba-notification/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + pull_request: + branches: [ "develop" ] + paths: + - umbba-notification/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + + # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 + - name: checkout + uses: actions/checkout@v3 + + # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + # 3) AWS Secrets Manger 환경변수 사용 + - name: Read secrets from AWS Secrets Manager into environment variables + uses: abhilash1in/aws-secrets-manager-action@v1.1.0 + with: + aws-access-key-id: ${{ secrets.AWS_DEVELOP_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_DEVELOP_SECRET_KEY }} + aws-region: ap-northeast-2 + secrets: /secret/umbba-secret + parse-json: false + + # 이 워크플로우는 gradle build + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) + run: ./gradlew umbba-notification:bootJar -x test diff --git a/.github/workflows/notification-CI-prod.yml b/.github/workflows/notification-CI-prod.yml new file mode 100644 index 00000000..1b01c8c7 --- /dev/null +++ b/.github/workflows/notification-CI-prod.yml @@ -0,0 +1,55 @@ +name: Umbba Notification Server CI (Production) + +on: + push: + branches: [ "main" ] + paths: + - umbba-notification/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + pull_request: + branches: [ "main" ] + paths: + - umbba-notification/** + - umbba-domain/** + - umbba-common/** + - umbba-external/** + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + + # 1) 워크플로우 실행 전 기본적으로 체크아웃 필요 + - name: checkout + uses: actions/checkout@v3 + + # 2) JDK 11버전 설치, 다른 JDK 버전을 사용하다면 수정 + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + + # 3) AWS Secrets Manger 환경변수 사용 + - name: Read secrets from AWS Secrets Manager into environment variables + uses: abhilash1in/aws-secrets-manager-action@v1.1.0 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} + aws-region: ap-northeast-2 + secrets: /secret/umbba-secret + parse-json: false + + # 이 워크플로우는 gradle build + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle # 실제 application build(-x 옵션을 통해 test는 제외) + run: ./gradlew umbba-notification:bootJar -x test diff --git a/scripts/umbba-api-dev/appspec.yml b/scripts/umbba-api-dev/appspec.yml new file mode 100644 index 00000000..0386a216 --- /dev/null +++ b/scripts/umbba-api-dev/appspec.yml @@ -0,0 +1,22 @@ +version: 0.0 +os: linux + +files: + - source: / + destination: /home/ubuntu/api-server + overwrite: yes + +permissions: + - object: / + pattern: "**" + owner: ubuntu + group: ubuntu + +hooks: + AfterInstall: + - location: deploy.sh + timeout: 180 + runas: ubuntu + - location: switch.sh + timeout: 180 + runas: ubuntu \ No newline at end of file diff --git a/scripts/umbba-api-dev/deploy.sh b/scripts/umbba-api-dev/deploy.sh new file mode 100644 index 00000000..6905ed35 --- /dev/null +++ b/scripts/umbba-api-dev/deploy.sh @@ -0,0 +1,86 @@ +#!/bin/bash +NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" + +BUILD_PATH=$(ls /home/ubuntu/api-server/umbba-api-0.0.1-SNAPSHOT.jar) +JAR_NAME=$(basename $BUILD_PATH) +echo "[$NOW_TIME] build 파일명: $JAR_NAME" + +echo "[$NOW_TIME] build 파일 복사" +DEPLOY_PATH=/home/ubuntu/api-server/nonstop/jar/ +cp $BUILD_PATH $DEPLOY_PATH + +echo "[$NOW_TIME] 현재 구동중인 Prod 확인" +CURRENT_PROFILE=$(curl -s http://localhost/profile) +echo "[$NOW_TIME] $CURRENT_PROFILE" + +# 쉬고 있는 prod 찾기: dev1이 사용중이면 dev2가 쉬고 있고, 반대면 dev1이 쉬고 있음 +if [ $CURRENT_PROFILE == dev1 ] +then + IDLE_PROFILE=dev2 + IDLE_PORT=8082 +elif [ $CURRENT_PROFILE == dev2 ] +then + IDLE_PROFILE=dev1 + IDLE_PORT=8081 +else + echo "[$NOW_TIME] 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE" + echo "[$NOW_TIME] dev1을 할당합니다. IDLE_PROFILE: dev1" + IDLE_PROFILE=dev1 + IDLE_PORT=8081 +fi + +echo "[$NOW_TIME] application.jar 교체" +IDLE_APPLICATION=$IDLE_PROFILE-Umbba-API.jar +IDLE_APPLICATION_PATH=$DEPLOY_PATH$IDLE_APPLICATION + +ln -Tfs $DEPLOY_PATH$JAR_NAME $IDLE_APPLICATION_PATH + +echo "[$NOW_TIME] $IDLE_PROFILE 에서 구동중인 애플리케이션 pid 확인" +IDLE_PID=$(pgrep -f $IDLE_APPLICATION) + +if [ -z $IDLE_PID ] +then + echo "[$NOW_TIME] 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다." +else + echo "[$NOW_TIME] kill -15 $IDLE_PID" + kill -15 $IDLE_PID + + while ps -p $IDLE_PID > /dev/null; do + sleep 1 + done + echo "[$NOW_TIME] 애플리케이션이 정상 종료되었습니다." +fi + +echo "[$NOW_TIME] $IDLE_PROFILE 배포" +nohup java -jar -Duser.timezone=Asia/Seoul -Dspring.profiles.active=$IDLE_PROFILE $IDLE_APPLICATION_PATH >> /home/ubuntu/api-server/deploy.log 2>/home/ubuntu/api-server/deploy_err.log & + +################################################################## + +echo "[$NOW_TIME] $IDLE_PROFILE 10초 후 Health check 시작" +echo "[$NOW_TIME] curl -s http://localhost:$IDLE_PORT/health " +sleep 10 + +for retry_count in {1..10} +do + response=$(curl -s http://localhost:$IDLE_PORT/actuator/health) + up_count=$(echo $response | grep 'UP' | wc -l) + + if [ $up_count -ge 1 ] + then # $up_count >= 1 ("UP" 문자열이 있는지 검증) + echo "[$NOW_TIME] Health check 성공" + break + else + echo "[$NOW_TIME] Health check의 응답을 알 수 없거나 혹은 status가 UP이 아닙니다." + echo "[$NOW_TIME] Health check: ${response}" + fi + + if [ $retry_count -eq 10 ] + then + echo "[$NOW_TIME] Health check 실패. " + echo "[$NOW_TIME] Nginx에 연결하지 않고 배포를 종료합니다." + exit 1 + fi + + echo "[$NOW_TIME] Health check 연결 실패. 재시도..." + sleep 10 +done \ No newline at end of file diff --git a/scripts/umbba-api-dev/switch.sh b/scripts/umbba-api-dev/switch.sh new file mode 100644 index 00000000..06387f45 --- /dev/null +++ b/scripts/umbba-api-dev/switch.sh @@ -0,0 +1,30 @@ +#!/bin/bash +NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" + +echo "[$NOW_TIME] 스위칭" +sleep 10 +echo "[$NOW_TIME] 현재 구동중인 Port 확인" +CURRENT_PROFILE=$(curl -s http://localhost/profile) + +# 쉬고 있는 prod 찾기: dev1이 사용중이면 dev2가 쉬고 있고, 반대면 dev1이 쉬고 있음 +if [ $CURRENT_PROFILE == dev1 ] +then + IDLE_PORT=8082 +elif [ $CURRENT_PROFILE == dev2 ] +then + IDLE_PORT=8081 +else + echo "[$NOW_TIME] 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE" + echo "[$NOW_TIME] 8081을 할당합니다." + IDLE_PORT=8081 +fi + +echo "[$NOW_TIME] 전환할 Port: $IDLE_PORT" +echo "[$NOW_TIME] Port 전환" +echo "set \$service_url http://127.0.0.1:${IDLE_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc + +PROXY_PORT=$(curl -s http://localhost/profile) +echo "[$NOW_TIME] Nginx Current Proxy Port: $PROXY_PORT" + +echo "[$NOW_TIME] Nginx Reload" +sudo service nginx reload \ No newline at end of file diff --git a/scripts/umbba-api-prod/appspec.yml b/scripts/umbba-api-prod/appspec.yml new file mode 100644 index 00000000..0386a216 --- /dev/null +++ b/scripts/umbba-api-prod/appspec.yml @@ -0,0 +1,22 @@ +version: 0.0 +os: linux + +files: + - source: / + destination: /home/ubuntu/api-server + overwrite: yes + +permissions: + - object: / + pattern: "**" + owner: ubuntu + group: ubuntu + +hooks: + AfterInstall: + - location: deploy.sh + timeout: 180 + runas: ubuntu + - location: switch.sh + timeout: 180 + runas: ubuntu \ No newline at end of file diff --git a/scripts/umbba-api-prod/deploy.sh b/scripts/umbba-api-prod/deploy.sh new file mode 100644 index 00000000..d8680401 --- /dev/null +++ b/scripts/umbba-api-prod/deploy.sh @@ -0,0 +1,86 @@ +#!/bin/bash +NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" + +BUILD_PATH=$(ls /home/ubuntu/api-server/umbba-api-0.0.1-SNAPSHOT.jar) +JAR_NAME=$(basename $BUILD_PATH) +echo "[$NOW_TIME] build 파일명: $JAR_NAME" + +echo "[$NOW_TIME] build 파일 복사" +DEPLOY_PATH=/home/ubuntu/api-server/nonstop/jar/ +cp $BUILD_PATH $DEPLOY_PATH + +echo "[$NOW_TIME] 현재 구동중인 Prod 확인" +CURRENT_PROFILE=$(curl -s http://localhost/profile) +echo "[$NOW_TIME] $CURRENT_PROFILE" + +# 쉬고 있는 prod 찾기: prod1이 사용중이면 prod2가 쉬고 있고, 반대면 prod1이 쉬고 있음 +if [ $CURRENT_PROFILE == prod1 ] +then + IDLE_PROFILE=prod2 + IDLE_PORT=8082 +elif [ $CURRENT_PROFILE == prod2 ] +then + IDLE_PROFILE=prod1 + IDLE_PORT=8081 +else + echo "[$NOW_TIME] 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE" + echo "[$NOW_TIME] prod1을 할당합니다. IDLE_PROFILE: prod1" + IDLE_PROFILE=prod1 + IDLE_PORT=8081 +fi + +echo "[$NOW_TIME] application.jar 교체" +IDLE_APPLICATION=$IDLE_PROFILE-Umbba-API.jar +IDLE_APPLICATION_PATH=$DEPLOY_PATH$IDLE_APPLICATION + +ln -Tfs $DEPLOY_PATH$JAR_NAME $IDLE_APPLICATION_PATH + +echo "[$NOW_TIME] $IDLE_PROFILE 에서 구동중인 애플리케이션 pid 확인" +IDLE_PID=$(pgrep -f $IDLE_APPLICATION) + +if [ -z $IDLE_PID ] +then + echo "[$NOW_TIME] 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다." +else + echo "[$NOW_TIME] kill -15 $IDLE_PID" + kill -15 $IDLE_PID + + while ps -p $IDLE_PID > /dev/null; do + sleep 1 + done + echo "[$NOW_TIME] 애플리케이션이 정상 종료되었습니다." +fi + +echo "[$NOW_TIME] $IDLE_PROFILE 배포" +nohup java -jar -Duser.timezone=Asia/Seoul -Dspring.profiles.active=$IDLE_PROFILE $IDLE_APPLICATION_PATH >> /home/ubuntu/api-server/deploy.log 2>/home/ubuntu/api-server/deploy_err.log & + +################################################################## + +echo "[$NOW_TIME] $IDLE_PROFILE 10초 후 Health check 시작" +echo "[$NOW_TIME] curl -s http://localhost:$IDLE_PORT/health " +sleep 10 + +for retry_count in {1..10} +do + response=$(curl -s http://localhost:$IDLE_PORT/actuator/health) + up_count=$(echo $response | grep 'UP' | wc -l) + + if [ $up_count -ge 1 ] + then # $up_count >= 1 ("UP" 문자열이 있는지 검증) + echo "[$NOW_TIME] Health check 성공" + break + else + echo "[$NOW_TIME] Health check의 응답을 알 수 없거나 혹은 status가 UP이 아닙니다." + echo "[$NOW_TIME] Health check: ${response}" + fi + + if [ $retry_count -eq 10 ] + then + echo "[$NOW_TIME] Health check 실패. " + echo "[$NOW_TIME] Nginx에 연결하지 않고 배포를 종료합니다." + exit 1 + fi + + echo "[$NOW_TIME] Health check 연결 실패. 재시도..." + sleep 10 +done \ No newline at end of file diff --git a/scripts/umbba-api-prod/switch.sh b/scripts/umbba-api-prod/switch.sh new file mode 100644 index 00000000..4efce738 --- /dev/null +++ b/scripts/umbba-api-prod/switch.sh @@ -0,0 +1,30 @@ +#!/bin/bash +NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" + +echo "[$NOW_TIME] 스위칭" +sleep 10 +echo "[$NOW_TIME] 현재 구동중인 Port 확인" +CURRENT_PROFILE=$(curl -s http://localhost/profile) + +# 쉬고 있는 prod 찾기: prod1이 사용중이면 prod2가 쉬고 있고, 반대면 prod1이 쉬고 있음 +if [ $CURRENT_PROFILE == prod1 ] +then + IDLE_PORT=8082 +elif [ $CURRENT_PROFILE == prod2 ] +then + IDLE_PORT=8081 +else + echo "[$NOW_TIME] 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE" + echo "[$NOW_TIME] 8081을 할당합니다." + IDLE_PORT=8081 +fi + +echo "[$NOW_TIME] 전환할 Port: $IDLE_PORT" +echo "[$NOW_TIME] Port 전환" +echo "set \$service_url http://127.0.0.1:${IDLE_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc + +PROXY_PORT=$(curl -s http://localhost/profile) +echo "[$NOW_TIME] Nginx Current Proxy Port: $PROXY_PORT" + +echo "[$NOW_TIME] Nginx Reload" +sudo service nginx reload \ No newline at end of file diff --git a/scripts/umbba-notification-dev/appspec.yml b/scripts/umbba-notification-dev/appspec.yml new file mode 100644 index 00000000..4a0bf554 --- /dev/null +++ b/scripts/umbba-notification-dev/appspec.yml @@ -0,0 +1,19 @@ +version: 0.0 +os: linux + +files: + - source: / + destination: /home/ubuntu/notification-server + overwrite: yes + +permissions: + - object: / + pattern: "**" + owner: ubuntu + group: ubuntu + +hooks: + AfterInstall: + - location: deploy.sh + timeout: 180 + runas: ubuntu \ No newline at end of file diff --git a/scripts/umbba-notification-dev/deploy.sh b/scripts/umbba-notification-dev/deploy.sh new file mode 100644 index 00000000..8024a227 --- /dev/null +++ b/scripts/umbba-notification-dev/deploy.sh @@ -0,0 +1,19 @@ +#!/bin/bash +NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" + +BUILD_PATH=/home/ubuntu/notification-server/umbba-notification-0.0.1-SNAPSHOT.jar +TARGET_PORT=8083 +TARGET_PID=$(lsof -Fp -i TCP:${TARGET_PORT} | grep -Po 'p[0-9]+' | grep -Po '[0-9]+') + +if [ ! -z ${TARGET_PID} ]; then + echo "[$NOW_TIME] Kill WAS running at ${TARGET_PORT}." >> /home/ubuntu/notification-server/deploy.log + sudo kill -15 ${TARGET_PID} + while ps -p $TARGET_PID > /dev/null; do + sleep 1 + done + echo "[$NOW_TIME] 애플리케이션이 정상 종료되었습니다." +fi + +nohup java -jar -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev $BUILD_PATH >> /home/ubuntu/notification-server/deploy.log 2>/home/ubuntu/notification-server/deploy_err.log & +echo "[$NOW_TIME] Now new WAS runs at ${TARGET_PORT}." >> /home/ubuntu/notification-server/deploy.log +exit 0 \ No newline at end of file diff --git a/scripts/umbba-notification-prod/appspec.yml b/scripts/umbba-notification-prod/appspec.yml new file mode 100644 index 00000000..4a0bf554 --- /dev/null +++ b/scripts/umbba-notification-prod/appspec.yml @@ -0,0 +1,19 @@ +version: 0.0 +os: linux + +files: + - source: / + destination: /home/ubuntu/notification-server + overwrite: yes + +permissions: + - object: / + pattern: "**" + owner: ubuntu + group: ubuntu + +hooks: + AfterInstall: + - location: deploy.sh + timeout: 180 + runas: ubuntu \ No newline at end of file diff --git a/scripts/umbba-notification-prod/deploy.sh b/scripts/umbba-notification-prod/deploy.sh new file mode 100644 index 00000000..1d95de1b --- /dev/null +++ b/scripts/umbba-notification-prod/deploy.sh @@ -0,0 +1,19 @@ +#!/bin/bash +NOW_TIME="$(date +%Y)-$(date +%m)-$(date +%d) $(date +%H):$(date +%M):$(date +%S)" + +BUILD_PATH=/home/ubuntu/notification-server/umbba-notification-0.0.1-SNAPSHOT.jar +TARGET_PORT=8083 +TARGET_PID=$(lsof -Fp -i TCP:${TARGET_PORT} | grep -Po 'p[0-9]+' | grep -Po '[0-9]+') + +if [ ! -z ${TARGET_PID} ]; then + echo "[$NOW_TIME] Kill WAS running at ${TARGET_PORT}." >> /home/ubuntu/notification-server/deploy.log + sudo kill -15 ${TARGET_PID} + while ps -p $TARGET_PID > /dev/null; do + sleep 1 + done + echo "[$NOW_TIME] 애플리케이션이 정상 종료되었습니다." +fi + +nohup java -jar -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod $BUILD_PATH >> /home/ubuntu/notification-server/deploy.log 2>/home/ubuntu/notification-server/deploy_err.log & +echo "[$NOW_TIME] Now new WAS runs at ${TARGET_PORT}." >> /home/ubuntu/notification-server/deploy.log +exit 0 \ No newline at end of file diff --git a/umbba-api/src/main/resources/application-dev1.yml b/umbba-api/src/main/resources/application-dev1.yml new file mode 100644 index 00000000..1627e262 --- /dev/null +++ b/umbba-api/src/main/resources/application-dev1.yml @@ -0,0 +1,54 @@ +spring: + config: + activate: + on-profile: dev1 + + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: ${DB_URL_DEV} + username: ${DB_USER_DEV} + password: ${DB_PWD_DEV} + hikari: + pool-name: Hikari 커넥션 풀 # Pool + connection-timeout: 30000 # 30초(default: 30초) + maximum-pool-size: 10 # default: 10개 + max-lifetime: 600000 # 10분(default: 30분) + leak-detection-threshold: 3500 # default: 0(이용X) + + jpa: + show-sql: false + hibernate: + ddl-auto: update + ejb: + naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + properties: + hibernate: + format_sql: true + +cloud: + aws: + credentials: + accessKey: ${CLOUD_ACCESS_DEV} + secretKey: ${CLOUD_SECRET_DEV} + region: + static: ${CLOUD_REGION_DEV} + s3: + bucket: ${BUCKET_NAME_DEV} + stack: + auto: false + sqs: + notification: + name: ${SQS_NAME_DEV} + url: ${SQS_URL_DEV} + +server: + port: 8081 + +kakao: + client-id: ${KAKAO_ID} + authorization-grant-type: authorization_code + redirect-uri: ${KAKAO_REDIRECT_DEV} + +slack: + webhook: + url: ${SLACK_URL_DEV} \ No newline at end of file diff --git a/umbba-api/src/main/resources/application-dev2.yml b/umbba-api/src/main/resources/application-dev2.yml new file mode 100644 index 00000000..e5b79300 --- /dev/null +++ b/umbba-api/src/main/resources/application-dev2.yml @@ -0,0 +1,54 @@ +spring: + config: + activate: + on-profile: dev2 + + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: ${DB_URL_DEV} + username: ${DB_USER_DEV} + password: ${DB_PWD_DEV} + hikari: + pool-name: Hikari 커넥션 풀 # Pool + connection-timeout: 30000 # 30초(default: 30초) + maximum-pool-size: 10 # default: 10개 + max-lifetime: 600000 # 10분(default: 30분) + leak-detection-threshold: 3500 # default: 0(이용X) + + jpa: + show-sql: false + hibernate: + ddl-auto: update + ejb: + naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + properties: + hibernate: + format_sql: true + +cloud: + aws: + credentials: + accessKey: ${CLOUD_ACCESS_DEV} + secretKey: ${CLOUD_SECRET_DEV} + region: + static: ${CLOUD_REGION_DEV} + s3: + bucket: ${BUCKET_NAME_DEV} + stack: + auto: false + sqs: + notification: + name: ${SQS_NAME_DEV} + url: ${SQS_URL_DEV} + +server: + port: 8082 + +kakao: + client-id: ${KAKAO_ID} + authorization-grant-type: authorization_code + redirect-uri: ${KAKAO_REDIRECT_DEV} + +slack: + webhook: + url: ${SLACK_URL_DEV} \ No newline at end of file diff --git a/umbba-api/src/main/resources/application-prod1.yml b/umbba-api/src/main/resources/application-prod1.yml new file mode 100644 index 00000000..38b2c3d7 --- /dev/null +++ b/umbba-api/src/main/resources/application-prod1.yml @@ -0,0 +1,54 @@ +spring: + config: + activate: + on-profile: prod1 + + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: ${DB_URL_PROD} + username: ${DB_USER_PROD} + password: ${DB_PWD_PROD} + hikari: + pool-name: Hikari 커넥션 풀 # Pool + connection-timeout: 30000 # 30초(default: 30초) + maximum-pool-size: 10 # default: 10개 + max-lifetime: 600000 # 10분(default: 30분) + leak-detection-threshold: 3500 # default: 0(이용X) + + jpa: + show-sql: false + hibernate: + ddl-auto: update + ejb: + naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + properties: + hibernate: + format_sql: true + +cloud: + aws: + credentials: + accessKey: ${CLOUD_ACCESS_PROD} + secretKey: ${CLOUD_SECRET_PROD} + region: + static: ${CLOUD_REGION_PROD} + s3: + bucket: ${BUCKET_NAME_PROD} + stack: + auto: false + sqs: + notification: + name: ${SQS_NAME_PROD} + url: ${SQS_URL_PROD} + +server: + port: 8081 + +kakao: + client-id: ${KAKAO_ID} + authorization-grant-type: authorization_code + redirect-uri: ${KAKAO_REDIRECT_PROD} + +slack: + webhook: + url: ${SLACK_URL_PROD} \ No newline at end of file diff --git a/umbba-api/src/main/resources/application-prod2.yml b/umbba-api/src/main/resources/application-prod2.yml new file mode 100644 index 00000000..5d924d7f --- /dev/null +++ b/umbba-api/src/main/resources/application-prod2.yml @@ -0,0 +1,54 @@ +spring: + config: + activate: + on-profile: prod2 + + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: ${DB_URL_PROD} + username: ${DB_USER_PROD} + password: ${DB_PWD_PROD} + hikari: + pool-name: Hikari 커넥션 풀 # Pool + connection-timeout: 30000 # 30초(default: 30초) + maximum-pool-size: 10 # default: 10개 + max-lifetime: 600000 # 10분(default: 30분) + leak-detection-threshold: 3500 # default: 0(이용X) + + jpa: + show-sql: false + hibernate: + ddl-auto: update + ejb: + naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + properties: + hibernate: + format_sql: true + +cloud: + aws: + credentials: + accessKey: ${CLOUD_ACCESS_PROD} + secretKey: ${CLOUD_SECRET_PROD} + region: + static: ${CLOUD_REGION_PROD} + s3: + bucket: ${BUCKET_NAME_PROD} + stack: + auto: false + sqs: + notification: + name: ${SQS_NAME_PROD} + url: ${SQS_URL_PROD} + +server: + port: 8082 + +kakao: + client-id: ${KAKAO_ID} + authorization-grant-type: authorization_code + redirect-uri: ${KAKAO_REDIRECT_PROD} + +slack: + webhook: + url: ${SLACK_URL_PROD} \ No newline at end of file diff --git a/umbba-notification/src/main/resources/application-prod.yml b/umbba-notification/src/main/resources/application-prod.yml new file mode 100644 index 00000000..1c7a2009 --- /dev/null +++ b/umbba-notification/src/main/resources/application-prod.yml @@ -0,0 +1,54 @@ +spring: + config: + activate: + on-profile: prod + + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: ${DB_URL_PROD} + username: ${DB_USER_PROD} + password: ${DB_PWD_PROD} + hikari: + pool-name: Hikari 커넥션 풀 # Pool + connection-timeout: 30000 # 30초(default: 30초) + maximum-pool-size: 10 # default: 10개 + max-lifetime: 600000 # 10분(default: 30분) + leak-detection-threshold: 3500 # default: 0(이용X) + + jpa: + show-sql: false + hibernate: + ddl-auto: update + ejb: + naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + properties: + hibernate: + format_sql: true + +cloud: + aws: + credentials: + accessKey: ${CLOUD_ACCESS_PROD} + secretKey: ${CLOUD_SECRET_PROD} + region: + static: ${CLOUD_REGION_PROD} + s3: + bucket: ${BUCKET_NAME_PROD} + stack: + auto: false + sqs: + notification: + name: ${SQS_NAME_PROD} + url: ${SQS_URL_PROD} + +server: + port: 8083 + +kakao: + client-id: ${KAKAO_ID} + authorization-grant-type: authorization_code + redirect-uri: ${KAKAO_REDIRECT_PROD} + +slack: + webhook: + url: ${SLACK_URL_PROD} \ No newline at end of file From 7c05eee3925a8be92b21f2954fcdfb1db0a76311 Mon Sep 17 00:00:00 2001 From: jun02160 Date: Sat, 10 Feb 2024 19:53:16 +0900 Subject: [PATCH 6/8] =?UTF-8?q?[FIX]=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=AC=B8=EB=8B=B5=20=EC=88=98=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95=20#117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/umbba/api/service/qna/QnAService.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java b/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java index 7b903360..367dace3 100644 --- a/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java +++ b/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java @@ -213,18 +213,28 @@ public MyUserInfoResponseDto getUserInfo(final Long userId) { User myUser = getUserById(userId); Parentchild parentchild = getParentchildByUser(myUser); - QnA todayQnA = getTodayQnAByParentchild(parentchild); User opponentUser = getOpponentByParentchild(parentchild, userId); + // TODO 상대 미연결인 부분에 대한 반환값 추가 예정 + /*List opponentUserList = userRepository.findUserByParentChild(parentchild) + .stream() + .filter(user -> !user.getId().equals(userId)) + .collect(Collectors.toList()); - int qnaCnt = parentchild.getCount(); - if (!todayQnA.isChildAnswer() || !todayQnA.isParentAnswer()) { - qnaCnt -= 1; - } + if (opponentUserList.isEmpty()) { + return MyUserInfoResponseDto.of(myUser, opponentUser, parentchild, todayQnA, 0, 0); + }*/ + + QnA todayQnA = getTodayQnAByParentchild(parentchild); + List qnaList = getQnAListByParentchild(parentchild); + + long qnaCnt = qnaList.stream() + .filter(qnA -> qnA.isChildAnswer() && qnA.isParentAnswer()) + .count(); LocalDateTime firstQnADate = parentchild.getQnaList().get(0).getCreatedAt(); long qnaDate = ChronoUnit.DAYS.between(firstQnADate, LocalDateTime.now()); - return MyUserInfoResponseDto.of(myUser, opponentUser, parentchild, todayQnA, qnaDate, qnaCnt); + return MyUserInfoResponseDto.of(myUser, opponentUser, parentchild, todayQnA, qnaDate, (int)qnaCnt); } /* @@ -332,10 +342,6 @@ else if (childList.get(3) != YES || parentList.get(3) != YES) { } - /* - 리팩토링을 위해 아래로 뺀 메서드들 끝 - */ - // 메인페이지 정보 public GetMainViewResponseDto getMainInfo(Long userId) { From 02b85b7d26350974c3b0d551608787b88a66b28d Mon Sep 17 00:00:00 2001 From: jun02160 Date: Sun, 11 Feb 2024 01:08:51 +0900 Subject: [PATCH 7/8] =?UTF-8?q?[FIX]=20=EB=B6=80=EB=AA=A8-=EC=9E=90?= =?UTF-8?q?=EC=8B=9D=20=EC=9C=A0=EC=A0=80=20=ED=83=80=EC=9E=85=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95=20#117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/domain/parentchild/ParentchildRelation.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/ParentchildRelation.java b/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/ParentchildRelation.java index 2ed9b1c6..43191e5a 100644 --- a/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/ParentchildRelation.java +++ b/umbba-domain/src/main/java/sopt/org/umbba/domain/domain/parentchild/ParentchildRelation.java @@ -61,12 +61,10 @@ public static ParentchildRelation relation(String gender, String relationInfo, b // 아들 | 딸 | 엄마 | 아빠 구분 public static String getUserType(ParentchildRelation relation, boolean isChild) { - if (relation.childGender.equals("여자")) { - if (isChild) return "딸"; - else return "엄마"; + if (isChild) { + return relation.childGender.equals("남자") ? "아들" : "딸"; } else { - if (isChild) return "아들"; - else return "아빠"; + return relation.parentGender.equals("남자") ? "아빠" : "엄마"; } } From 924d3ee94d7d9a3135ff8c5c597da2989828fe0b Mon Sep 17 00:00:00 2001 From: jun02160 Date: Sun, 11 Feb 2024 01:09:44 +0900 Subject: [PATCH 8/8] =?UTF-8?q?[FEAT]=20=EB=A7=A4=EC=B9=AD=20=EC=9D=B4?= =?UTF-8?q?=EC=A0=84=EC=97=90=20=EB=8C=80=ED=95=9C=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=EA=B0=92=20=EC=B6=94=EA=B0=80=20#117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/MyUserInfoResponseDto.java | 13 +++++++++++ .../org/umbba/api/service/qna/QnAService.java | 22 +++++++++---------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java b/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java index 04973b72..93f1a0ab 100644 --- a/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java +++ b/umbba-api/src/main/java/sopt/org/umbba/api/controller/qna/dto/response/MyUserInfoResponseDto.java @@ -2,6 +2,7 @@ import static sopt.org.umbba.domain.domain.parentchild.ParentchildRelation.*; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; @@ -10,11 +11,13 @@ import sopt.org.umbba.domain.domain.parentchild.Parentchild; import sopt.org.umbba.domain.domain.parentchild.ParentchildRelation; import sopt.org.umbba.domain.domain.qna.QnA; +import sopt.org.umbba.domain.domain.qna.QuestionSection; import sopt.org.umbba.domain.domain.user.User; @Getter @Builder @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +@JsonInclude(JsonInclude.Include.NON_NULL) public class MyUserInfoResponseDto { private String myUsername; @@ -42,4 +45,14 @@ public static MyUserInfoResponseDto of(User myUser, User opponentUser, Parentchi .matchedDate(date) // 일수와 문답 수는 다를 수 있음 .qnaCnt(qnaCnt).build(); } + + // 아직 매칭된 유저가 없는 경우 + public static MyUserInfoResponseDto of(User myUser) { + + return MyUserInfoResponseDto.builder() + .myUsername(myUser.getUsername()) + .section(QuestionSection.YOUNG.getValue()) + .matchedDate(0L) + .qnaCnt(0).build(); + } } diff --git a/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java b/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java index 367dace3..4424791d 100644 --- a/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java +++ b/umbba-api/src/main/java/sopt/org/umbba/api/service/qna/QnAService.java @@ -213,28 +213,28 @@ public MyUserInfoResponseDto getUserInfo(final Long userId) { User myUser = getUserById(userId); Parentchild parentchild = getParentchildByUser(myUser); - User opponentUser = getOpponentByParentchild(parentchild, userId); - // TODO 상대 미연결인 부분에 대한 반환값 추가 예정 - /*List opponentUserList = userRepository.findUserByParentChild(parentchild) + List opponentUserList = userRepository.findUserByParentChild(parentchild) .stream() .filter(user -> !user.getId().equals(userId)) .collect(Collectors.toList()); + // 매칭된 상대 유저가 없는 경우 if (opponentUserList.isEmpty()) { - return MyUserInfoResponseDto.of(myUser, opponentUser, parentchild, todayQnA, 0, 0); - }*/ + return MyUserInfoResponseDto.of(myUser); + } + User opponentUser = getOpponentByParentchild(parentchild, userId); QnA todayQnA = getTodayQnAByParentchild(parentchild); - List qnaList = getQnAListByParentchild(parentchild); - long qnaCnt = qnaList.stream() - .filter(qnA -> qnA.isChildAnswer() && qnA.isParentAnswer()) - .count(); + int qnaCnt = parentchild.getCount(); + if (!todayQnA.isChildAnswer() || !todayQnA.isParentAnswer()) { + qnaCnt -= 1; + } LocalDateTime firstQnADate = parentchild.getQnaList().get(0).getCreatedAt(); long qnaDate = ChronoUnit.DAYS.between(firstQnADate, LocalDateTime.now()); - return MyUserInfoResponseDto.of(myUser, opponentUser, parentchild, todayQnA, qnaDate, (int)qnaCnt); + return MyUserInfoResponseDto.of(myUser, opponentUser, parentchild, todayQnA, qnaDate, qnaCnt); } /* @@ -264,7 +264,7 @@ private List getQnAListByParentchild(Parentchild parentchild) { return qnaList; } - protected QnA getTodayQnAByParentchild(Parentchild parentchild) { + private QnA getTodayQnAByParentchild(Parentchild parentchild) { List qnaList = parentchild.getQnaList(); if (qnaList == null || qnaList.isEmpty()) { throw new CustomException(ErrorType.PARENTCHILD_HAVE_NO_QNALIST);