From b5b0abf3f10bb122d27e73f940214764d01970b3 Mon Sep 17 00:00:00 2001 From: kwonssshyeon <104684033+kwonssshyeon@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:59:10 +0900 Subject: [PATCH] =?UTF-8?q?Refac/issue=20#112=20docker=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=EB=B3=80=EC=88=98=20=EC=A3=BC=EC=9E=85=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95,=20=EC=BB=A8=EB=B2=A4?= =?UTF-8?q?=EC=85=98=20=EB=A7=9E=EC=B6=B0=20=EC=88=98=EC=A0=95(#114)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refac: yml 분리 규칙 변경(프로필 -> 기능) * Fix: 테스트 워크플로, 환경변수 수정 * Fix: dev 서버 배포 워크플로 수정 * Fix: main 서버 배포 워크플로 수정 * Refac: PK 네이밍 규칙 통일 * Refac: User 관련 예외처리 코드 통일 * Refac: 지원서(admin) 관련 예외처리 코드 통일 * Refac: response dto(member, team) 클래스 위치 변경 * Fix: dto getter 추가 * Feat: health check 엔드포인트 생성 --- .github/workflows/deploy-dev.yml | 20 +---- .github/workflows/deploy-main.yml | 18 +---- .github/workflows/test-dev.yml | 13 +--- .gitignore | 1 - .../controller/HealthCheckController.java | 12 +++ .../controller/MemberController.java | 3 +- .../controller/TeamController.java | 8 +- .../memberStatus/AdminMemberResponse.java | 6 +- .../dto/admin/team/AdminTeamResponse.java | 4 +- .../dto/member/MemberResponse.java | 66 +++++++++++----- .../dto/member/TeamInfoResponse.java | 28 ------- .../dto/role/UserRoleRequest.java | 10 --- .../dto/team/TeamResponse.java | 23 +++--- .../official_homepage/entity/Member.java | 1 - .../official_homepage/entity/MemberTeam.java | 3 +- .../official_homepage/entity/Team.java | 2 +- .../entity/application/Application.java | 3 +- .../entity/application/ApplicationAnswer.java | 4 +- .../exception/DiscordClient.java | 1 + .../exception/ErrorCode.java | 21 ++++- .../service/MemberInfoService.java | 6 +- .../service/MemberInfoServiceImpl.java | 22 +++--- .../admin/AdminApplicationService.java | 16 ++-- .../admin/AdminMemberStatusServiceImpl.java | 4 +- .../service/admin/AdminTeamServiceImpl.java | 5 +- .../application/ApplicationServiceImpl.java | 4 +- .../service/{ => team}/TeamService.java | 8 +- src/main/resources/application-auth.yml | 19 +++++ src/main/resources/application-db.yml | 76 +++++++++++++++++++ src/main/resources/application-doc.yml | 14 ++++ src/main/resources/application.yml | 32 ++++++++ .../OfficialHomepageApplicationTests.java | 3 - 32 files changed, 278 insertions(+), 178 deletions(-) create mode 100644 src/main/java/com/gdsc_knu/official_homepage/controller/HealthCheckController.java delete mode 100644 src/main/java/com/gdsc_knu/official_homepage/dto/member/TeamInfoResponse.java delete mode 100644 src/main/java/com/gdsc_knu/official_homepage/dto/role/UserRoleRequest.java rename src/main/java/com/gdsc_knu/official_homepage/service/{ => team}/TeamService.java (80%) create mode 100644 src/main/resources/application-auth.yml create mode 100644 src/main/resources/application-db.yml create mode 100644 src/main/resources/application-doc.yml create mode 100644 src/main/resources/application.yml diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index ee94911b..d42d1e0c 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -10,12 +10,9 @@ name: Deploy dev branch on: push: branches: [ "dev" ] - - jobs: build: runs-on: ubuntu-latest - permissions: contents: read @@ -28,14 +25,6 @@ jobs: java-version: '17' distribution: 'temurin' - # set up application file - - name: Create application.yml - run: | - mkdir -p ./src/main/resources - cd ./src/main/resources - echo "${{ secrets.APPLICATION }}" > application.yml - echo "${{ secrets.APPLICATION_PROD }}" > application-prod.yml - # apply caching - name: Gradle Caching uses: actions/cache@v3 @@ -51,7 +40,7 @@ jobs: - name: Setup Gradle run: | chmod +x ./gradlew - ./gradlew clean build -x test -Pprofile=prod + ./gradlew clean build -x test -Pprofile=dev # login dockerhub - name: docker login @@ -83,9 +72,8 @@ jobs: key: ${{ secrets.PRIVATE_KEY }} port: ${{ secrets.PORT }} script: | + sudo docker stop ${{ secrets.DOCKER_IMAGENAME }} + sudo docker rm ${{ secrets.DOCKER_IMAGENAME }} sudo docker rmi ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKER_IMAGENAME }} sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKER_IMAGENAME }} - sudo docker stop ${{ secrets.DOCKER_IMAGENAME }} 2>/dev/null || true - sudo docker rm ${{ secrets.DOCKER_IMAGENAME }} - sudo docker-compose -f docker-compose.yml up -d - sudo docker system prune -f + sudo docker-compose -f docker-compose.yml up -d \ No newline at end of file diff --git a/.github/workflows/deploy-main.yml b/.github/workflows/deploy-main.yml index 40f73655..8c568fc6 100644 --- a/.github/workflows/deploy-main.yml +++ b/.github/workflows/deploy-main.yml @@ -10,12 +10,9 @@ name: Deploy main branch on: push: branches: [ "main" ] - - jobs: build: runs-on: ubuntu-latest - permissions: contents: read @@ -28,14 +25,6 @@ jobs: java-version: '17' distribution: 'temurin' - # set up application file - - name: Create application.yml - run: | - mkdir -p ./src/main/resources - cd ./src/main/resources - echo "${{ secrets.APPLICATION }}" > application.yml - echo "${{ secrets.APPLICATION_MAIN }}" > application-main.yml - # apply caching - name: Gradle Caching uses: actions/cache@v3 @@ -51,7 +40,7 @@ jobs: - name: Setup Gradle run: | chmod +x ./gradlew - ./gradlew clean build -x test -Pprofile=main + ./gradlew clean build -x test -Pprofile=prod # login dockerhub - name: docker login @@ -83,9 +72,8 @@ jobs: key: ${{ secrets.MAIN_PRIVATE_KEY }} port: ${{ secrets.PORT }} script: | + sudo docker stop ${{ secrets.DOCKER_IMAGENAME }} + sudo docker rm ${{ secrets.DOCKER_IMAGENAME }} sudo docker rmi ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKER_IMAGENAME }} sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKER_IMAGENAME }} - sudo docker stop ${{ secrets.DOCKER_IMAGENAME }} 2>/dev/null || true - sudo docker rm ${{ secrets.DOCKER_IMAGENAME }} sudo docker-compose -f docker-compose.yml up -d - sudo docker system prune -f diff --git a/.github/workflows/test-dev.yml b/.github/workflows/test-dev.yml index fb47198d..521346b0 100644 --- a/.github/workflows/test-dev.yml +++ b/.github/workflows/test-dev.yml @@ -10,12 +10,9 @@ name: Test dev branch on: pull_request: branches: [ "dev" ] - - jobs: test: runs-on: ubuntu-latest - permissions: write-all # set up java @@ -27,14 +24,6 @@ jobs: java-version: '17' distribution: 'temurin' - # set up application file - - name: Create application.yml - run: | - mkdir -p ./src/main/resources - cd ./src/main/resources - echo "${{ secrets.APPLICATION }}" > application.yml - echo "${{ secrets.APPLICATION_TEST }}" > application-test.yml - # apply caching - name: Gradle Caching uses: actions/cache@v3 @@ -50,7 +39,7 @@ jobs: - name: Setup Gradle run: | chmod +x ./gradlew - ./gradlew clean build -Pprofile=test + ./gradlew clean build - name: Publish Test Result uses: EnricoMi/publish-unit-test-result-action@v1 diff --git a/.gitignore b/.gitignore index 439d796c..4496bc32 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,5 @@ out/ ### VS Code ### .vscode/ -/src/main/resources/**/*.yml src/main/resources/static/index.html .env \ No newline at end of file diff --git a/src/main/java/com/gdsc_knu/official_homepage/controller/HealthCheckController.java b/src/main/java/com/gdsc_knu/official_homepage/controller/HealthCheckController.java new file mode 100644 index 00000000..24c8e618 --- /dev/null +++ b/src/main/java/com/gdsc_knu/official_homepage/controller/HealthCheckController.java @@ -0,0 +1,12 @@ +package com.gdsc_knu.official_homepage.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HealthCheckController { + @GetMapping("/check") + public String healthCheck(){ + return "status up"; + } +} diff --git a/src/main/java/com/gdsc_knu/official_homepage/controller/MemberController.java b/src/main/java/com/gdsc_knu/official_homepage/controller/MemberController.java index 3d0ff161..40f455e0 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/controller/MemberController.java +++ b/src/main/java/com/gdsc_knu/official_homepage/controller/MemberController.java @@ -4,7 +4,6 @@ import com.gdsc_knu.official_homepage.authentication.jwt.JwtMemberDetail; import com.gdsc_knu.official_homepage.dto.member.MemberRequest; import com.gdsc_knu.official_homepage.dto.member.MemberResponse; -import com.gdsc_knu.official_homepage.dto.member.TeamInfoResponse; import com.gdsc_knu.official_homepage.entity.Member; import com.gdsc_knu.official_homepage.entity.enumeration.Role; import com.gdsc_knu.official_homepage.entity.enumeration.Track; @@ -32,7 +31,7 @@ public void additionalInfo(@TokenMember JwtMemberDetail jwtMemberDetail, @GetMapping() @Operation(summary="사용자 정보 조회 API") - public ResponseEntity getMemberInfo(@TokenMember JwtMemberDetail jwtMemberDetail){ + public ResponseEntity getMemberInfo(@TokenMember JwtMemberDetail jwtMemberDetail){ return ResponseEntity.ok().body(memberInfoService.getMemberInfo(jwtMemberDetail.getId())); } diff --git a/src/main/java/com/gdsc_knu/official_homepage/controller/TeamController.java b/src/main/java/com/gdsc_knu/official_homepage/controller/TeamController.java index 396ae476..d865b252 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/controller/TeamController.java +++ b/src/main/java/com/gdsc_knu/official_homepage/controller/TeamController.java @@ -2,10 +2,10 @@ import com.gdsc_knu.official_homepage.annotation.TokenMember; import com.gdsc_knu.official_homepage.authentication.jwt.JwtMemberDetail; -import com.gdsc_knu.official_homepage.dto.member.TeamInfoResponse; +import com.gdsc_knu.official_homepage.dto.member.MemberResponse; import com.gdsc_knu.official_homepage.dto.team.TeamResponse; import com.gdsc_knu.official_homepage.service.MemberInfoService; -import com.gdsc_knu.official_homepage.service.TeamService; +import com.gdsc_knu.official_homepage.service.team.TeamService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @@ -25,14 +25,14 @@ public class TeamController { @GetMapping("/{teamId}/member") @Operation(summary = "팀원 정보 조회 API", description = "해당 팀의 팀원목록(유저 ID, 이름, 직렬)을 반환합니다. (미배치된 팀은 조회되지 않습니다.)") - public ResponseEntity> getTeamMembers(@PathVariable("teamId") Long teamId) { + public ResponseEntity> getTeamMembers(@PathVariable("teamId") Long teamId) { return ResponseEntity.ok().body(teamService.getTeamMember(teamId)); } @GetMapping() @Operation(summary="현재 로그인한 사용자가 속한 팀 정보 조회 API", description = "현재 로그인한 사용자가 속한 팀 정보(팀 ID, 팀 이름) 리스트를 반환합니다.") - public ResponseEntity> getMemberTeamInfo(@TokenMember JwtMemberDetail jwtMemberDetail){ + public ResponseEntity> getMemberTeamInfo(@TokenMember JwtMemberDetail jwtMemberDetail){ return ResponseEntity.ok().body(memberInfoService.getMemberTeamInfo(jwtMemberDetail.getId())); } } diff --git a/src/main/java/com/gdsc_knu/official_homepage/dto/admin/memberStatus/AdminMemberResponse.java b/src/main/java/com/gdsc_knu/official_homepage/dto/admin/memberStatus/AdminMemberResponse.java index 9000de4c..e4b0a6e8 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/dto/admin/memberStatus/AdminMemberResponse.java +++ b/src/main/java/com/gdsc_knu/official_homepage/dto/admin/memberStatus/AdminMemberResponse.java @@ -1,6 +1,6 @@ package com.gdsc_knu.official_homepage.dto.admin.memberStatus; -import com.gdsc_knu.official_homepage.dto.member.TeamInfoResponse; +import com.gdsc_knu.official_homepage.dto.team.TeamResponse; import com.gdsc_knu.official_homepage.entity.Member; import com.gdsc_knu.official_homepage.entity.enumeration.Role; import com.gdsc_knu.official_homepage.entity.enumeration.Track; @@ -22,7 +22,7 @@ public class AdminMemberResponse { private String studentNumber; private String email; private String phoneNumber; - private List teams; + private List teams; private Role role; public static AdminMemberResponse from(Member member) { @@ -34,7 +34,7 @@ public static AdminMemberResponse from(Member member) { .email(member.getEmail()) .phoneNumber(member.getPhoneNumber()) .teams(member.getTeams().stream() - .map(TeamInfoResponse::from) + .map(TeamResponse.Main::from) .toList()) .role(member.getRole()) .build(); diff --git a/src/main/java/com/gdsc_knu/official_homepage/dto/admin/team/AdminTeamResponse.java b/src/main/java/com/gdsc_knu/official_homepage/dto/admin/team/AdminTeamResponse.java index 0068c6b8..6a1c3727 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/dto/admin/team/AdminTeamResponse.java +++ b/src/main/java/com/gdsc_knu/official_homepage/dto/admin/team/AdminTeamResponse.java @@ -1,6 +1,6 @@ package com.gdsc_knu.official_homepage.dto.admin.team; -import com.gdsc_knu.official_homepage.dto.member.TeamInfoResponse; +import com.gdsc_knu.official_homepage.dto.team.TeamResponse; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -19,7 +19,7 @@ public static class Team { private Long id; private String teamName; @Builder.Default - private List subTeams = new ArrayList<>(); + private List subTeams = new ArrayList<>(); } @Getter diff --git a/src/main/java/com/gdsc_knu/official_homepage/dto/member/MemberResponse.java b/src/main/java/com/gdsc_knu/official_homepage/dto/member/MemberResponse.java index fcd2e2e1..51f003bb 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/dto/member/MemberResponse.java +++ b/src/main/java/com/gdsc_knu/official_homepage/dto/member/MemberResponse.java @@ -1,31 +1,57 @@ package com.gdsc_knu.official_homepage.dto.member; +import com.gdsc_knu.official_homepage.dto.team.TeamResponse; import com.gdsc_knu.official_homepage.entity.Member; import com.gdsc_knu.official_homepage.entity.enumeration.Role; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; -import lombok.NoArgsConstructor; import java.util.List; -@Getter -@NoArgsConstructor public class MemberResponse { - private String name; - private String profileUrl; - private int age; - private String major; - private String studentNumber; - private String email; - private Role role; - private List teamInfos; - public MemberResponse(Member member, List teamInfos){ - this.name = member.getName(); - this.profileUrl = member.getProfileUrl(); - this.age = member.getAge(); - this.major = member.getMajor(); - this.studentNumber = member.getStudentNumber(); - this.email = member.getEmail(); - this.role = member.getRole(); - this.teamInfos = teamInfos; + @Getter + @Builder + @AllArgsConstructor + public static class Main { + private String name; + private String profileUrl; + private int age; + private String major; + private String studentNumber; + private String email; + private Role role; + private List teamInfos; + public static MemberResponse.Main from (Member member) { + return Main.builder() + .name(member.getName()) + .profileUrl(member.getProfileUrl()) + .age(member.getAge()) + .major(member.getMajor()) + .studentNumber(member.getStudentNumber()) + .email(member.getEmail()) + .role(member.getRole()) + .teamInfos(member.getTeams().stream() + .map(TeamResponse.Main::from) + .toList()) + .build(); + } + } + + @Getter + @Builder + @AllArgsConstructor + public static class WithTrack { + private Long id; + private String name; + private String track; + + public static WithTrack from(Member member) { + return WithTrack.builder() + .id(member.getId()) + .name(member.getName()) + .track(member.getTrack().name()) + .build(); + } } } diff --git a/src/main/java/com/gdsc_knu/official_homepage/dto/member/TeamInfoResponse.java b/src/main/java/com/gdsc_knu/official_homepage/dto/member/TeamInfoResponse.java deleted file mode 100644 index e9302f54..00000000 --- a/src/main/java/com/gdsc_knu/official_homepage/dto/member/TeamInfoResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gdsc_knu.official_homepage.dto.member; - -import com.gdsc_knu.official_homepage.entity.Team; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class TeamInfoResponse { - private Long id; - private String teamName; - - public TeamInfoResponse(Team team) { - this.id = team.getId(); - this.teamName = team.getTeamName(); - } - - public static TeamInfoResponse from(Team team) { - return TeamInfoResponse.builder() - .id(team.getId()) - .teamName(team.getTeamName()) - .build(); - } -} \ No newline at end of file diff --git a/src/main/java/com/gdsc_knu/official_homepage/dto/role/UserRoleRequest.java b/src/main/java/com/gdsc_knu/official_homepage/dto/role/UserRoleRequest.java deleted file mode 100644 index cc7db45a..00000000 --- a/src/main/java/com/gdsc_knu/official_homepage/dto/role/UserRoleRequest.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.gdsc_knu.official_homepage.dto.role; - -import lombok.Getter; - -import java.util.List; - -@Getter -public class UserRoleRequest { - private List userIds; -} diff --git a/src/main/java/com/gdsc_knu/official_homepage/dto/team/TeamResponse.java b/src/main/java/com/gdsc_knu/official_homepage/dto/team/TeamResponse.java index 11037a03..e6095975 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/dto/team/TeamResponse.java +++ b/src/main/java/com/gdsc_knu/official_homepage/dto/team/TeamResponse.java @@ -1,26 +1,21 @@ package com.gdsc_knu.official_homepage.dto.team; -import com.gdsc_knu.official_homepage.entity.Member; +import com.gdsc_knu.official_homepage.entity.Team; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; -import lombok.NoArgsConstructor; public class TeamResponse { - @Builder @Getter - @NoArgsConstructor + @Builder @AllArgsConstructor - public static class MemberInfo { - private Long id; - private String name; - private String track; - - public static MemberInfo from(Member member) { - return MemberInfo.builder() - .id(member.getId()) - .name(member.getName()) - .track(member.getTrack().name()) + public static class Main { + private final Long id; + private final String teamName; + public static Main from(Team team) { + return Main.builder() + .id(team.getId()) + .teamName(team.getTeamName()) .build(); } } diff --git a/src/main/java/com/gdsc_knu/official_homepage/entity/Member.java b/src/main/java/com/gdsc_knu/official_homepage/entity/Member.java index 37e99306..0ea4f18a 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/entity/Member.java +++ b/src/main/java/com/gdsc_knu/official_homepage/entity/Member.java @@ -15,7 +15,6 @@ @Getter public class Member extends BaseTimeEntity{ @Id - @Column(name = "member_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/src/main/java/com/gdsc_knu/official_homepage/entity/MemberTeam.java b/src/main/java/com/gdsc_knu/official_homepage/entity/MemberTeam.java index 8b67ddc4..cc304dd6 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/entity/MemberTeam.java +++ b/src/main/java/com/gdsc_knu/official_homepage/entity/MemberTeam.java @@ -14,13 +14,12 @@ public class MemberTeam { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id") @OnDelete(action = OnDeleteAction.CASCADE) private Member member; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "team_id") @OnDelete(action = OnDeleteAction.CASCADE) private Team team; diff --git a/src/main/java/com/gdsc_knu/official_homepage/entity/Team.java b/src/main/java/com/gdsc_knu/official_homepage/entity/Team.java index fedeac3b..a780bf67 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/entity/Team.java +++ b/src/main/java/com/gdsc_knu/official_homepage/entity/Team.java @@ -35,7 +35,7 @@ public void addSubTeam(Team subteam) { subteam.setParent(this); } - public void setParent(Team parent) { + private void setParent(Team parent) { this.parent = parent; } } diff --git a/src/main/java/com/gdsc_knu/official_homepage/entity/application/Application.java b/src/main/java/com/gdsc_knu/official_homepage/entity/application/Application.java index 0c1c20d4..ab3b2958 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/entity/application/Application.java +++ b/src/main/java/com/gdsc_knu/official_homepage/entity/application/Application.java @@ -24,7 +24,6 @@ @Getter public class Application extends BaseTimeEntity { @Id - @Column(name = "application_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -57,11 +56,11 @@ public class Application extends BaseTimeEntity { @Enumerated(EnumType.STRING) private Track track; + @Column(length = 2048) private String note; @Builder.Default @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "application_id") private List answers = new ArrayList<>(); public Application(Member member, ApplicationRequest applicationRequest) { diff --git a/src/main/java/com/gdsc_knu/official_homepage/entity/application/ApplicationAnswer.java b/src/main/java/com/gdsc_knu/official_homepage/entity/application/ApplicationAnswer.java index aa3fd7e0..25d461b3 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/entity/application/ApplicationAnswer.java +++ b/src/main/java/com/gdsc_knu/official_homepage/entity/application/ApplicationAnswer.java @@ -13,17 +13,15 @@ @Getter public class ApplicationAnswer { @Id - @Column(name = "application_answer_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private int questionNumber; - @Column(columnDefinition = "varchar(1024)") + @Column(length = 1024) private String answer; @ManyToOne - @JoinColumn(name = "application_id") private Application application; public void updateAnswer(String answer) { diff --git a/src/main/java/com/gdsc_knu/official_homepage/exception/DiscordClient.java b/src/main/java/com/gdsc_knu/official_homepage/exception/DiscordClient.java index 3efc0b60..928dbb79 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/exception/DiscordClient.java +++ b/src/main/java/com/gdsc_knu/official_homepage/exception/DiscordClient.java @@ -22,6 +22,7 @@ public class DiscordClient { @Value("${logging.discord.webhook-url}") private String webhookUrl; + // TODO: 비동기 처리 public void sendErrorAlert(Exception e, String message, HttpStatus status, HttpServletRequest request) { DiscordMessage discordMessage = createMessage(e, message, status, request); RestTemplate restTemplate = new RestTemplate(); diff --git a/src/main/java/com/gdsc_knu/official_homepage/exception/ErrorCode.java b/src/main/java/com/gdsc_knu/official_homepage/exception/ErrorCode.java index e75d9942..3e71ef6f 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/exception/ErrorCode.java +++ b/src/main/java/com/gdsc_knu/official_homepage/exception/ErrorCode.java @@ -11,16 +11,29 @@ public enum ErrorCode { * 대문자로 ErrorCode명 정의 (상태코드 / HttpStatus / 메세지) */ - NOT_FOUND(404,HttpStatus.NOT_FOUND, "사용자를 찾을 수 없습니다"), + // User + USER_NOT_FOUND(404,HttpStatus.NOT_FOUND, "사용자를 찾을 수 없습니다"), + + // Auth INVALID_PERMISSION(401,HttpStatus.UNAUTHORIZED, "인증되지 않은 사용자입니다."), - INVALID_INPUT(400, HttpStatus.BAD_REQUEST,"잘못된 요청입니다."), - CONFLICT(409, HttpStatus.CONFLICT, "이미 최종 제출된 지원서 입니다."), - FORBIDDEN(403, HttpStatus.FORBIDDEN, "접근 권한이 없습니다."), JWT_EXPIRED(401, HttpStatus.UNAUTHORIZED, "토큰이 만료되었습니다."), JWT_NOT_FOUND(401, HttpStatus.UNAUTHORIZED, "엑세스 토큰이 존재하지 않습니다."), RT_NOT_FOUND(401, HttpStatus.UNAUTHORIZED, "리프레시 토큰이 저장되어 있지 않습니다."), JWT_INVALID(401, HttpStatus.UNAUTHORIZED, "유효하지 않은 토큰입니다."), JWT_INCORRECT(401, HttpStatus.UNAUTHORIZED, "리프레시 토큰이 일치하지 않습니다."), + FORBIDDEN(403, HttpStatus.FORBIDDEN, "접근 권한이 없습니다."), + + // Application + APPLICATION_NOT_FOUND(404,HttpStatus.NOT_FOUND, "지원서를 찾을 수 없습니다"), + CONFLICT(409, HttpStatus.CONFLICT, "이미 최종 제출된 지원서 입니다."), + INVALID_APPLICATION_STATE(400, HttpStatus.BAD_REQUEST,"지원서 상태가 유효하지 않습니다."), + + // Team + + + INVALID_INPUT(400, HttpStatus.BAD_REQUEST,"잘못된 요청입니다."), + + // Server error FAILED_UPLOAD(500, HttpStatus.INTERNAL_SERVER_ERROR, "파일 업로드에 실패했습니다."), FAILED_SEND_MAIL(500, HttpStatus.INTERNAL_SERVER_ERROR, "메일 전송에 실패했습니다."); diff --git a/src/main/java/com/gdsc_knu/official_homepage/service/MemberInfoService.java b/src/main/java/com/gdsc_knu/official_homepage/service/MemberInfoService.java index 5f94a3d8..24a8b8d6 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/service/MemberInfoService.java +++ b/src/main/java/com/gdsc_knu/official_homepage/service/MemberInfoService.java @@ -2,7 +2,7 @@ import com.gdsc_knu.official_homepage.dto.member.MemberRequest; import com.gdsc_knu.official_homepage.dto.member.MemberResponse; -import com.gdsc_knu.official_homepage.dto.member.TeamInfoResponse; +import com.gdsc_knu.official_homepage.dto.team.TeamResponse; import com.gdsc_knu.official_homepage.entity.Member; import com.gdsc_knu.official_homepage.entity.enumeration.Role; import com.gdsc_knu.official_homepage.entity.enumeration.Track; @@ -10,8 +10,8 @@ import java.util.List; public interface MemberInfoService { - MemberResponse getMemberInfo(Long id); + MemberResponse.Main getMemberInfo(Long id); void addMemberInfo(Long id, MemberRequest.Append memberInfoAdd); - List getMemberTeamInfo(Long id); + List getMemberTeamInfo(Long id); Member getMemberAdmin(String email, Track track, Role role); } diff --git a/src/main/java/com/gdsc_knu/official_homepage/service/MemberInfoServiceImpl.java b/src/main/java/com/gdsc_knu/official_homepage/service/MemberInfoServiceImpl.java index b63d8bd1..ee443a60 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/service/MemberInfoServiceImpl.java +++ b/src/main/java/com/gdsc_knu/official_homepage/service/MemberInfoServiceImpl.java @@ -1,6 +1,7 @@ package com.gdsc_knu.official_homepage.service; import com.gdsc_knu.official_homepage.dto.member.*; +import com.gdsc_knu.official_homepage.dto.team.TeamResponse; import com.gdsc_knu.official_homepage.entity.Member; import com.gdsc_knu.official_homepage.entity.Team; import com.gdsc_knu.official_homepage.entity.enumeration.Role; @@ -22,22 +23,17 @@ public class MemberInfoServiceImpl implements MemberInfoService { @Override @Transactional(readOnly = true) - public MemberResponse getMemberInfo(Long id) { + public MemberResponse.Main getMemberInfo(Long id) { Member member = memberRepository.findById(id) - .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND)); - - List teams = member.getTeams().stream() - .map(TeamInfoResponse::from) - .toList(); - - return new MemberResponse(member,teams); + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + return MemberResponse.Main.from(member); } - @Transactional @Override + @Transactional public void addMemberInfo(Long id, MemberRequest.Append request) { Member member = memberRepository.findById(id) - .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND)); + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); member.addInfo(request.getName(), request.getAge(), request.getMajor(), @@ -51,12 +47,12 @@ public void addMemberInfo(Long id, MemberRequest.Append request) { */ @Override @Transactional(readOnly = true) - public List getMemberTeamInfo(Long id) { + public List getMemberTeamInfo(Long id) { return memberRepository.findById(id) - .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND)) + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)) .getTeams().stream() .sorted(Comparator.comparing(Team::getId).reversed()) - .map(TeamInfoResponse::from) + .map(TeamResponse.Main::from) .toList(); } diff --git a/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminApplicationService.java b/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminApplicationService.java index a6850789..857131c8 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminApplicationService.java +++ b/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminApplicationService.java @@ -7,6 +7,8 @@ import com.gdsc_knu.official_homepage.entity.application.Application; import com.gdsc_knu.official_homepage.entity.enumeration.ApplicationStatus; import com.gdsc_knu.official_homepage.entity.enumeration.Track; +import com.gdsc_knu.official_homepage.exception.CustomException; +import com.gdsc_knu.official_homepage.exception.ErrorCode; import com.gdsc_knu.official_homepage.repository.ApplicationRepository; import com.gdsc_knu.official_homepage.service.MailService; import lombok.RequiredArgsConstructor; @@ -20,7 +22,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.stream.Collectors; @Service @@ -72,14 +73,14 @@ public PagingResponse getApplicationsByOption @Transactional public void markApplication(Long id) { Application application = applicationRepository.findById(id) - .orElseThrow(() -> new NoSuchElementException("해당 지원서류가 없습니다.")); + .orElseThrow(() -> new CustomException(ErrorCode.APPLICATION_NOT_FOUND)); application.changeMark(); } public void decideApplication(Long id, ApplicationStatus status) { Application application = applicationRepository.findById(id) - .orElseThrow(() -> new NoSuchElementException("해당 지원서류가 없습니다.")); + .orElseThrow(() -> new CustomException(ErrorCode.APPLICATION_NOT_FOUND)); updateApplicationStatus(application, status); mailService.sendEach(application); } @@ -92,7 +93,7 @@ private void updateApplicationStatus(Application application, ApplicationStatus } else if (status == ApplicationStatus.REJECTED) { application.reject(); } else { - throw new IllegalArgumentException("제출 완료된 서류만 합격/불합격을 결정할 수 있습니다."); + throw new CustomException(ErrorCode.INVALID_APPLICATION_STATE); } }); } @@ -101,16 +102,15 @@ private void updateApplicationStatus(Application application, ApplicationStatus @Transactional public AdminApplicationResponse.Detail getApplicationDetail(Long id) { Application application = applicationRepository.findById(id) - .orElseThrow(() -> new NoSuchElementException("해당 지원서류가 없습니다.")); - if (!application.isOpened()) - application.open(); + .orElseThrow(() -> new CustomException(ErrorCode.APPLICATION_NOT_FOUND)); + application.open(); return AdminApplicationResponse.Detail.from(application); } @Transactional public void noteApplication(Long id, String note) { Application application = applicationRepository.findById(id) - .orElseThrow(() -> new NoSuchElementException("해당 지원서류가 없습니다.")); + .orElseThrow(() -> new CustomException(ErrorCode.APPLICATION_NOT_FOUND)); application.saveNote(note); } diff --git a/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminMemberStatusServiceImpl.java b/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminMemberStatusServiceImpl.java index fa819ef0..d40e30a1 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminMemberStatusServiceImpl.java +++ b/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminMemberStatusServiceImpl.java @@ -61,7 +61,7 @@ public Long updateMemberRole(AdminMemberRequest.RoleUpdate roleUpdateRequest) { .map(userId -> { try { Member member = memberRepository.findById(userId) - .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND)); + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); member.updateRole(newRole); return 1L; } catch (CustomException e) { @@ -87,7 +87,7 @@ public Long updateMemberTrack(AdminMemberRequest.TrackUpdate trackUpdateRequest) .map(userId -> { try { Member member = memberRepository.findById(userId) - .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND)); + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); member.updateTrack(newTrack); return 1L; } catch (CustomException e) { diff --git a/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminTeamServiceImpl.java b/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminTeamServiceImpl.java index 0356ef1e..396ddb3f 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminTeamServiceImpl.java +++ b/src/main/java/com/gdsc_knu/official_homepage/service/admin/AdminTeamServiceImpl.java @@ -1,7 +1,7 @@ package com.gdsc_knu.official_homepage.service.admin; import com.gdsc_knu.official_homepage.dto.admin.team.*; -import com.gdsc_knu.official_homepage.dto.member.TeamInfoResponse; +import com.gdsc_knu.official_homepage.dto.team.TeamResponse; import com.gdsc_knu.official_homepage.entity.Member; import com.gdsc_knu.official_homepage.entity.MemberTeam; import com.gdsc_knu.official_homepage.entity.Team; @@ -17,7 +17,6 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; -import java.util.Objects; @Service @RequiredArgsConstructor @@ -39,7 +38,7 @@ public List getTeamInfos() { .id(team.getId()) .teamName(team.getTeamName()) .subTeams(team.getSubTeams().stream() - .map(TeamInfoResponse::new) + .map(TeamResponse.Main::from) .toList()) .build()) .toList(); diff --git a/src/main/java/com/gdsc_knu/official_homepage/service/application/ApplicationServiceImpl.java b/src/main/java/com/gdsc_knu/official_homepage/service/application/ApplicationServiceImpl.java index 15190ede..cc087d40 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/service/application/ApplicationServiceImpl.java +++ b/src/main/java/com/gdsc_knu/official_homepage/service/application/ApplicationServiceImpl.java @@ -94,7 +94,7 @@ private void validateApplicationStatus(ApplicationStatus applicationStatus) { */ private Member validateMember(String email) { return memberRepository.findByEmail(email) - .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND)); + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); } /** @@ -106,7 +106,7 @@ private Member validateMember(String email) { */ private Application validateApplicationAccess(String name, String studentNumber) { Application application = applicationRepository.findByNameAndStudentNumber(name, studentNumber) - .orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND, "회원님의 지원서가 존재하지 않습니다.")); + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND, "회원님의 지원서가 존재하지 않습니다.")); if (!application.getApplicationStatus().equals(ApplicationStatus.TEMPORAL)) { throw new CustomException(ErrorCode.CONFLICT); } diff --git a/src/main/java/com/gdsc_knu/official_homepage/service/TeamService.java b/src/main/java/com/gdsc_knu/official_homepage/service/team/TeamService.java similarity index 80% rename from src/main/java/com/gdsc_knu/official_homepage/service/TeamService.java rename to src/main/java/com/gdsc_knu/official_homepage/service/team/TeamService.java index a4375ceb..17b3d79c 100644 --- a/src/main/java/com/gdsc_knu/official_homepage/service/TeamService.java +++ b/src/main/java/com/gdsc_knu/official_homepage/service/team/TeamService.java @@ -1,6 +1,6 @@ -package com.gdsc_knu.official_homepage.service; +package com.gdsc_knu.official_homepage.service.team; -import com.gdsc_knu.official_homepage.dto.team.TeamResponse; +import com.gdsc_knu.official_homepage.dto.member.MemberResponse; import com.gdsc_knu.official_homepage.entity.MemberTeam; import com.gdsc_knu.official_homepage.entity.Team; import com.gdsc_knu.official_homepage.exception.CustomException; @@ -19,7 +19,7 @@ public class TeamService { private final MemberTeamRepository memberTeamRepository; private final TeamRepository teamRepository; - public List getTeamMember(Long teamId) { + public List getTeamMember(Long teamId) { Team team = teamRepository.findById(teamId) .orElseThrow(() -> new NoSuchElementException("존재하지 않는 팀입니다.")); if (team.getParent() == null) @@ -27,7 +27,7 @@ public List getTeamMember(Long teamId) { List memberTeams = memberTeamRepository.findMembersByTeamId(teamId); return memberTeams.stream() - .map(memberTeam -> TeamResponse.MemberInfo.from(memberTeam.getMember())) + .map(memberTeam -> MemberResponse.WithTrack.from(memberTeam.getMember())) .toList(); } } diff --git a/src/main/resources/application-auth.yml b/src/main/resources/application-auth.yml new file mode 100644 index 00000000..116805d9 --- /dev/null +++ b/src/main/resources/application-auth.yml @@ -0,0 +1,19 @@ +oauth2: # default + google: + client-id: ${GOOGLE_CLIENT_ID:default} + client-secret: ${GOOGLE_CLIENT_SECRET:default} + redirect-uri: ${GOOGLE_DEV_REDIRECT_URI:default} + token-uri: https://oauth2.googleapis.com/token + userinfo-uri: https://www.googleapis.com/oauth2/v3/userinfo +jwt: + secret: ${JWT_SECRET:aelakjfliwuebnkjshlkjaejdkjsjylakejhfksjdaelakjfliwuebnkjshlkjaejdkjsjylakejhfksjd} + access-token-expiration: 3600000 + refresh-token-expiration: 604800000 +--- +spring: + config: + activate: + on-profile: prod +oauth2: + google: + redirect-uri: ${GOOGLE_PROD_REDIRECT_URI} \ No newline at end of file diff --git a/src/main/resources/application-db.yml b/src/main/resources/application-db.yml new file mode 100644 index 00000000..a6cc44f0 --- /dev/null +++ b/src/main/resources/application-db.yml @@ -0,0 +1,76 @@ +spring: #default, test configuration (H2) + datasource: + url: jdbc:h2:mem:gdsc + username: sa + password: + driver-class-name: org.h2.Driver + jpa: + hibernate: + ddl-auto: create + show-sql: true + database-platform: org.hibernate.dialect.H2Dialect + properties: + hibernate: + default_batch_fetch_size: 100 + data: + redis: + host: 127.0.0.1 + port: 6379 +--- +spring: # mysql 공통 + config: + activate: + on-profile: local, dev, prod + datasource.driver-class-name: com.mysql.cj.jdbc.Driver + jpa.database-platform: org.hibernate.dialect.MySQL8Dialect +--- +spring: + config: + activate: + on-profile: local + datasource: + url: jdbc:mysql://localhost:3306/gdsc + username: root + password: 1234 + jpa: + hibernate: + ddl-auto: update + sql: + init: + mode: never +--- +spring: + config: + activate: + on-profile: dev + datasource: + url: ${DEV_DB_PATH} + username: ${DEV_DB_USERNAME} + password: ${DEV_DB_PASSWORD} + jpa: + hibernate: + ddl-auto: update + sql: + init: + mode: never + data: + redis: + host: ${REDIS_HOST} +--- +spring: + config: + activate: + on-profile: prod + datasource: + url: ${PROD_DB_PATH} + username: ${PROD_DB_USERNAME} + password: ${PROD_DB_PASSWORD} + jpa: + hibernate: + ddl-auto: none + sql: + init: + mode: never + data: + redis: + host: ${REDIS_HOST} \ No newline at end of file diff --git a/src/main/resources/application-doc.yml b/src/main/resources/application-doc.yml new file mode 100644 index 00000000..8a93bd6c --- /dev/null +++ b/src/main/resources/application-doc.yml @@ -0,0 +1,14 @@ +springdoc: + swagger-ui: + path: /api-docs + operations-sorter: alpha + paths-to-match: /api/** + use-fqn: true +--- +spring: + config: + activate: + on-profile: prod +springdoc: + api-docs: + enabled: false \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 00000000..e66c512b --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,32 @@ +spring: + profiles: + include: + - db + - auth + - doc + cloud: + aws: + credentials: + access-key: ${AWS_ACCESS_KEY:default} + secret-key: ${AWS_SECRET_KEY:default} + region: + static: ${AWS_REGION:default} + s3: + bucket: ${AWS_S3_BUCKET:default} + stack: + auto: false + mail: + host: smtp.gmail.com + port: ${SMTP_PORT:0000} + username: ${SMTP_USERNAME:default} + password: ${SMTP_PASSWORD:default} + properties: + mail: + smtp: + auth: true + starttls: + enable: true +logging: + discord: + webhook-url: ${DISCORD_WEBHOOK_URL:default} + diff --git a/src/test/java/com/gdsc_knu/official_homepage/OfficialHomepageApplicationTests.java b/src/test/java/com/gdsc_knu/official_homepage/OfficialHomepageApplicationTests.java index 53cf4964..d58a5b31 100644 --- a/src/test/java/com/gdsc_knu/official_homepage/OfficialHomepageApplicationTests.java +++ b/src/test/java/com/gdsc_knu/official_homepage/OfficialHomepageApplicationTests.java @@ -5,9 +5,6 @@ import org.springframework.test.context.TestPropertySource; @SpringBootTest -@TestPropertySource(properties = { - "spring.config.location = src/main/resources/application.yml, src/main/resources/application-test.yml" -}) class OfficialHomepageApplicationTests { @Test