From 45b588276f6a3a8d11d5c04fd5c02eb88af3a745 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 3 Jul 2024 13:33:35 +0900 Subject: [PATCH 001/205] =?UTF-8?q?[=E2=9A=B0=EF=B8=8Fdel/#12]=20=EC=93=B8?= =?UTF-8?q?=EB=AA=A8=EC=97=86=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terning/terningserver/exception/enums/SuccessMessage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index b366fe4..48ab89e 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -11,7 +11,6 @@ public enum SuccessMessage { SUCCESS_GET_CATEGORIES(200, true, "카테고리 리스트 조회를 성공하였습니다."), SUCCESS_CREATE_WORD(201, true, "단어를 성공적으로 추가하였습니다."), SUCCESS_GET_WORDS(200, true, "단어 리스트 조회를 성공하였습니다."), - SUCCESS_GET_MEMORIZED_WORDS(200, true, "외운 단어 리스트 조회를 성공하였습니다."), SUCCESS_GET_WORD(200, true, "특정 단어 조회를 성공하였습니다."); private final int status; From 4f32157c8b2f832159909686565a4537e505c68b Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 3 Jul 2024 13:33:35 +0900 Subject: [PATCH 002/205] =?UTF-8?q?[=F0=9F=92=A1test/#12]=20Discord=20<>?= =?UTF-8?q?=20Github=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terning/terningserver/exception/enums/SuccessMessage.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index b366fe4..48ab89e 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -11,7 +11,6 @@ public enum SuccessMessage { SUCCESS_GET_CATEGORIES(200, true, "카테고리 리스트 조회를 성공하였습니다."), SUCCESS_CREATE_WORD(201, true, "단어를 성공적으로 추가하였습니다."), SUCCESS_GET_WORDS(200, true, "단어 리스트 조회를 성공하였습니다."), - SUCCESS_GET_MEMORIZED_WORDS(200, true, "외운 단어 리스트 조회를 성공하였습니다."), SUCCESS_GET_WORD(200, true, "특정 단어 조회를 성공하였습니다."); private final int status; From 63a73ee7e327f92908e5e43fab8b3f5031fd3497 Mon Sep 17 00:00:00 2001 From: Willy Date: Sat, 6 Jul 2024 03:16:41 +0900 Subject: [PATCH 003/205] =?UTF-8?q?[=E2=9C=A8feat/#14]=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=20=EC=97=B0?= =?UTF-8?q?=EA=B4=80=EA=B4=80=EA=B3=84=20=EB=A7=A4=ED=95=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TerningserverApplication.java | 2 + .../terningserver/domain/Advertisement.java | 21 ++++++++ .../terning/terningserver/domain/Company.java | 23 ++++++++ .../terning/terningserver/domain/Filter.java | 31 +++++++++++ .../domain/InternshipAnnouncement.java | 53 +++++++++++++++++++ .../terning/terningserver/domain/Scrap.java | 37 +++++++++++++ .../terning/terningserver/domain/User.java | 53 +++++++++++++++++++ .../domain/common/BaseTimeEntity.java | 25 +++++++++ .../terningserver/domain/common/Empty.txt | 0 .../terningserver/domain/enums/AuthType.java | 5 ++ .../terningserver/domain/enums/Color.java | 22 ++++++++ .../domain/enums/CompanyCategory.java | 35 ++++++++++++ .../terningserver/domain/enums/Empty.txt | 0 .../terningserver/domain/enums/Grade.java | 34 ++++++++++++ .../terningserver/domain/enums/State.java | 6 +++ .../domain/enums/WorkingPeriod.java | 31 +++++++++++ 16 files changed, 378 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/domain/Advertisement.java create mode 100644 src/main/java/org/terning/terningserver/domain/Company.java create mode 100644 src/main/java/org/terning/terningserver/domain/Filter.java create mode 100644 src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java create mode 100644 src/main/java/org/terning/terningserver/domain/Scrap.java create mode 100644 src/main/java/org/terning/terningserver/domain/User.java create mode 100644 src/main/java/org/terning/terningserver/domain/common/BaseTimeEntity.java delete mode 100644 src/main/java/org/terning/terningserver/domain/common/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/domain/enums/AuthType.java create mode 100644 src/main/java/org/terning/terningserver/domain/enums/Color.java create mode 100644 src/main/java/org/terning/terningserver/domain/enums/CompanyCategory.java delete mode 100644 src/main/java/org/terning/terningserver/domain/enums/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/domain/enums/Grade.java create mode 100644 src/main/java/org/terning/terningserver/domain/enums/State.java create mode 100644 src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java diff --git a/src/main/java/org/terning/terningserver/TerningserverApplication.java b/src/main/java/org/terning/terningserver/TerningserverApplication.java index c1ea2a7..2faebbc 100644 --- a/src/main/java/org/terning/terningserver/TerningserverApplication.java +++ b/src/main/java/org/terning/terningserver/TerningserverApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing @SpringBootApplication public class TerningserverApplication { diff --git a/src/main/java/org/terning/terningserver/domain/Advertisement.java b/src/main/java/org/terning/terningserver/domain/Advertisement.java new file mode 100644 index 0000000..bb38dcd --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/Advertisement.java @@ -0,0 +1,21 @@ +package org.terning.terningserver.domain; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.terning.terningserver.domain.common.BaseTimeEntity; + +import static jakarta.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PROTECTED; + +@Entity +@Getter +@NoArgsConstructor(access = PROTECTED) +public class Advertisement extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = IDENTITY) + private Long id; +} diff --git a/src/main/java/org/terning/terningserver/domain/Company.java b/src/main/java/org/terning/terningserver/domain/Company.java new file mode 100644 index 0000000..aa11de8 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/Company.java @@ -0,0 +1,23 @@ +package org.terning.terningserver.domain; + + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import org.terning.terningserver.domain.enums.CompanyCategory; + +@Embeddable +public class Company { + + @Column(nullable = false, length = 64) + private String companyInfo; // 기업명 + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private CompanyCategory companyCategory; // 회사 카테고리 + + @Column(nullable = false, length = 256) + private String companyImage; + +} diff --git a/src/main/java/org/terning/terningserver/domain/Filter.java b/src/main/java/org/terning/terningserver/domain/Filter.java new file mode 100644 index 0000000..a9554d9 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/Filter.java @@ -0,0 +1,31 @@ +package org.terning.terningserver.domain; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.terning.terningserver.domain.enums.Grade; +import org.terning.terningserver.domain.enums.WorkingPeriod; +import static lombok.AccessLevel.PROTECTED; +import static jakarta.persistence.GenerationType.IDENTITY; +import java.time.YearMonth; + +@Entity +@Getter +@NoArgsConstructor(access = PROTECTED) +public class Filter { + + @Id + @GeneratedValue(strategy = IDENTITY) + private Long id; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private Grade grade; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private WorkingPeriod workingPeriod; + + @Column(nullable = false) + private YearMonth startDate; +} diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java new file mode 100644 index 0000000..328b80b --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -0,0 +1,53 @@ +package org.terning.terningserver.domain; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.terning.terningserver.domain.common.BaseTimeEntity; + +import java.time.YearMonth; +import java.util.Date; + +import static jakarta.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PROTECTED; + +@Entity +@Getter +@NoArgsConstructor(access = PROTECTED) +public class InternshipAnnouncement extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = IDENTITY) + private Long id; // 고유 ID + + @Column(nullable = false, length = 64) + private String title; // 인턴십 제목 + + private Date deadline; // 지원 마감일 + + @Column(length = 16) + private String workingPeriod; // 근무 기간 + + private YearMonth startDate; // 시작 날짜 + + @Column(nullable = false) + private int viewCount; // 조회 수 + + @Column(nullable = false) + private int scrapCount; // 스크랩 수 + + @Column(nullable = false, length = 256) + private String url; // 인턴십 공고 URL + + @Embedded + private Company company; + + @Column(columnDefinition = "TEXT") + private String qualifications; // 자격 요건 + + @Column(columnDefinition = "TEXT") + private String jobType; // 직무 유형 + + @Column(columnDefinition = "TEXT") + private String detail; // 상세 내용 +} diff --git a/src/main/java/org/terning/terningserver/domain/Scrap.java b/src/main/java/org/terning/terningserver/domain/Scrap.java new file mode 100644 index 0000000..c46bf9e --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/Scrap.java @@ -0,0 +1,37 @@ +package org.terning.terningserver.domain; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.terning.terningserver.domain.common.BaseTimeEntity; +import org.terning.terningserver.domain.enums.Color; + +import java.awt.*; + +import static jakarta.persistence.EnumType.STRING; +import static lombok.AccessLevel.PROTECTED; +import static jakarta.persistence.FetchType.LAZY; +import static jakarta.persistence.GenerationType.IDENTITY; + +@Entity +@Getter +@NoArgsConstructor(access = PROTECTED) +public class Scrap extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = IDENTITY) + private Long id; // 스크랩 고유 ID + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; // 스크랩한 사용자 + + @OneToOne(fetch = LAZY) + @JoinColumn(name = "internshipAnnouncement_id", nullable = false) + private InternshipAnnouncement internshipAnnouncement; // 스크랩한 인턴십 공고 + + @Enumerated(STRING) + @Column(nullable = false) + private Color color; // 스크랩 색상 (사용자가 지정) + +} diff --git a/src/main/java/org/terning/terningserver/domain/User.java b/src/main/java/org/terning/terningserver/domain/User.java new file mode 100644 index 0000000..11351a9 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/User.java @@ -0,0 +1,53 @@ +package org.terning.terningserver.domain; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.terning.terningserver.domain.common.BaseTimeEntity; +import org.terning.terningserver.domain.enums.AuthType; +import org.terning.terningserver.domain.enums.State; + +import java.util.ArrayList; +import java.util.List; + +import static jakarta.persistence.EnumType.STRING; +import static jakarta.persistence.FetchType.LAZY; +import static jakarta.persistence.GenerationType.IDENTITY; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "Users") +public class User extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = IDENTITY) + private Long id; // 사용자 고유 ID + + @OneToOne(fetch = LAZY) + @JoinColumn(name="filter_id", nullable = false) + private Filter filter; // 사용자 필터 설정 + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) + private List scrapList = new ArrayList<>(); // 스크랩 공고 + + @Column(nullable = false, length = 12) + private String name; // 사용자 이름 + +// private String email; //이메일 + +// private String userImage; //유저 아이콘 + + @Enumerated(STRING) + @Column(nullable = false) + private AuthType authType; // 인증 유형 (예: 카카오, 애플) + + @Column(nullable = false, length = 256) + private String authId; // 인증 서비스에서 제공하는 고유 ID + + @Enumerated(STRING) + @Column(nullable = false) + private State state; // 사용자 상태 (예: 활성, 비활성, 정지) + +} diff --git a/src/main/java/org/terning/terningserver/domain/common/BaseTimeEntity.java b/src/main/java/org/terning/terningserver/domain/common/BaseTimeEntity.java new file mode 100644 index 0000000..bdcc14c --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/common/BaseTimeEntity.java @@ -0,0 +1,25 @@ +package org.terning.terningserver.domain.common; + +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Getter +@EntityListeners(AuditingEntityListener.class) +@MappedSuperclass +public abstract class BaseTimeEntity { + + @CreatedDate + @Column(name = "created_at", nullable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "modified_at", nullable = false) + private LocalDateTime modifiedAt; +} diff --git a/src/main/java/org/terning/terningserver/domain/common/Empty.txt b/src/main/java/org/terning/terningserver/domain/common/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/domain/enums/AuthType.java b/src/main/java/org/terning/terningserver/domain/enums/AuthType.java new file mode 100644 index 0000000..d565eb6 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/enums/AuthType.java @@ -0,0 +1,5 @@ +package org.terning.terningserver.domain.enums; + +public enum AuthType { + KAKAO, APPLE +} diff --git a/src/main/java/org/terning/terningserver/domain/enums/Color.java b/src/main/java/org/terning/terningserver/domain/enums/Color.java new file mode 100644 index 0000000..123ed79 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/enums/Color.java @@ -0,0 +1,22 @@ +package org.terning.terningserver.domain.enums; + + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum Color { + + RED(0, "ED4E54"), + ORANGE1(1, "EE7647"), + ORANGE2(2, "5397F3"), + YELLOW(3, "F5E660"), + GREEN1(4, "C4E953"), + GREEN2(5, "84D558"), + BLUE1(6, "45D0CC"), + BLUE2(7, "4AA9F2"), + PURPLE(8, "9B64E2"), + PINK(9, "F260AC"); + + private final int key; + private final String value; +} diff --git a/src/main/java/org/terning/terningserver/domain/enums/CompanyCategory.java b/src/main/java/org/terning/terningserver/domain/enums/CompanyCategory.java new file mode 100644 index 0000000..ce8ad40 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/enums/CompanyCategory.java @@ -0,0 +1,35 @@ +package org.terning.terningserver.domain.enums; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum CompanyCategory { + + LARGE_AND_MEDIUM_COMPANIES(0, "대기업/중견기업"), + SMALL_COMPANIES(1, "중소기업"), + PUBLIC_INSTITUTIONS(2, "공공기관/공기업"), + FOREIGN_COMPANIES(3, "외국계기업"), + STARTUPS(4, "스타트업"), + NON_PROFIT_ORGANIZATIONS(5, "비영리단체/재단"), + OTHERS(6, "기타"); + + private final int key; + private final String value; + + public static CompanyCategory fromKey(int key){ + for(CompanyCategory category : CompanyCategory.values()){ + if(category.key == key){ + return category; + } + } + throw new IllegalArgumentException("올바르지 않은 요청 값입니다."); + } + public static CompanyCategory fromString(String value){ + for(CompanyCategory category : CompanyCategory.values()){ + if(category.value.equalsIgnoreCase(value)) { + return category; + } + } + throw new IllegalArgumentException("올바르지 않은 요청 값입니다."); + } +} diff --git a/src/main/java/org/terning/terningserver/domain/enums/Empty.txt b/src/main/java/org/terning/terningserver/domain/enums/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/domain/enums/Grade.java b/src/main/java/org/terning/terningserver/domain/enums/Grade.java new file mode 100644 index 0000000..3fe639a --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/enums/Grade.java @@ -0,0 +1,34 @@ +package org.terning.terningserver.domain.enums; + +import lombok.RequiredArgsConstructor; + + +@RequiredArgsConstructor +public enum Grade { + FRESHMAN(1, "1학년"), + SOPHOMORE(2, "2학년"), + JUNIOR(3, "3학년"), + SENIOR(4, "4학년"); + + private final int key; + private final String value; + + public static Grade fromKey(int key){ + for(Grade grade : Grade.values()){ + if(grade.key == key){ + return grade; + } + } + throw new IllegalArgumentException("올바르지 않은 요청 값입니다."); + } + + public static Grade fromString(String value){ + for(Grade grade : Grade.values()){ + if(grade.value.equalsIgnoreCase(value)) { + return grade; + } + } + throw new IllegalArgumentException("올바르지 않은 요청 값입니다."); + } + +} diff --git a/src/main/java/org/terning/terningserver/domain/enums/State.java b/src/main/java/org/terning/terningserver/domain/enums/State.java new file mode 100644 index 0000000..ee314b7 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/enums/State.java @@ -0,0 +1,6 @@ +package org.terning.terningserver.domain.enums; + +public enum State { + //활성화(active), 비활성화(inactive), 정지(banned) + ACTIVE, INACTIVE, BANNED +} diff --git a/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java b/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java new file mode 100644 index 0000000..d6c4c17 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java @@ -0,0 +1,31 @@ +package org.terning.terningserver.domain.enums; + + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum WorkingPeriod { + OPTION1(1, "1개월 ~ 3개월"), + OPTION2(2, "4개월 ~ 6개월"), + OPTION3(3, "7개월 이상"); + + private final int key; + private final String value; + + public static WorkingPeriod fromKey(int key){ + for(WorkingPeriod period : WorkingPeriod.values()){ + if(period.key == key){ + return period; + } + } + throw new IllegalArgumentException("올바르지 않은 요청 값입니다."); + } + public static WorkingPeriod fromString(String value){ + for(WorkingPeriod period : WorkingPeriod.values()){ + if(period.value.equalsIgnoreCase(value)) { + return period; + } + } + throw new IllegalArgumentException("올바르지 않은 요청 값입니다."); + } +} From 1837cfbdfe13ac3d2b54b56180eb055252de1472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 20:37:29 +0900 Subject: [PATCH 004/205] =?UTF-8?q?[=E2=9C=85chore/#17]:=20JWT=EC=99=80=20?= =?UTF-8?q?Spring=20Security=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - JSON Web Token (JWT) 처리를 위해 jjwt-api, jjwt-impl, jjwt-jackson 버전 0.11.5 추가. - 어플리케이션의 보안 기능을 통합하기 위해 Spring Boot Starter Security 추가. --- build.gradle | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build.gradle b/build.gradle index f77d87d..72c88dd 100644 --- a/build.gradle +++ b/build.gradle @@ -41,6 +41,15 @@ dependencies { //Health-check implementation 'org.springframework.boot:spring-boot-starter-actuator' + + //JWT + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' + implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' + implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' + + // Spring Security + implementation 'org.springframework.boot:spring-boot-starter-security' + } tasks.named('test') { From 046b23b0d7ecedd52ca02fed1db0ca72a7df6dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 20:46:50 +0900 Subject: [PATCH 005/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20=20ValueConfig?= =?UTF-8?q?=EB=A5=BC=20=ED=86=B5=ED=95=9C=20JWT=20=EC=86=8D=EC=84=B1=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EB=B0=8F=20=EC=B4=88=EA=B8=B0=ED=99=94=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - @Configuration 및 @Getter 어노테이션을 사용하여 JWT 관련 속성을 관리하는 ValueConfig 클래스 도입. - 외부 설정 파일에서 secretKey, kakaoUri, appleUri, accessTokenExpired, refreshTokenExpired 등의 속성을 주입받기 위해 @Value 어노테이션 사용. - 객체 생성 후 초기화를 위해 @PostConstruct 메소드에서 secretKey를 UTF-8로 인코딩 후 Base64로 인코딩 처리. --- .../terningserver/config/ValueConfig.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/config/ValueConfig.java diff --git a/src/main/java/org/terning/terningserver/config/ValueConfig.java b/src/main/java/org/terning/terningserver/config/ValueConfig.java new file mode 100644 index 0000000..b28f71c --- /dev/null +++ b/src/main/java/org/terning/terningserver/config/ValueConfig.java @@ -0,0 +1,34 @@ +package org.terning.terningserver.config; + +import jakarta.annotation.PostConstruct; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +@Configuration +@Getter +public class ValueConfig { + + @Value("${jwt.secret}") + private String secretKey; + + @Value("${jwt.KAKAO_URL}") + private String kakaoUri; + + @Value("${jwt.APPLE_URL}") + private String appleUri; + + @Value("${jwt.ACCESS_TOKEN_EXPIRED}") + private Long accessTokenExpired; + + @Value("${jwt.REFRESH_TOKEN_EXPIRED}") + private Long refreshTokenExpired; + + @PostConstruct + protected void init() { + secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8)); + } +} From a6c30c15be156c944dc35d51fd087e20a5cded9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 20:53:30 +0900 Subject: [PATCH 006/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20JWT=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - JwtTokenProvider 클래스를 통해 JWT 토큰 생성 로직 구현. - Authentication 정보를 사용하여 클레임 설정. - 발행 시간 및 만료 시간을 포함한 JWT 생성. - ValueConfig에서 제공하는 secretKey를 사용하여 서명 키 생성. - JWT 헤더와 클레임을 정의하여 토큰의 보안 및 유효성을 강화. --- .../terningserver/jwt/JwtTokenProvider.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java diff --git a/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java b/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java new file mode 100644 index 0000000..4817a79 --- /dev/null +++ b/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java @@ -0,0 +1,47 @@ +package org.terning.terningserver.jwt; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; +import org.terning.terningserver.config.ValueConfig; + +import javax.crypto.SecretKey; +import java.util.Date; + +import static io.jsonwebtoken.Header.JWT_TYPE; +import static io.jsonwebtoken.Header.TYPE; +import static io.jsonwebtoken.security.Keys.hmacShaKeyFor; +import static java.util.Base64.getEncoder; + +@Slf4j +@Component +@RequiredArgsConstructor +public class JwtTokenProvider { + + private final ValueConfig valueConfig; + + public String generateToken(Authentication authentication, long expiration) { + return Jwts.builder() + .setHeaderParam(TYPE, JWT_TYPE) + .setClaims(generateClaims(authentication)) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + expiration)) + .signWith(getSigningKey()) + .compact(); + } + + private Claims generateClaims(Authentication authentication) { + val claims = Jwts.claims(); + claims.put("userId", authentication.getPrincipal()); + return claims; + } + + private SecretKey getSigningKey() { + val encodedKey = getEncoder().encodeToString(valueConfig.getSecretKey().getBytes()); + return hmacShaKeyFor(encodedKey.getBytes()); + } +} From 6d32dcc80b878f5354387c51dd8bea162ecf5d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 21:11:25 +0900 Subject: [PATCH 007/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20JWT=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=ED=95=84=ED=84=B0=20=EA=B8=B0=EB=B3=B8=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - JwtAuthenticationFilter 클래스를 생성하여 OncePerRequestFilter를 상속받음. - HttpServletRequest에서 JWT 액세스 토큰을 추출하는 로직 구현. - 요청 헤더의 'Authorization'에서 'Bearer ' 접두어를 사용하여 토큰 존재 여부 및 추출 기능 구현. - doFilterInternal 메소드는 현재 비어 있으며, 추후 인증 로직을 구현할 예정. --- .../jwt/JwtAuthenticationFilter.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java diff --git a/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java b/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java new file mode 100644 index 0000000..a420001 --- /dev/null +++ b/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java @@ -0,0 +1,46 @@ +package org.terning.terningserver.jwt; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import lombok.val; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import org.terning.terningserver.config.ValueConfig; + +import java.io.IOException; + +import static org.springframework.http.HttpHeaders.AUTHORIZATION; + +@Slf4j +@Component +@RequiredArgsConstructor +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + private static JwtTokenProvider jwtTokenProvider; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + + } + + private String getAccessTokenFromRequest(HttpServletRequest request) { + return isContainsAccessToken(request) ? getAuthorizationAccessToken(request) : null; + } + + private boolean isContainsAccessToken(HttpServletRequest request) { + val authorization = request.getHeader(AUTHORIZATION); + return authorization != null && authorization.startsWith(ValueConfig.BEARER_HEADER); + } + + private String getAuthorizationAccessToken(HttpServletRequest request) { + return getTokenFromBearerString(request.getHeader(AUTHORIZATION)); + } + + private String getTokenFromBearerString(String token) { + return token.replaceFirst(ValueConfig.BEARER_HEADER, ValueConfig.BLANK); + } +} From 1c7e4467b71b599a30c348fea1ca92c95d86e9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 21:13:20 +0900 Subject: [PATCH 008/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20=EC=95=A0?= =?UTF-8?q?=ED=94=8C=EB=A6=AC=EC=BC=80=EC=9D=B4=EC=85=98=20=EC=83=81?= =?UTF-8?q?=EC=88=98=20=EC=A0=95=EC=9D=98=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - iOS 및 Android의 앱 버전 및 강제 업데이트 버전 관련 상수 추가. - 사용자에게 알림을 보낼 때 사용할 제목과 내용의 상수 정의. - JWT 토큰 처리를 위한 구분자, Bearer 토큰 헤더 및 기타 관련 상수 설정. - RSA 암호화 알고리즘을 위한 키, 지수, 알고리즘 종류 등의 상수 추가. - 인증 헤더 키와 암호화 관련 상수의 일관된 정의를 통해 보안성 강화. --- .../terningserver/config/ValueConfig.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/org/terning/terningserver/config/ValueConfig.java b/src/main/java/org/terning/terningserver/config/ValueConfig.java index b28f71c..bbff185 100644 --- a/src/main/java/org/terning/terningserver/config/ValueConfig.java +++ b/src/main/java/org/terning/terningserver/config/ValueConfig.java @@ -27,6 +27,23 @@ public class ValueConfig { @Value("${jwt.REFRESH_TOKEN_EXPIRED}") private Long refreshTokenExpired; + public static final String IOS_FORCE_UPDATE_VERSION = "0.0.9"; + public static final String IOS_APP_VERSION = "1.0.0"; + public static final String ANDROID_FORCE_UPDATE_VERSION = "1.0.1"; + public static final String ANDROID_APP_VERSION = "1.0.1"; + public static final String NOTIFICATION_TITLE = "새로운 버전이 업데이트 되었어요!"; + public static final String NOTIFICATION_CONTENT = "안정적인 서비스 사용을 위해\n최신버전으로 업데이트 해주세요."; + public static final String TOKEN_VALUE_DELIMITER = "\\."; + public static final String BEARER_HEADER = "Bearer "; + public static final String BLANK = ""; + public static final String MODULUS = "n"; + public static final String EXPONENT = "e"; + public static final String KID_HEADER_KEY = "kid"; + public static final String ALG_HEADER_KEY = "alg"; + public static final String RSA = "RSA"; + public static final String KEY = "keys"; + public static final String ID = "sub"; + @PostConstruct protected void init() { secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8)); From 41df25b5c7775274d0c6de0bdfa1616cb97f7307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 21:18:30 +0900 Subject: [PATCH 009/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20=20JWT=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=83=81=ED=83=9C=20=EC=97=B4=EA=B1=B0?= =?UTF-8?q?=ED=98=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - JwtValidationType 열거형을 추가하여 JWT의 유효성 검사 결과를 명확히 구분. - VALID_JWT: 유효한 JWT 토큰. - INVALID_JWT_TOKEN: 유효하지 않은 형식의 JWT 토큰. - EXPIRED_JWT_TOKEN: 만료된 JWT 토큰. - UNSUPPORTED_JWT_TOKEN: 지원되지 않는 형식의 JWT 토큰. - EMPTY_JWT: 내용이 없는 JWT 토큰. --- .../org/terning/terningserver/jwt/JwtValidationType.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/jwt/JwtValidationType.java diff --git a/src/main/java/org/terning/terningserver/jwt/JwtValidationType.java b/src/main/java/org/terning/terningserver/jwt/JwtValidationType.java new file mode 100644 index 0000000..3e5c98c --- /dev/null +++ b/src/main/java/org/terning/terningserver/jwt/JwtValidationType.java @@ -0,0 +1,9 @@ +package org.terning.terningserver.jwt; + +public enum JwtValidationType { + VALID_JWT, + INVALID_JWT_TOKEN, + EXPIRED_JWT_TOKEN, + UNSUPPORTED_JWT_TOKEN, + EMPTY_JWT +} From 7e54308cd7816cc3f8aa1b0114035376982ad823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 21:41:29 +0900 Subject: [PATCH 010/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20JWT=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=B6=94=EC=B6=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - validateToken 메소드를 통해 JWT 토큰의 유효성 검사 로직을 구현. - 각 종류의 예외에 따라 적절한 JwtValidationType을 반환. - MalformedJwtException, ExpiredJwtException, UnsupportedJwtException, IllegalArgumentException 처리 추가. - getUserFromJwt 메소드를 통해 토큰에서 사용자 ID 추출 기능 구현. - getBody 메소드를 통해 JWT 파서를 구성하고, 서명 키를 사용하여 토큰의 클레임을 반환하는 로직 구현. - 이 변경은 JWT 토큰을 안정적으로 처리하고, 필요한 사용자 정보를 효율적으로 추출하는 기능을 제공합니다. --- .../terningserver/jwt/JwtTokenProvider.java | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java b/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java index 4817a79..b53cd20 100644 --- a/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java +++ b/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java @@ -1,7 +1,6 @@ package org.terning.terningserver.jwt; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; @@ -16,6 +15,7 @@ import static io.jsonwebtoken.Header.TYPE; import static io.jsonwebtoken.security.Keys.hmacShaKeyFor; import static java.util.Base64.getEncoder; +import static org.terning.terningserver.jwt.JwtValidationType.*; @Slf4j @Component @@ -34,6 +34,25 @@ public String generateToken(Authentication authentication, long expiration) { .compact(); } + public JwtValidationType validateToken(String token) { + try { + getBody(token); + return VALID_JWT; + } catch (MalformedJwtException exception) { + log.error(exception.getMessage()); + return INVALID_JWT_TOKEN; + } catch (ExpiredJwtException exception) { + log.error(exception.getMessage()); + return EXPIRED_JWT_TOKEN; + } catch (UnsupportedJwtException exception) { + log.error(exception.getMessage()); + return UNSUPPORTED_JWT_TOKEN; + } catch (IllegalArgumentException exception) { + log.error(exception.getMessage()); + return EMPTY_JWT; + } + } + private Claims generateClaims(Authentication authentication) { val claims = Jwts.claims(); claims.put("userId", authentication.getPrincipal()); @@ -44,4 +63,17 @@ private SecretKey getSigningKey() { val encodedKey = getEncoder().encodeToString(valueConfig.getSecretKey().getBytes()); return hmacShaKeyFor(encodedKey.getBytes()); } + + public Long getUserFromJwt(String token) { + val claims = getBody(token); + return Long.parseLong(claims.get("memberId").toString()); + } + + private Claims getBody(final String token) { + return Jwts.parserBuilder() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } } From 94599517f9c3dd7851eae6523418b8a18140a6c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 21:45:55 +0900 Subject: [PATCH 011/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8F=C2=A0refactor/#17]:?= =?UTF-8?q?=20memberId=20->=20userId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/terning/terningserver/jwt/JwtTokenProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java b/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java index b53cd20..7e80c27 100644 --- a/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java +++ b/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java @@ -66,7 +66,7 @@ private SecretKey getSigningKey() { public Long getUserFromJwt(String token) { val claims = getBody(token); - return Long.parseLong(claims.get("memberId").toString()); + return Long.parseLong(claims.get("userId").toString()); } private Claims getBody(final String token) { From 46fcf07750e4802d0e60f596eef6e545b3a544b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 21:50:11 +0900 Subject: [PATCH 012/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20JWT=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=EC=97=90=EC=84=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20ID?= =?UTF-8?q?=20=EC=B6=94=EC=B6=9C=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - getUserId 메소드를 통해 JWT 토큰에서 사용자 ID를 추출하는 기능 구현. - jwtTokenProvider의 getUserFromJwt 메소드를 호출하여 사용자 ID를 반환. - 이 메소드는 사용자 인증이나 세션 관리 등에 사용될 수 있는 중요한 정보를 제공합니다. --- .../terning/terningserver/jwt/JwtAuthenticationFilter.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java b/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java index a420001..8756b8d 100644 --- a/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java @@ -43,4 +43,8 @@ private String getAuthorizationAccessToken(HttpServletRequest request) { private String getTokenFromBearerString(String token) { return token.replaceFirst(ValueConfig.BEARER_HEADER, ValueConfig.BLANK); } + + private long getUserId(String token) { + return jwtTokenProvider.getUserFromJwt(token); + } } From cd67fa2964eaab03a00acb503913b445029e942a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 21:52:44 +0900 Subject: [PATCH 013/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=20=EC=A0=95=EC=9D=98=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=ED=86=A0=ED=81=B0=20=ED=81=B4=EB=9E=98=EC=8A=A4=20UserAuthenti?= =?UTF-8?q?cation=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UsernamePasswordAuthenticationToken을 상속받아 UserAuthentication 클래스 정의. - 사용자의 신원과 권한을 처리하기 위해 principal, credentials, 및 authorities 파라미터를 받는 생성자 구현. - 이 클래스는 애플리케이션의 특정 인증 요구 사항을 충족하기 위해 사용자 정의 인증 메커니즘을 제공합니다. --- .../terningserver/jwt/UserAuthentication.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/jwt/UserAuthentication.java diff --git a/src/main/java/org/terning/terningserver/jwt/UserAuthentication.java b/src/main/java/org/terning/terningserver/jwt/UserAuthentication.java new file mode 100644 index 0000000..f2a1980 --- /dev/null +++ b/src/main/java/org/terning/terningserver/jwt/UserAuthentication.java @@ -0,0 +1,17 @@ +package org.terning.terningserver.jwt; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; + +import java.util.Collection; + +public class UserAuthentication extends UsernamePasswordAuthenticationToken { + + public UserAuthentication( + Object principal, + Object credentials, + Collection authorities + ) { + super(principal, credentials, authorities); + } +} From 5f8367cb7b7b1426da4e87797250e9818f2aab34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 21:55:22 +0900 Subject: [PATCH 014/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20JWT=20=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=20=EC=9D=B8=EC=A6=9D=20=ED=95=84=ED=84=B0=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - doFilterInternal 메소드에 JWT 토큰 추출 및 검증 로직 구현. - 유효한 JWT가 있는 경우, UserAuthentication 객체를 생성하고 SecurityContextHolder에 인증 정보 설정. - 인증 과정 중 발생할 수 있는 예외를 로깅. - 요청 처리 후 다음 필터 또는 서블릿으로 요청을 연속해서 처리하는 로직 추가. - 이 구현은 애플리케이션의 보안 강화에 기여하며, 사용자 인증을 효율적으로 처리합니다. --- .../jwt/JwtAuthenticationFilter.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java b/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java index 8756b8d..86a7594 100644 --- a/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java @@ -7,13 +7,17 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import org.terning.terningserver.config.ValueConfig; import java.io.IOException; +import static io.jsonwebtoken.lang.Strings.hasText; import static org.springframework.http.HttpHeaders.AUTHORIZATION; +import static org.terning.terningserver.jwt.JwtValidationType.VALID_JWT; @Slf4j @Component @@ -23,8 +27,20 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private static JwtTokenProvider jwtTokenProvider; @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + try { + val token = getAccessTokenFromRequest(request); + if (hasText(token) && jwtTokenProvider.validateToken(token) == VALID_JWT) { + val authentication = new UserAuthentication(getUserId(token), null, null); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } catch (Exception exception) { + log.error(exception.getMessage()); + } + filterChain.doFilter(request, response); } private String getAccessTokenFromRequest(HttpServletRequest request) { From 88ec082041592ff2364970f59e18b69b57be4bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 23:02:18 +0900 Subject: [PATCH 015/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20HTTP=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=EC=98=A4=EB=A5=98=20=EC=BD=94=EB=93=9C=20=EB=B0=8F?= =?UTF-8?q?=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - INVALID_TOKEN, INVALID_KEY 오류 코드 및 메시지 추가. - 401 상태 코드와 "유효하지 않은 토큰입니다.", "유효하지 않은 키입니다." 메시지를 정의. --- .../terning/terningserver/exception/enums/ErrorMessage.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index 77d8202..91a7df2 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -1,5 +1,7 @@ package org.terning.terningserver.exception.enums; + + import lombok.AllArgsConstructor; import lombok.Getter; @@ -8,7 +10,9 @@ public enum ErrorMessage { NOT_FOUND_INTERN_CATEGORY(404, "해당 인턴 공고는 존재하지 않습니다."), - WRONG_PERIOD(404, "해당 단어가 존재하지 않습니다."); + WRONG_PERIOD(404, "해당 단어가 존재하지 않습니다."), + INVALID_TOKEN(401, "유효하지 않은 토큰입니다."), + INVALID_KEY(401, "유효하지 않은 키입니다."); private final int status; private final String message; From ace5f0886b1b61809bf567d725533addabd4ef6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 23:03:23 +0900 Subject: [PATCH 016/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=EC=8B=A4=ED=8C=A8=20=EC=8B=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=A0=95=EC=9D=98=20=EC=9D=91=EB=8B=B5=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CustomJwtAuthenticationEntryPoint 클래스에 인증 실패 시 호출될 로직 구현. - 인증되지 않은 요청에 대해 JSON 형식의 401 Unauthorized 응답 반환. - 응답에는 INVALID_TOKEN 오류의 상태 코드와 메시지를 포함. - ObjectMapper를 사용하여 에러 메시지를 JSON 형식으로 변환. - 이 구현은 인증 실패 시 보다 명확하고 유용한 정보를 사용자에게 제공합니다. --- .../CustomJwtAuthenticationEntryPoint.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/jwt/CustomJwtAuthenticationEntryPoint.java diff --git a/src/main/java/org/terning/terningserver/jwt/CustomJwtAuthenticationEntryPoint.java b/src/main/java/org/terning/terningserver/jwt/CustomJwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..d19c1a4 --- /dev/null +++ b/src/main/java/org/terning/terningserver/jwt/CustomJwtAuthenticationEntryPoint.java @@ -0,0 +1,40 @@ +package org.terning.terningserver.jwt; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; +import org.terning.terningserver.exception.dto.ErrorResponse; + +import java.io.IOException; + +import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.terning.terningserver.exception.enums.ErrorMessage.INVALID_TOKEN; + +@Component +@RequiredArgsConstructor +public class CustomJwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + private final ObjectMapper objectMapper; + + @Override + public void commence( + HttpServletRequest request, + HttpServletResponse response, + AuthenticationException exception + ) throws IOException { + setResponse(response); + } + + private void setResponse(HttpServletResponse response) throws IOException { + response.setCharacterEncoding("UTF-8"); + response.setContentType(APPLICATION_JSON_VALUE); + response.setStatus(SC_UNAUTHORIZED); + response.getWriter().println(objectMapper.writeValueAsString(ErrorResponse.of(INVALID_TOKEN.getStatus(), INVALID_TOKEN.getMessage()))); + } +} From abbeecfc9419adaf4961f4ca0e6e6c8bf62feaad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 23:14:52 +0900 Subject: [PATCH 017/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20=EC=9B=B9=20?= =?UTF-8?q?=EB=B3=B4=EC=95=88=20=EC=84=A4=EC=A0=95=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20SecurityConfig=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CSRF 보호와 폼 로그인 기능을 비활성화하여 API 보안 강화. - STATELESS 세션 정책을 적용하여 토큰 기반 인증 시스템 구축. - CustomJwtAuthenticationEntryPoint를 사용하여 인증 실패 시 사용자 정의 응답 처리. - /api/v1/auth/** 및 /error 경로에 대한 접근 제한 없이 설정. - JwtAuthenticationFilter를 필터 체인에 추가하여 모든 요청에 대한 인증 절차 강화. --- .../terningserver/config/SecurityConfig.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/config/SecurityConfig.java diff --git a/src/main/java/org/terning/terningserver/config/SecurityConfig.java b/src/main/java/org/terning/terningserver/config/SecurityConfig.java new file mode 100644 index 0000000..2f2c751 --- /dev/null +++ b/src/main/java/org/terning/terningserver/config/SecurityConfig.java @@ -0,0 +1,44 @@ +package org.terning.terningserver.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.terning.terningserver.jwt.CustomJwtAuthenticationEntryPoint; +import org.terning.terningserver.jwt.JwtAuthenticationFilter; + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SecurityConfig { + + private final JwtAuthenticationFilter jwtAuthenticationFilter; + private final CustomJwtAuthenticationEntryPoint customJwtAuthenticationEntryPoint; + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + return http + .csrf(AbstractHttpConfigurer::disable) + .formLogin(AbstractHttpConfigurer::disable) + .sessionManagement(sessionManagement -> + sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS) + ) + .exceptionHandling(exceptionHandling -> + exceptionHandling.authenticationEntryPoint(customJwtAuthenticationEntryPoint)) + .authorizeHttpRequests(authorizeHttpRequests -> + authorizeHttpRequests + .requestMatchers(new AntPathRequestMatcher("/api/v1/auth/**")).permitAll() + .requestMatchers(new AntPathRequestMatcher("/error")).permitAll() + .anyRequest().authenticated()) + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) + .build(); + } + + +} From dee84f086eb8e9b8de249a5fa3c0ad95473e19b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 23:22:10 +0900 Subject: [PATCH 018/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20User=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EC=97=90=20=EB=A6=AC=ED=94=84=EB=A0=88?= =?UTF-8?q?=EC=8B=9C=20=ED=86=A0=ED=81=B0=20=EA=B4=80=EB=A6=AC=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - User 클래스 생성자에 @Builder 어노테이션 적용하여 객체 생성을 간소화. - 인증 유형과 ID를 초기화하는 생성자 구현. - 리프레시 토큰을 업데이트하고 초기화하는 메소드 추가. - updateRefreshToken 메소드를 통해 리프레시 토큰 값을 갱신. - resetRefreshToken 메소드를 통해 리프레시 토큰을 초기화. --- .../org/terning/terningserver/domain/User.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/org/terning/terningserver/domain/User.java b/src/main/java/org/terning/terningserver/domain/User.java index 11351a9..689e75e 100644 --- a/src/main/java/org/terning/terningserver/domain/User.java +++ b/src/main/java/org/terning/terningserver/domain/User.java @@ -2,6 +2,7 @@ import jakarta.persistence.*; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.terning.terningserver.domain.common.BaseTimeEntity; @@ -46,8 +47,24 @@ public class User extends BaseTimeEntity { @Column(nullable = false, length = 256) private String authId; // 인증 서비스에서 제공하는 고유 ID + private String refreshToken; // 리프레시 토큰 + @Enumerated(STRING) @Column(nullable = false) private State state; // 사용자 상태 (예: 활성, 비활성, 정지) + @Builder + public User(AuthType authType, String authId) { + this.authType = authType; + this.authId = authId; + } + + public void updateRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public void resetRefreshToken() { + this.refreshToken = null; + } + } From 48d6448bfcf20be8096e3284dc4ba254bae21882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 23:53:29 +0900 Subject: [PATCH 019/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20UserRepository?= =?UTF-8?q?=EC=97=90=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EA=B2=80=EC=83=89=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UserRepository 인터페이스에 findByAuthTypeAndAuthId 메소드 구현. - 특정 AuthType과 AuthId를 조합하여 사용자를 검색하는 쿼리 메소드 추가. - 반환 타입으로 Optional를 사용하여 결과가 없는 경우를 안전하게 처리. --- .../org/terning/terningserver/repository/Empty.txt | 0 .../terningserver/repository/UserRepository.java | 12 ++++++++++++ 2 files changed, 12 insertions(+) delete mode 100644 src/main/java/org/terning/terningserver/repository/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/repository/UserRepository.java diff --git a/src/main/java/org/terning/terningserver/repository/Empty.txt b/src/main/java/org/terning/terningserver/repository/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/repository/UserRepository.java b/src/main/java/org/terning/terningserver/repository/UserRepository.java new file mode 100644 index 0000000..6792fc0 --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/UserRepository.java @@ -0,0 +1,12 @@ +package org.terning.terningserver.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.domain.enums.AuthType; + +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + + Optional findByAuthTypeAndAuthId(AuthType authTypeType, String authId); +} From dd8e831492c6374a117751c203e6a2b387381688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 6 Jul 2024 23:57:19 +0900 Subject: [PATCH 020/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20SignInRequest=20?= =?UTF-8?q?=EB=A0=88=EC=BD=94=EB=93=9C=20=EC=A0=95=EC=9D=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용자 인증 요청을 처리하기 위해 SignInRequest 레코드 추가. - 인증 유형(AuthType)을 저장하는 불변 필드 정의. - @NonNull 어노테이션을 통해 authType 필드의 null 방지. - of 팩토리 메소드를 통해 타입 안전한 객체 생성 지원. --- .../exception/dto/auth/request/SignInRequest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/exception/dto/auth/request/SignInRequest.java diff --git a/src/main/java/org/terning/terningserver/exception/dto/auth/request/SignInRequest.java b/src/main/java/org/terning/terningserver/exception/dto/auth/request/SignInRequest.java new file mode 100644 index 0000000..e72b743 --- /dev/null +++ b/src/main/java/org/terning/terningserver/exception/dto/auth/request/SignInRequest.java @@ -0,0 +1,13 @@ +package org.terning.terningserver.exception.dto.auth.request; + +import lombok.NonNull; +import org.terning.terningserver.domain.enums.AuthType; + +public record SignInRequest( + @NonNull AuthType authType + ) { + + public static SignInRequest of(AuthType authType){ + return new SignInRequest(authType); + } +} From 949aa706493a5c869a311a067007750c097baafd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 00:02:50 +0900 Subject: [PATCH 021/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20Token=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80=EB=A1=9C=20?= =?UTF-8?q?=ED=86=A0=ED=81=B0=20=EA=B4=80=EB=A6=AC=20=EA=B0=95=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 액세스 토큰과 리프레시 토큰을 저장하기 위한 Token 클래스 추가. - 불변 필드로 accessToken과 refreshToken 정의. - Lombok의 @Getter와 @EqualsAndHashCode 어노테이션을 사용하여 보일러플레이트 코드 감소. - @Builder를 통한 객체 생성 메커니즘 구현으로 코드의 가독성 및 유연성 증가. --- .../terning/terningserver/domain/Token.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/domain/Token.java diff --git a/src/main/java/org/terning/terningserver/domain/Token.java b/src/main/java/org/terning/terningserver/domain/Token.java new file mode 100644 index 0000000..a51a6c1 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/Token.java @@ -0,0 +1,20 @@ +package org.terning.terningserver.domain; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +@Getter +@EqualsAndHashCode +public class Token { + + private final String accessToken; + private final String refreshToken; + + @Builder + public Token(String accessToken, String refreshToken) { + this.accessToken = accessToken; + this.refreshToken = refreshToken; + } + +} From 5b5dff14e51a2f3cbc31eadd0984618f16ea29e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 00:04:10 +0900 Subject: [PATCH 022/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20SignInResponse?= =?UTF-8?q?=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EC=A0=95=EC=9D=98=20=EB=B0=8F?= =?UTF-8?q?=20=EB=B9=8C=EB=8D=94=20=ED=8C=A8=ED=84=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 로그인 응답용 SignInResponse 레코드 추가, 액세스 토큰과 리프레시 토큰을 필드로 포함. - Lombok의 @Builder 어노테이션을 사용하여 클래스 내부에서만 인스턴스 생성을 제한하는 빌더 패턴 구현. - of 정적 팩토리 메소드를 통해 Token 객체에서 토큰 정보를 추출하고 SignInResponse 인스턴스 생성 지원. --- .../dto/auth/response/SignInResponse.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/exception/dto/auth/response/SignInResponse.java diff --git a/src/main/java/org/terning/terningserver/exception/dto/auth/response/SignInResponse.java b/src/main/java/org/terning/terningserver/exception/dto/auth/response/SignInResponse.java new file mode 100644 index 0000000..bf2b9a4 --- /dev/null +++ b/src/main/java/org/terning/terningserver/exception/dto/auth/response/SignInResponse.java @@ -0,0 +1,19 @@ +package org.terning.terningserver.exception.dto.auth.response; + +import lombok.Builder; +import org.terning.terningserver.domain.Token; + +import static lombok.AccessLevel.PRIVATE; + +@Builder(access = PRIVATE) +public record SignInResponse( + String accessToken, + String refreshToken +) { + public static SignInResponse of(Token token) { + return SignInResponse.builder() + .accessToken(token.getAccessToken()) + .refreshToken(token.getRefreshToken()) + .build(); + } +} From dc360d4bd8241362f8432b0d498c53e1a2d70a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 13:42:19 +0900 Subject: [PATCH 023/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20TokenGetRequest?= =?UTF-8?q?=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EC=A0=95=EC=9D=98=20=EB=B0=8F?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 리프레시 토큰 저장용 TokenGetRequest 레코드 추가. - @NonNull 어노테이션을 활용해 refreshToken 필드의 null 방지. - PRIVATE 접근 레벨의 @Builder로 클래스 내부에서만 인스턴스 생성 가능. - of 정적 팩토리 메소드 구현으로 안전하게 객체 생성 지원. --- .../dto/auth/request/TokenGetRequest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/exception/dto/auth/request/TokenGetRequest.java diff --git a/src/main/java/org/terning/terningserver/exception/dto/auth/request/TokenGetRequest.java b/src/main/java/org/terning/terningserver/exception/dto/auth/request/TokenGetRequest.java new file mode 100644 index 0000000..d7e297b --- /dev/null +++ b/src/main/java/org/terning/terningserver/exception/dto/auth/request/TokenGetRequest.java @@ -0,0 +1,18 @@ +package org.terning.terningserver.exception.dto.auth.request; + +import lombok.Builder; +import lombok.NonNull; + +import static lombok.AccessLevel.*; + +@Builder(access = PRIVATE) +public record TokenGetRequest( + @NonNull String refreshToken +) { + + public static TokenGetRequest of(String refreshToken) { + return TokenGetRequest.builder() + .refreshToken(refreshToken) + .build(); + } +} From a8e6396239382f7d389a1fb0bf751646e6c5dd28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 13:44:33 +0900 Subject: [PATCH 024/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20TokenGetResponse?= =?UTF-8?q?=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EC=A0=95=EC=9D=98=20=EB=B0=8F?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 액세스 토큰 응답용 TokenGetResponse 레코드 추가. - @NonNull 어노테이션을 활용해 accessToken 필드의 null 방지. - PRIVATE 접근 레벨의 @Builder로 클래스 내부에서만 인스턴스 생성 가능. - of 정적 팩토리 메소드 구현으로 안전하게 객체 생성 지원. --- .../dto/auth/response/TokenGetResponse.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/exception/dto/auth/response/TokenGetResponse.java diff --git a/src/main/java/org/terning/terningserver/exception/dto/auth/response/TokenGetResponse.java b/src/main/java/org/terning/terningserver/exception/dto/auth/response/TokenGetResponse.java new file mode 100644 index 0000000..71fad26 --- /dev/null +++ b/src/main/java/org/terning/terningserver/exception/dto/auth/response/TokenGetResponse.java @@ -0,0 +1,17 @@ +package org.terning.terningserver.exception.dto.auth.response; + +import lombok.Builder; +import lombok.NonNull; + +import static lombok.AccessLevel.*; + +@Builder(access = PRIVATE) +public record TokenGetResponse(@NonNull String accessToken +) { + + public static TokenGetResponse of(String accessToken) { + return TokenGetResponse.builder() + .accessToken(accessToken) + .build(); + } +} From fb02fc8aeb8f2f4e57a9da8b289fe11d50b88376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 13:45:43 +0900 Subject: [PATCH 025/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20AuthService=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98=20=EB=B0=8F=20=EC=9D=B8=EC=A6=9D=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용자 인증 관련 주요 서비스를 제공하는 AuthService 인터페이스 추가. - signIn, signOut, withdraw 및 reissueToken 메소드를 통해 로그인, 로그아웃, 회원 탈퇴, 토큰 재발급 기능을 선언. - 각 메소드는 사용자 인증 및 세션 관리를 위해 필수적인 작업을 수행하며 API의 안정성을 보장합니다. --- .../terningserver/service/AuthService.java | 17 +++++++++++++++++ .../org/terning/terningserver/service/Empty.txt | 0 2 files changed, 17 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/service/AuthService.java delete mode 100644 src/main/java/org/terning/terningserver/service/Empty.txt diff --git a/src/main/java/org/terning/terningserver/service/AuthService.java b/src/main/java/org/terning/terningserver/service/AuthService.java new file mode 100644 index 0000000..07b337c --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/AuthService.java @@ -0,0 +1,17 @@ +package org.terning.terningserver.service; + +import org.terning.terningserver.exception.dto.auth.request.SignInRequest; +import org.terning.terningserver.exception.dto.auth.request.TokenGetRequest; +import org.terning.terningserver.exception.dto.auth.response.SignInResponse; +import org.terning.terningserver.exception.dto.auth.response.TokenGetResponse; + +public interface AuthService { + + SignInResponse signIn(SignInRequest request); + + void signOut(long memberId); + + void withdraw(long memberId); + + TokenGetResponse reissueToken(TokenGetRequest request); +} diff --git a/src/main/java/org/terning/terningserver/service/Empty.txt b/src/main/java/org/terning/terningserver/service/Empty.txt deleted file mode 100644 index e69de29..0000000 From 69a8acd823c13b707ad98eee3386b99ecd2e1be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 15:03:35 +0900 Subject: [PATCH 026/205] =?UTF-8?q?[=F0=9F=93=82=C2=A0file/#17]:=20auth=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20DTO=EC=99=80=20=EC=9A=94=EC=B2=AD/?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{exception/dto => domain}/auth/request/SignInRequest.java | 2 +- .../{exception/dto => domain}/auth/request/TokenGetRequest.java | 2 +- .../{exception/dto => domain}/auth/response/SignInResponse.java | 2 +- .../dto => domain}/auth/response/TokenGetResponse.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/main/java/org/terning/terningserver/{exception/dto => domain}/auth/request/SignInRequest.java (81%) rename src/main/java/org/terning/terningserver/{exception/dto => domain}/auth/request/TokenGetRequest.java (85%) rename src/main/java/org/terning/terningserver/{exception/dto => domain}/auth/response/SignInResponse.java (88%) rename src/main/java/org/terning/terningserver/{exception/dto => domain}/auth/response/TokenGetResponse.java (84%) diff --git a/src/main/java/org/terning/terningserver/exception/dto/auth/request/SignInRequest.java b/src/main/java/org/terning/terningserver/domain/auth/request/SignInRequest.java similarity index 81% rename from src/main/java/org/terning/terningserver/exception/dto/auth/request/SignInRequest.java rename to src/main/java/org/terning/terningserver/domain/auth/request/SignInRequest.java index e72b743..f0545c2 100644 --- a/src/main/java/org/terning/terningserver/exception/dto/auth/request/SignInRequest.java +++ b/src/main/java/org/terning/terningserver/domain/auth/request/SignInRequest.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.exception.dto.auth.request; +package org.terning.terningserver.domain.auth.request; import lombok.NonNull; import org.terning.terningserver.domain.enums.AuthType; diff --git a/src/main/java/org/terning/terningserver/exception/dto/auth/request/TokenGetRequest.java b/src/main/java/org/terning/terningserver/domain/auth/request/TokenGetRequest.java similarity index 85% rename from src/main/java/org/terning/terningserver/exception/dto/auth/request/TokenGetRequest.java rename to src/main/java/org/terning/terningserver/domain/auth/request/TokenGetRequest.java index d7e297b..1384e55 100644 --- a/src/main/java/org/terning/terningserver/exception/dto/auth/request/TokenGetRequest.java +++ b/src/main/java/org/terning/terningserver/domain/auth/request/TokenGetRequest.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.exception.dto.auth.request; +package org.terning.terningserver.domain.auth.request; import lombok.Builder; import lombok.NonNull; diff --git a/src/main/java/org/terning/terningserver/exception/dto/auth/response/SignInResponse.java b/src/main/java/org/terning/terningserver/domain/auth/response/SignInResponse.java similarity index 88% rename from src/main/java/org/terning/terningserver/exception/dto/auth/response/SignInResponse.java rename to src/main/java/org/terning/terningserver/domain/auth/response/SignInResponse.java index bf2b9a4..252e9a0 100644 --- a/src/main/java/org/terning/terningserver/exception/dto/auth/response/SignInResponse.java +++ b/src/main/java/org/terning/terningserver/domain/auth/response/SignInResponse.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.exception.dto.auth.response; +package org.terning.terningserver.domain.auth.response; import lombok.Builder; import org.terning.terningserver.domain.Token; diff --git a/src/main/java/org/terning/terningserver/exception/dto/auth/response/TokenGetResponse.java b/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetResponse.java similarity index 84% rename from src/main/java/org/terning/terningserver/exception/dto/auth/response/TokenGetResponse.java rename to src/main/java/org/terning/terningserver/domain/auth/response/TokenGetResponse.java index 71fad26..e081a39 100644 --- a/src/main/java/org/terning/terningserver/exception/dto/auth/response/TokenGetResponse.java +++ b/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetResponse.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.exception.dto.auth.response; +package org.terning.terningserver.domain.auth.response; import lombok.Builder; import lombok.NonNull; From 0ee5497448347c11f6e6abd083e5f4748ecee6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 15:06:37 +0900 Subject: [PATCH 027/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20SignInServiceReq?= =?UTF-8?q?uest=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EB=B0=8F=20=EB=B9=8C=EB=8D=94=20=ED=8C=A8=ED=84=B4=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 인증 서비스 요청을 위한 SignInServiceRequest 레코드 추가. - authAccessToken 및 authType 필드를 포함하여 인증 요청에 필요한 정보 저장. - @NonNull 어노테이션을 사용하여 필수 필드의 null 방지. - PRIVATE 접근 레벨의 @Builder로 클래스 내부에서만 객체 생성 가능. - of 정적 팩토리 메소드 구현으로 안전한 객체 생성 지원. --- .../auth/request/SignInServiceRequest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/domain/auth/request/SignInServiceRequest.java diff --git a/src/main/java/org/terning/terningserver/domain/auth/request/SignInServiceRequest.java b/src/main/java/org/terning/terningserver/domain/auth/request/SignInServiceRequest.java new file mode 100644 index 0000000..e964d79 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/auth/request/SignInServiceRequest.java @@ -0,0 +1,21 @@ +package org.terning.terningserver.domain.auth.request; + +import lombok.Builder; +import lombok.NonNull; +import org.terning.terningserver.domain.enums.AuthType; + +import static lombok.AccessLevel.*; + +@Builder(access = PRIVATE) +public record SignInServiceRequest( + @NonNull String authAccessToken, + @NonNull AuthType authType +) { + + public static SignInServiceRequest of(String authAccessToken, SignInRequest request) { + return SignInServiceRequest.builder() + .authAccessToken(authAccessToken) + .authType(request.authType()) + .build(); + } +} From 81274d07cf9562b3a8718e0f29905d5d9dd1c18f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 15:10:53 +0900 Subject: [PATCH 028/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20SignInServiceRes?= =?UTF-8?q?ponse=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EC=A0=95=EC=9D=98=20?= =?UTF-8?q?=EB=B0=8F=20=EB=B9=8C=EB=8D=94=20=ED=8C=A8=ED=84=B4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 인증 서비스 응답용 SignInServiceResponse 레코드 추가. - @NonNull 어노테이션을 사용해 accessToken과 refreshToken 필드의 null 방지. - PRIVATE 접근 레벨의 @Builder로 내부에서만 객체 생성 가능. - of 정적 팩토리 메소드를 통해 Token 객체로부터 토큰 정보 추출 및 객체 생성 지원. --- .../auth/response/SignInServiceResponse.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/domain/auth/response/SignInServiceResponse.java diff --git a/src/main/java/org/terning/terningserver/domain/auth/response/SignInServiceResponse.java b/src/main/java/org/terning/terningserver/domain/auth/response/SignInServiceResponse.java new file mode 100644 index 0000000..0476c57 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/auth/response/SignInServiceResponse.java @@ -0,0 +1,21 @@ +package org.terning.terningserver.domain.auth.response; + +import lombok.Builder; +import lombok.NonNull; +import org.terning.terningserver.domain.Token; + +import static lombok.AccessLevel.PRIVATE; + +@Builder(access = PRIVATE) +public record SignInServiceResponse( + @NonNull String accessToken, + @NonNull String refreshToken +) { + + public static SignInServiceResponse of(Token token) { + return SignInServiceResponse.builder() + .accessToken(token.getAccessToken()) + .refreshToken(token.getRefreshToken()) + .build(); + } +} From 890da2487a17215b8af9732da7085de5ff660437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 15:13:37 +0900 Subject: [PATCH 029/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8F=C2=A0refactor/#17]:?= =?UTF-8?q?=20AuthService=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4?= =?UTF-8?q?=EC=97=90=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=ED=8A=B9=ED=99=94=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=A9=94=EC=86=8C=EB=93=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/service/AuthService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/AuthService.java b/src/main/java/org/terning/terningserver/service/AuthService.java index 07b337c..b90214a 100644 --- a/src/main/java/org/terning/terningserver/service/AuthService.java +++ b/src/main/java/org/terning/terningserver/service/AuthService.java @@ -1,13 +1,13 @@ package org.terning.terningserver.service; -import org.terning.terningserver.exception.dto.auth.request.SignInRequest; -import org.terning.terningserver.exception.dto.auth.request.TokenGetRequest; -import org.terning.terningserver.exception.dto.auth.response.SignInResponse; -import org.terning.terningserver.exception.dto.auth.response.TokenGetResponse; +import org.terning.terningserver.domain.auth.request.SignInServiceRequest; +import org.terning.terningserver.domain.auth.request.TokenGetRequest; +import org.terning.terningserver.domain.auth.response.SignInServiceResponse; +import org.terning.terningserver.domain.auth.response.TokenGetResponse; public interface AuthService { - SignInResponse signIn(SignInRequest request); + SignInServiceResponse signIn(SignInServiceRequest request); void signOut(long memberId); From 91d314759eec1b9b7e29842694e8499b27d114d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 15:15:26 +0900 Subject: [PATCH 030/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=20=EC=A0=95=EC=9D=98=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?UserException=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RuntimeException을 상속받는 UserException 클래스를 정의. - ErrorMessage 열거형을 활용하여 예외 상황별 메시지 관리 가능. - 생성자에서 ErrorMessage 객체를 받아 예외 메시지를 초기화하며, 예외 발생 시 상세 정보 제공. - @Getter 어노테이션을 통해 errorMessage 필드의 접근자 메소드 자동 생성. --- .../terningserver/exception/UserException.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/exception/UserException.java diff --git a/src/main/java/org/terning/terningserver/exception/UserException.java b/src/main/java/org/terning/terningserver/exception/UserException.java new file mode 100644 index 0000000..9abca99 --- /dev/null +++ b/src/main/java/org/terning/terningserver/exception/UserException.java @@ -0,0 +1,15 @@ +package org.terning.terningserver.exception; + +import lombok.Getter; +import org.terning.terningserver.exception.enums.ErrorMessage; + +@Getter +public class UserException extends RuntimeException { + + private final ErrorMessage errorMessage; + + public UserException(ErrorMessage errorMessage) { + super("[UserException] : " + errorMessage.getMessage()); + this.errorMessage = errorMessage; + } +} From 6b286a7698f0cd3e42281f84c2b6dedbde6cd591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 15:22:33 +0900 Subject: [PATCH 031/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8F=20refactor/#17]:=20?= =?UTF-8?q?AuthService=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=ED=99=95=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/service/AuthService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/AuthService.java b/src/main/java/org/terning/terningserver/service/AuthService.java index b90214a..6889cdb 100644 --- a/src/main/java/org/terning/terningserver/service/AuthService.java +++ b/src/main/java/org/terning/terningserver/service/AuthService.java @@ -1,17 +1,17 @@ package org.terning.terningserver.service; import org.terning.terningserver.domain.auth.request.SignInServiceRequest; -import org.terning.terningserver.domain.auth.request.TokenGetRequest; +import org.terning.terningserver.domain.auth.request.TokenGetServiceRequest; import org.terning.terningserver.domain.auth.response.SignInServiceResponse; -import org.terning.terningserver.domain.auth.response.TokenGetResponse; +import org.terning.terningserver.domain.auth.response.TokenGetServiceResponse; public interface AuthService { SignInServiceResponse signIn(SignInServiceRequest request); - void signOut(long memberId); + void signOut(long userId); - void withdraw(long memberId); + void withdraw(long userId); - TokenGetResponse reissueToken(TokenGetRequest request); + TokenGetServiceResponse reissueToken(TokenGetServiceRequest request); } From e9bd2999bef867109e2a6acbee8cb363b32c4d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 15:24:09 +0900 Subject: [PATCH 032/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20TokenGetServiceR?= =?UTF-8?q?equest=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EC=A0=95=EC=9D=98=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 토큰 재발급 요청을 위한 TokenGetServiceRequest 레코드 추가. - PRIVATE 접근 레벨의 @Builder를 사용하여 클래스 내부에서만 인스턴스 생성 가능. - @NonNull 어노테이션을 통해 refreshToken 필드가 null이 아님을 보장. - of 정적 팩토리 메소드를 구현하여 안전하게 객체 생성 지원. --- .../auth/request/TokenGetServiceRequest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/domain/auth/request/TokenGetServiceRequest.java diff --git a/src/main/java/org/terning/terningserver/domain/auth/request/TokenGetServiceRequest.java b/src/main/java/org/terning/terningserver/domain/auth/request/TokenGetServiceRequest.java new file mode 100644 index 0000000..5e2c127 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/auth/request/TokenGetServiceRequest.java @@ -0,0 +1,18 @@ +package org.terning.terningserver.domain.auth.request; + +import lombok.Builder; +import lombok.NonNull; + +import static lombok.AccessLevel.*; + +@Builder(access = PRIVATE) +public record TokenGetServiceRequest( + @NonNull String refreshToken +) { + + public static TokenGetServiceRequest of(String refreshToken) { + return TokenGetServiceRequest.builder() + .refreshToken(refreshToken) + .build(); + } +} From bc87a5a4097118acb8e43b79bb6923548d457ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 15:24:58 +0900 Subject: [PATCH 033/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20TokenGetServiceR?= =?UTF-8?q?esponse=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EB=B0=8F=20=EC=83=9D=EC=84=B1=EC=9E=90=20=ED=8C=A8=ED=84=B4=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 토큰 서비스 응답을 위한 TokenGetServiceResponse 레코드 추가. - PRIVATE 접근 레벨의 @Builder를 사용하여 클래스 내부에서만 인스턴스 생성 가능. - @NonNull 어노테이션을 통해 accessToken 필드가 null이 아님을 보장. - of 정적 팩토리 메소드를 구현하여 안전하게 객체 생성 지원. --- .../auth/response/TokenGetServiceResponse.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/domain/auth/response/TokenGetServiceResponse.java diff --git a/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetServiceResponse.java b/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetServiceResponse.java new file mode 100644 index 0000000..6de0e9d --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetServiceResponse.java @@ -0,0 +1,18 @@ +package org.terning.terningserver.domain.auth.response; + +import lombok.Builder; +import lombok.NonNull; + +import static lombok.AccessLevel.*; + +@Builder(access = PRIVATE) +public record TokenGetServiceResponse( + @NonNull String accessToken +) { + + public static TokenGetServiceResponse of(String accessToken) { + return TokenGetServiceResponse.builder() + .accessToken(accessToken) + .build(); + } +} From a3bb123d401ec3e31c01d83a438eb52d11446c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 15:59:58 +0900 Subject: [PATCH 034/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20AuthService=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EC=9D=84=20=ED=86=B5=ED=95=9C=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=20=EC=9D=B8=EC=A6=9D=20=EB=B0=8F=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=ED=99=95=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AuthServiceImpl 클래스에서 signIn, signOut, withdraw, reissueToken 등의 메소드 구현. - 사용자 인증, 로그아웃, 회원 탈퇴, 토큰 재발급 기능을 통합적으로 제공. - 각 인증 유형에 따른 사용자 데이터 처리 로직을 포함. - JwtTokenProvider를 활용한 토큰 생성 및 관리 메커니즘 구현. --- .../service/AuthServiceImpl.java | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/service/AuthServiceImpl.java diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java new file mode 100644 index 0000000..5ee0b73 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -0,0 +1,121 @@ +package org.terning.terningserver.service; + +import lombok.val; +import org.springframework.security.core.Authentication; +import org.springframework.transaction.annotation.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.terning.terningserver.config.ValueConfig; +import org.terning.terningserver.domain.Token; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.domain.auth.request.SignInServiceRequest; +import org.terning.terningserver.domain.auth.request.TokenGetServiceRequest; +import org.terning.terningserver.domain.auth.response.SignInServiceResponse; +import org.terning.terningserver.domain.auth.response.TokenGetServiceResponse; +import org.terning.terningserver.domain.enums.AuthType; +import org.terning.terningserver.exception.UserException; +import org.terning.terningserver.jwt.JwtTokenProvider; +import org.terning.terningserver.jwt.UserAuthentication; +import org.terning.terningserver.repository.UserRepository; + +import static org.terning.terningserver.exception.enums.ErrorMessage.INVALID_USER; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class AuthServiceImpl implements AuthService { + + private final JwtTokenProvider jwtTokenProvider; + private final UserRepository userRepository; + private final KakaoService kakaoService; + private final AppleService appleService; + private final UserService userService; + private final ValueConfig valueConfig; + + @Override + @Transactional + public SignInServiceResponse signIn(SignInServiceRequest request) { + val user = getUser(request.authAccessToken(), request.authType()); + val token = getToken(user); + return SignInServiceResponse.of(token); + } + + @Override + @Transactional + public void signOut(long userId) { + val user = findUser(userId); + user.resetRefreshToken(); + } + + @Override + @Transactional + public void withdraw(long userId) { + val user = findUser(userId); + deleteUser(user); + } + + @Override + public TokenGetServiceResponse reissueToken(TokenGetServiceRequest request) { + val user = findUser(request.refreshToken()); + val token = generateAccessToken(user.getId()); + return TokenGetServiceResponse.of(token); + } + + private User getUser(String authAccessToken, AuthType authType) { + val authId = getAuthId(authAccessToken, authType); + return signUp(authType, authId); + } + + private String getAuthId(String authAccessToken, AuthType authType) { + return switch (authType) { + case APPLE -> appleService.getAppleData(authAccessToken); + case KAKAO -> kakaoService.getKakaoData(authAccessToken); + }; + } + + private User signUp(AuthType authType, String authId) { + return userRepository.findByAuthTypeAndAuthId(authType, authId) + .orElseGet(() -> saveUser(authType, authId)); + } + + private User saveUser(AuthType authType, String authId) { + val user = User.builder().authType(authType).authId(authId).build(); + return userRepository.save(user); + } + + private Token getToken(User user) { + val token = generateToken(new UserAuthentication(user.getId(), null, null)); + user.updateRefreshToken(token.getRefreshToken()); + return token; + } + + private Token generateToken(Authentication authentication) { + return Token.builder() + .accessToken(jwtTokenProvider.generateToken(authentication, valueConfig.getAccessTokenExpired())) + .refreshToken(jwtTokenProvider.generateToken(authentication, valueConfig.getRefreshTokenExpired())) + .build(); + } + + private User findUser(long id) { + return userRepository.findById(id).orElseThrow(() -> new UserException(INVALID_USER)); + } + + private User findUser(String refreshToken) { + return userRepository.findByRefreshToken(getTokenFromBearerString(refreshToken)) + .orElseThrow(() -> new UserException(INVALID_USER)); + } + + private String getTokenFromBearerString(String token) { + return token.replaceFirst(ValueConfig.BEARER_HEADER, ValueConfig.BLANK); + } + + private String generateAccessToken(long userId) { + val authentication = new UserAuthentication(userId, null, null); + return jwtTokenProvider.generateToken(authentication, valueConfig.getAccessTokenExpired()); + } + + private void deleteUser(User user) { + userService.deleteUser(user); + } + +} From 0398cd71d2484844bbb4e4a16bb080035acc15ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 16:03:05 +0900 Subject: [PATCH 035/205] =?UTF-8?q?[=E2=9C=85=C2=A0chore/#17]:=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=95=EB=A0=AC=EC=9D=84=20=ED=86=B5=ED=95=9C=20?= =?UTF-8?q?=EA=B0=80=EC=8B=9C=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terning/terningserver/exception/enums/ErrorMessage.java | 6 +++--- .../terning/terningserver/repository/UserRepository.java | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index 91a7df2..a9cd7b5 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -9,10 +9,10 @@ @AllArgsConstructor public enum ErrorMessage { - NOT_FOUND_INTERN_CATEGORY(404, "해당 인턴 공고는 존재하지 않습니다."), - WRONG_PERIOD(404, "해당 단어가 존재하지 않습니다."), INVALID_TOKEN(401, "유효하지 않은 토큰입니다."), - INVALID_KEY(401, "유효하지 않은 키입니다."); + INVALID_KEY(401, "유효하지 않은 키입니다."), + + INVALID_USER(404, "유효하지 않은 유저입니다."); private final int status; private final String message; diff --git a/src/main/java/org/terning/terningserver/repository/UserRepository.java b/src/main/java/org/terning/terningserver/repository/UserRepository.java index 6792fc0..c8e3d23 100644 --- a/src/main/java/org/terning/terningserver/repository/UserRepository.java +++ b/src/main/java/org/terning/terningserver/repository/UserRepository.java @@ -9,4 +9,6 @@ public interface UserRepository extends JpaRepository { Optional findByAuthTypeAndAuthId(AuthType authTypeType, String authId); + + Optional findByRefreshToken(String refreshToken); } From 979cefdc95016d82c6a6e313a115c30160e32f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 16:07:46 +0900 Subject: [PATCH 036/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20UserServiceImpl?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=EC=97=90=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UserService 인터페이스를 구현하는 UserServiceImpl 클래스에 deleteUser 메소드 추가. - UserRepository를 사용하여 전달된 User 객체를 데이터베이스에서 삭제. - 메소드 실행 시 트랜잭션 관리를 위해 @Transactional 어노테이션 적용. --- .../service/UserServiceImpl.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/service/UserServiceImpl.java diff --git a/src/main/java/org/terning/terningserver/service/UserServiceImpl.java b/src/main/java/org/terning/terningserver/service/UserServiceImpl.java new file mode 100644 index 0000000..d32a2ba --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/UserServiceImpl.java @@ -0,0 +1,21 @@ +package org.terning.terningserver.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.repository.UserRepository; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UserServiceImpl implements UserService { + + private final UserRepository userRepository; + + @Override + public void deleteUser(User user) { + userRepository.delete(user); + } + +} From 23ebd46cde0f7a8e5bdd7b00817a47ad5415b948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 7 Jul 2024 16:08:30 +0900 Subject: [PATCH 037/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20UserService=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=EC=97=90=20delete?= =?UTF-8?q?User=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UserService 인터페이스를 새롭게 정의하고, 이를 통해 사용자 삭제 기능의 추상화를 제공. - deleteUser 메소드는 User 객체를 매개변수로 받아, 구현 클래스에서 해당 사용자를 삭제하도록 요구. --- .../org/terning/terningserver/service/UserService.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/service/UserService.java diff --git a/src/main/java/org/terning/terningserver/service/UserService.java b/src/main/java/org/terning/terningserver/service/UserService.java new file mode 100644 index 0000000..de3eca2 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/UserService.java @@ -0,0 +1,8 @@ +package org.terning.terningserver.service; + +import org.terning.terningserver.domain.User; + +public interface UserService { + + void deleteUser(User user); +} From fa37dacd9f0a748f8ab00a275c5cd481efbfa22d Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 8 Jul 2024 05:27:55 +0900 Subject: [PATCH 038/205] =?UTF-8?q?[=E2=9C=85chore/#18]=20.gitignore=20?= =?UTF-8?q?=EC=88=98=EC=A0=95(QueryDSL)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index a50b7a1..4f5aa4a 100644 --- a/.gitignore +++ b/.gitignore @@ -190,3 +190,6 @@ Temporary Items # application.yml src/main/resources/application.yml src/main/resources/application-dev.yml + +# Q-Class +src/main/generated From 2eccb9957562f941c640ca8aab4b2e71481aac90 Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 8 Jul 2024 05:28:51 +0900 Subject: [PATCH 039/205] =?UTF-8?q?[=E2=9C=85chore/#18]=20build.gradle=20?= =?UTF-8?q?=EC=88=98=EC=A0=95(QueryDSL)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 44 ++++++++++++++++--- .../terningserver/dto/user/response/Empty.txt | 0 .../terningserver/repository/Empty.txt | 0 3 files changed, 38 insertions(+), 6 deletions(-) delete mode 100644 src/main/java/org/terning/terningserver/dto/user/response/Empty.txt delete mode 100644 src/main/java/org/terning/terningserver/repository/Empty.txt diff --git a/build.gradle b/build.gradle index f77d87d..3adb068 100644 --- a/build.gradle +++ b/build.gradle @@ -13,16 +13,14 @@ java { } } -configurations { - compileOnly { - extendsFrom annotationProcessor - } -} - repositories { mavenCentral() } +ext { + set('queryDslVersion', "5.0.0") +} + dependencies { //default @@ -41,8 +39,42 @@ dependencies { //Health-check implementation 'org.springframework.boot:spring-boot-starter-actuator' + + //QueryDSL + implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta" + annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" +} + +//QueryDSL 초기 설정 +//1. Q-Class를 생성할 디렉토리 경로를 설정합니다. +def queryDslSrcDir = 'src/main/generated/querydsl/' + +//2. JavaCompile Task를 수행하는 경우 생성될 소스코드의 출력 디렉토리를 queryDslSrcDir로 설정합니다. +tasks.withType(JavaCompile).configureEach { + options.getGeneratedSourceOutputDirectory().set(file(queryDslSrcDir)) +} + +//3. 소스 코드로 인식할 디렉토리 경로에 Q-Class 파일을 추가합니다. 이렇게 하면 Q-Class가 일반 Java 클래스처럼 취급되어 컴파일과 실행 시 classPath에 포함됩니다. +sourceSets { + main.java.srcDirs += [queryDslSrcDir] +} + +//4. clean Task를 수행하는 경우 지정한 디렉토리를 삭제하도록 설정합니다. -> 자동 생성된 Q-Class를 제거합니다. +clean { + delete file(queryDslSrcDir) +} + +//5. QueryDSL과 관련된 라이브러리들이 컴파일 시점에만 필요하도록 설정합니다. 또한, QueryDSL 설정을 컴파일 클래스 패스에 추가합니다. +configurations { + compileOnly { + extendsFrom annotationProcessor + } + querydsl.extendsFrom compileClasspath } tasks.named('test') { useJUnitPlatform() } + diff --git a/src/main/java/org/terning/terningserver/dto/user/response/Empty.txt b/src/main/java/org/terning/terningserver/dto/user/response/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/repository/Empty.txt b/src/main/java/org/terning/terningserver/repository/Empty.txt deleted file mode 100644 index e69de29..0000000 From 4c024d93cb709937937abef529febbb8253972f1 Mon Sep 17 00:00:00 2001 From: Willy Date: Tue, 9 Jul 2024 14:58:15 +0900 Subject: [PATCH 040/205] =?UTF-8?q?[=E2=9C=85chore/#18]=20QueryDSL=20?= =?UTF-8?q?=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +++ .../terningserver/config/QuerydslConfig.java | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/config/QuerydslConfig.java diff --git a/build.gradle b/build.gradle index 3adb068..19aa4de 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,9 @@ dependencies { annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" + + //validation + implementation 'ort.springframework.boot:spring-boot-starter-validation' } //QueryDSL 초기 설정 diff --git a/src/main/java/org/terning/terningserver/config/QuerydslConfig.java b/src/main/java/org/terning/terningserver/config/QuerydslConfig.java new file mode 100644 index 0000000..8ffa1dc --- /dev/null +++ b/src/main/java/org/terning/terningserver/config/QuerydslConfig.java @@ -0,0 +1,19 @@ +package org.terning.terningserver.config; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class QuerydslConfig { + + @PersistenceContext + private EntityManager entityManager; + + @Bean + public JPAQueryFactory jpaQueryFactory(){ + return new JPAQueryFactory(entityManager); + } +} From 84aa224babc4a88cfb33f7e0cb07427c1dff5061 Mon Sep 17 00:00:00 2001 From: Willy Date: Tue, 9 Jul 2024 15:01:23 +0900 Subject: [PATCH 041/205] =?UTF-8?q?[=E2=9C=85chore/#18]=20QueryDSL=20?= =?UTF-8?q?=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/terning/terningserver/controller/api/Empty.txt | 0 .../java/org/terning/terningserver/dto/user/response/Empty.txt | 0 src/main/java/org/terning/terningserver/repository/Empty.txt | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/controller/api/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/dto/user/response/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/repository/Empty.txt diff --git a/src/main/java/org/terning/terningserver/controller/api/Empty.txt b/src/main/java/org/terning/terningserver/controller/api/Empty.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/org/terning/terningserver/dto/user/response/Empty.txt b/src/main/java/org/terning/terningserver/dto/user/response/Empty.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/org/terning/terningserver/repository/Empty.txt b/src/main/java/org/terning/terningserver/repository/Empty.txt new file mode 100644 index 0000000..e69de29 From b20bd3ed725117043b626e63e1d7aa9e0f0ae24c Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Tue, 9 Jul 2024 17:45:20 +0900 Subject: [PATCH 042/205] =?UTF-8?q?[=E2=9C=85chore/#20]:=20=EB=AA=A8?= =?UTF-8?q?=EB=93=A0=20enum=20=ED=83=80=EC=9E=85=20key=20=EA=B0=92=200?= =?UTF-8?q?=EB=B6=80=ED=84=B0=20=EC=8B=9C=EC=9E=91=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/domain/enums/Grade.java | 8 ++++---- .../terning/terningserver/domain/enums/WorkingPeriod.java | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/terning/terningserver/domain/enums/Grade.java b/src/main/java/org/terning/terningserver/domain/enums/Grade.java index 3fe639a..cd111ab 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/Grade.java +++ b/src/main/java/org/terning/terningserver/domain/enums/Grade.java @@ -5,10 +5,10 @@ @RequiredArgsConstructor public enum Grade { - FRESHMAN(1, "1학년"), - SOPHOMORE(2, "2학년"), - JUNIOR(3, "3학년"), - SENIOR(4, "4학년"); + FRESHMAN(0, "1학년"), + SOPHOMORE(1, "2학년"), + JUNIOR(2, "3학년"), + SENIOR(3, "4학년"); private final int key; private final String value; diff --git a/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java b/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java index d6c4c17..48e9e21 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java +++ b/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java @@ -5,9 +5,9 @@ @RequiredArgsConstructor public enum WorkingPeriod { - OPTION1(1, "1개월 ~ 3개월"), - OPTION2(2, "4개월 ~ 6개월"), - OPTION3(3, "7개월 이상"); + OPTION1(0, "1개월 ~ 3개월"), + OPTION2(1, "4개월 ~ 6개월"), + OPTION3(2, "7개월 이상"); private final int key; private final String value; From 705591457ddef35b87c7075340daad91e4681b4e Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Tue, 9 Jul 2024 18:33:49 +0900 Subject: [PATCH 043/205] =?UTF-8?q?[=E2=9C=85chore/#20]=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EB=B0=8F=20=EC=84=B1=EA=B3=B5=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=20=ED=95=84=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/exception/dto/ErrorResponse.java | 5 +---- .../terningserver/exception/dto/SuccessResponse.java | 9 ++++----- .../terningserver/exception/enums/SuccessMessage.java | 11 +++++------ 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/terning/terningserver/exception/dto/ErrorResponse.java b/src/main/java/org/terning/terningserver/exception/dto/ErrorResponse.java index 3411fc6..5cde14f 100644 --- a/src/main/java/org/terning/terningserver/exception/dto/ErrorResponse.java +++ b/src/main/java/org/terning/terningserver/exception/dto/ErrorResponse.java @@ -11,9 +11,7 @@ @Builder public record ErrorResponse( int status, - String message, - @JsonInclude(JsonInclude.Include.NON_NULL) - List errors + String message ) { public static ErrorResponse of(int status, String message){ return ErrorResponse.builder() @@ -26,7 +24,6 @@ public static ErrorResponse of(int status, String message, BindingResult binding return ErrorResponse.builder() .status(status) .message(message) - .errors(ValidationError.of(bindingResult)) .build(); } diff --git a/src/main/java/org/terning/terningserver/exception/dto/SuccessResponse.java b/src/main/java/org/terning/terningserver/exception/dto/SuccessResponse.java index c94fb68..fa35e84 100644 --- a/src/main/java/org/terning/terningserver/exception/dto/SuccessResponse.java +++ b/src/main/java/org/terning/terningserver/exception/dto/SuccessResponse.java @@ -4,19 +4,18 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import org.terning.terningserver.exception.enums.SuccessMessage; -@JsonPropertyOrder({"isSuccess", "code", "message", "result"}) +@JsonPropertyOrder({"status", "message", "result"}) public record SuccessResponse( - boolean isSuccess, - int code, + int status, String message, @JsonInclude(JsonInclude.Include.NON_NULL) T result ) { public static SuccessResponse of(SuccessMessage successMessage){ - return new SuccessResponse(successMessage.isSuccess(), successMessage.getStatus(), successMessage.getMessage(), null); + return new SuccessResponse(successMessage.getStatus(), successMessage.getMessage(), null); } public static SuccessResponse of(SuccessMessage successMessage, T result){ - return new SuccessResponse(successMessage.isSuccess(), successMessage.getStatus(), successMessage.getMessage(), result); + return new SuccessResponse(successMessage.getStatus(), successMessage.getMessage(), result); } } diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 48ab89e..5d6594d 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -7,14 +7,13 @@ @AllArgsConstructor public enum SuccessMessage { - SUCCESS_CREATE_CATEGORY(201, true, "카테고리를 성공적으로 추가하였습니다."), - SUCCESS_GET_CATEGORIES(200, true, "카테고리 리스트 조회를 성공하였습니다."), - SUCCESS_CREATE_WORD(201, true, "단어를 성공적으로 추가하였습니다."), - SUCCESS_GET_WORDS(200, true, "단어 리스트 조회를 성공하였습니다."), - SUCCESS_GET_WORD(200, true, "특정 단어 조회를 성공하였습니다."); + SUCCESS_CREATE_CATEGORY(201, "카테고리를 성공적으로 추가하였습니다."), + SUCCESS_GET_CATEGORIES(200, "카테고리 리스트 조회를 성공하였습니다."), + SUCCESS_CREATE_WORD(201, "단어를 성공적으로 추가하였습니다."), + SUCCESS_GET_WORDS(200, "단어 리스트 조회를 성공하였습니다."), + SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."); private final int status; - private final boolean success; private final String message; } From 9af51b60908b64da6c0fcb08cf8395092183d15f Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Wed, 10 Jul 2024 02:16:37 +0900 Subject: [PATCH 044/205] =?UTF-8?q?[=E2=9C=A8=20feat/#22]=20=ED=83=90?= =?UTF-8?q?=EC=83=89=20>=20=EC=A1=B0=ED=9A=8C=EC=88=98=20=EB=A7=8E?= =?UTF-8?q?=EC=9D=80=20=EA=B3=B5=EA=B3=A0=20dto=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/controller/Empty.txt | 0 .../controller/SearchController.java | 11 ++++++++ .../terningserver/controller/api/Empty.txt | 0 .../controller/swagger/SearchSwagger.java | 12 +++++++++ .../terning/terningserver/domain/Company.java | 2 ++ .../dto/search/response/SearchResponse.java | 26 +++++++++++++++++++ .../exception/enums/SuccessMessage.java | 4 +++ 7 files changed, 55 insertions(+) delete mode 100644 src/main/java/org/terning/terningserver/controller/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/controller/SearchController.java delete mode 100644 src/main/java/org/terning/terningserver/controller/api/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java create mode 100644 src/main/java/org/terning/terningserver/dto/search/response/SearchResponse.java diff --git a/src/main/java/org/terning/terningserver/controller/Empty.txt b/src/main/java/org/terning/terningserver/controller/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java new file mode 100644 index 0000000..3db3f12 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -0,0 +1,11 @@ +package org.terning.terningserver.controller; + + +import org.springframework.web.bind.annotation.RestController; + + +@RestController +public class SearchController { + + +} diff --git a/src/main/java/org/terning/terningserver/controller/api/Empty.txt b/src/main/java/org/terning/terningserver/controller/api/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java new file mode 100644 index 0000000..76b2d20 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java @@ -0,0 +1,12 @@ +package org.terning.terningserver.controller.swagger; + + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +@Tag(name = "Search", description = "탐색 관련 API") +public interface SearchSwagger { + +// @Operation(summary = "탐색 > 지금 조회수 많은 공고", description = "탐색 화면에서 조회수 많은 공고를 불러오는 API") + +} diff --git a/src/main/java/org/terning/terningserver/domain/Company.java b/src/main/java/org/terning/terningserver/domain/Company.java index aa11de8..4740871 100644 --- a/src/main/java/org/terning/terningserver/domain/Company.java +++ b/src/main/java/org/terning/terningserver/domain/Company.java @@ -5,9 +5,11 @@ import jakarta.persistence.Embeddable; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import lombok.Getter; import org.terning.terningserver.domain.enums.CompanyCategory; @Embeddable +@Getter public class Company { @Column(nullable = false, length = 64) diff --git a/src/main/java/org/terning/terningserver/dto/search/response/SearchResponse.java b/src/main/java/org/terning/terningserver/dto/search/response/SearchResponse.java new file mode 100644 index 0000000..fafe4a5 --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/search/response/SearchResponse.java @@ -0,0 +1,26 @@ +package org.terning.terningserver.dto.search.response; + +import lombok.Builder; +import org.terning.terningserver.domain.Company; +import org.terning.terningserver.domain.InternshipAnnouncement; + +import java.util.List; + +public record SearchResponse( + List announcements +) { + + @Builder + public record MostViewedAnnouncementResponse( + Long internshipAnnouncementId, + String companyImage, + String title + ) { + public static MostViewedAnnouncementResponse of (InternshipAnnouncement internshipAnnouncement) { + return MostViewedAnnouncementResponse.builder() + .internshipAnnouncementId(internshipAnnouncement.getId()) + .companyImage(internshipAnnouncement.getCompany().getCompanyImage()) + .build(); + } + } +} diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 48ab89e..96c6890 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -13,6 +13,10 @@ public enum SuccessMessage { SUCCESS_GET_WORDS(200, true, "단어 리스트 조회를 성공하였습니다."), SUCCESS_GET_WORD(200, true, "특정 단어 조회를 성공하였습니다."); + // Search - 탐색 화면 + + + private final int status; private final boolean success; private final String message; From f75ce4f2d5cc432da08e71808ad453191b4869b0 Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Wed, 10 Jul 2024 02:56:03 +0900 Subject: [PATCH 045/205] =?UTF-8?q?[=E2=9C=A8=20feat/#22]=20=ED=83=90?= =?UTF-8?q?=EC=83=89=20>=20=EC=A1=B0=ED=9A=8C=EC=88=98=20&=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=20=EC=88=98=20=EB=A7=8E=EC=9D=80=20=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20dto=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PopularAnnouncementListResponse.java | 35 +++++++++++++++++++ .../dto/search/response/SearchResponse.java | 26 -------------- .../exception/enums/SuccessMessage.java | 6 ++-- 3 files changed, 38 insertions(+), 29 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/dto/search/response/PopularAnnouncementListResponse.java delete mode 100644 src/main/java/org/terning/terningserver/dto/search/response/SearchResponse.java diff --git a/src/main/java/org/terning/terningserver/dto/search/response/PopularAnnouncementListResponse.java b/src/main/java/org/terning/terningserver/dto/search/response/PopularAnnouncementListResponse.java new file mode 100644 index 0000000..39c2e05 --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/search/response/PopularAnnouncementListResponse.java @@ -0,0 +1,35 @@ +package org.terning.terningserver.dto.search.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import org.terning.terningserver.domain.InternshipAnnouncement; + +import java.util.List; +import java.util.stream.Collectors; + +public record PopularAnnouncementListResponse( + List announcements +) { + + @Builder + public record MostViewedAndScrappedAnnouncement( + Long internshipAnnouncementId, + String companyImage, + String title + ) { + public static MostViewedAndScrappedAnnouncement from(InternshipAnnouncement announcement) { + return MostViewedAndScrappedAnnouncement.builder() + .internshipAnnouncementId(announcement.getId()) + .companyImage(announcement.getCompany().getCompanyImage()) + .title(announcement.getTitle()) + .build(); + } + } + + public static PopularAnnouncementListResponse of(List announcements) { + return new PopularAnnouncementListResponse( + announcements.stream().map(MostViewedAndScrappedAnnouncement::from).toList() + ); + } +} diff --git a/src/main/java/org/terning/terningserver/dto/search/response/SearchResponse.java b/src/main/java/org/terning/terningserver/dto/search/response/SearchResponse.java deleted file mode 100644 index fafe4a5..0000000 --- a/src/main/java/org/terning/terningserver/dto/search/response/SearchResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.terning.terningserver.dto.search.response; - -import lombok.Builder; -import org.terning.terningserver.domain.Company; -import org.terning.terningserver.domain.InternshipAnnouncement; - -import java.util.List; - -public record SearchResponse( - List announcements -) { - - @Builder - public record MostViewedAnnouncementResponse( - Long internshipAnnouncementId, - String companyImage, - String title - ) { - public static MostViewedAnnouncementResponse of (InternshipAnnouncement internshipAnnouncement) { - return MostViewedAnnouncementResponse.builder() - .internshipAnnouncementId(internshipAnnouncement.getId()) - .companyImage(internshipAnnouncement.getCompany().getCompanyImage()) - .build(); - } - } -} diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 24daf6a..d4b180d 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -11,10 +11,10 @@ public enum SuccessMessage { SUCCESS_GET_CATEGORIES(200, "카테고리 리스트 조회를 성공하였습니다."), SUCCESS_CREATE_WORD(201, "단어를 성공적으로 추가하였습니다."), SUCCESS_GET_WORDS(200, "단어 리스트 조회를 성공하였습니다."), - SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."); - - // Search - 탐색 화면 + SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."), + // Search (탐색 화면) + SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다."); private final int status; From 8570084e7e05bfb729ab00dab02bae481ebdda65 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 10 Jul 2024 16:24:38 +0900 Subject: [PATCH 046/205] Update Empty.txt --- .../terning/terningserver/controller/{api => swagger}/Empty.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/terning/terningserver/controller/{api => swagger}/Empty.txt (100%) diff --git a/src/main/java/org/terning/terningserver/controller/api/Empty.txt b/src/main/java/org/terning/terningserver/controller/swagger/Empty.txt similarity index 100% rename from src/main/java/org/terning/terningserver/controller/api/Empty.txt rename to src/main/java/org/terning/terningserver/controller/swagger/Empty.txt From 1a9751ae8b2c2047b49aeae95d6e2b2750b3ee8e Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 10 Jul 2024 16:45:42 +0900 Subject: [PATCH 047/205] =?UTF-8?q?[=E2=9C=85chore/#23]=20Connection=20Poo?= =?UTF-8?q?l=20+=20Hikari=20CP=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +-- build.gradle | 2 -- src/main/resources/application-dev.yml | 41 ++++++++++++++++++++++++++ src/main/resources/application.yml | 4 +++ 4 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application.yml diff --git a/.gitignore b/.gitignore index 4f5aa4a..99bdb2d 100644 --- a/.gitignore +++ b/.gitignore @@ -188,8 +188,8 @@ Temporary Items .apdisk # application.yml -src/main/resources/application.yml -src/main/resources/application-dev.yml +#src/main/resources/application.yml +#src/main/resources/application-dev.yml # Q-Class src/main/generated diff --git a/build.gradle b/build.gradle index 19aa4de..4886711 100644 --- a/build.gradle +++ b/build.gradle @@ -46,8 +46,6 @@ dependencies { annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" - //validation - implementation 'ort.springframework.boot:spring-boot-starter-validation' } //QueryDSL 초기 설정 diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..07ab368 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,41 @@ +spring: + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://localhost:5432/terning + username: ${USER_ID} + password: ${USER_PW} + + hikari: + maximum-pool-size: 10 + minimum-idle: 10 + connection-timeout: 5000 # 5 seconds + validation-timeout: 2000 # 2 seconds + idle-timeout: 600000 # 10 minutes + max-lifetime: 1800000 # 30 minutes + + # 로그 관련 설정 + data-source-properties: + dataSource.logWriter: # 로그 작성 구현체 지정 + dataSource.logUnclosedConnections: false # 사용하지 않은 커넥션의 로깅 여부 지정 + + # 모니터링 관련 설정 + metrics: + enabled: true # HikariCP 메트릭스 활성화 + export: + reporter: + - prometheus # 사용할 메트릭스 리포터 설정 + prometheus: + enabled: true # Prometheus 메트릭스 리포터 활성화 여부 + step: 60s # 측정 간격 + jpa: + show-sql: true + hibernate: + ddl-auto: update + properties: + hibernate: + format_sql: true + show_sql: true + +logging: + level: + com.zaxxer.hikari: INFO \ 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 0000000..41ba440 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,4 @@ +spring: + profiles: + active: + - dev \ No newline at end of file From f81c7561df09b6fbbaf09428026ee86f6bbec385 Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Wed, 10 Jul 2024 20:42:55 +0900 Subject: [PATCH 048/205] =?UTF-8?q?[=E2=9C=A8=20feat/#22]=20SearchControll?= =?UTF-8?q?er,=20SearchService=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SearchController.java | 19 ++++++++++ .../domain/InternshipAnnouncement.java | 3 +- .../exception/enums/SuccessMessage.java | 2 +- .../terningserver/repository/Empty.txt | 0 .../InternshipRepository.java | 7 ++++ .../InternshipRepositoryCustom.java | 9 +++++ .../InternshipRepositoryImpl.java | 37 +++++++++++++++++++ .../terning/terningserver/service/Empty.txt | 0 .../terningserver/service/SearchService.java | 25 +++++++++++++ 9 files changed, 100 insertions(+), 2 deletions(-) delete mode 100644 src/main/java/org/terning/terningserver/repository/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java create mode 100644 src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java create mode 100644 src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java delete mode 100644 src/main/java/org/terning/terningserver/service/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/service/SearchService.java diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index 3db3f12..6d3231b 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -1,11 +1,30 @@ package org.terning.terningserver.controller; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; +import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.exception.enums.SuccessMessage; +import org.terning.terningserver.service.SearchService; @RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") public class SearchController { + private final SearchService searchService; + + @GetMapping("/search/views") + public ResponseEntity> getPopularAnnouncements() { + return ResponseEntity.ok(SuccessResponse.of( + SuccessMessage.SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS, + searchService.getMostViewedAnnouncements()) + ); + } } diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java index 328b80b..e337b07 100644 --- a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -5,6 +5,7 @@ import lombok.NoArgsConstructor; import org.terning.terningserver.domain.common.BaseTimeEntity; +import java.time.LocalDate; import java.time.YearMonth; import java.util.Date; @@ -23,7 +24,7 @@ public class InternshipAnnouncement extends BaseTimeEntity { @Column(nullable = false, length = 64) private String title; // 인턴십 제목 - private Date deadline; // 지원 마감일 + private LocalDate deadline; // 지원 마감일 @Column(length = 16) private String workingPeriod; // 근무 기간 diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index d4b180d..3077f56 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -14,7 +14,7 @@ public enum SuccessMessage { SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."), // Search (탐색 화면) - SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다."); + SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다."),; private final int status; diff --git a/src/main/java/org/terning/terningserver/repository/Empty.txt b/src/main/java/org/terning/terningserver/repository/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java new file mode 100644 index 0000000..8e3de69 --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java @@ -0,0 +1,7 @@ +package org.terning.terningserver.repository.InternshipAnnouncement; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.terning.terningserver.domain.InternshipAnnouncement; + +public interface InternshipRepository extends JpaRepository, InternshipRepositoryCustom { +} diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java new file mode 100644 index 0000000..3507dec --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java @@ -0,0 +1,9 @@ +package org.terning.terningserver.repository.InternshipAnnouncement; + +import org.terning.terningserver.domain.InternshipAnnouncement; + +import java.util.List; + +public interface InternshipRepositoryCustom { + List getMostViewedInternship(); +} diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java new file mode 100644 index 0000000..d042c4d --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java @@ -0,0 +1,37 @@ +package org.terning.terningserver.repository.InternshipAnnouncement; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.terning.terningserver.domain.InternshipAnnouncement; + +import static org.terning.terningserver.domain.QInternshipAnnouncement.internshipAnnouncement; + +import java.time.LocalDate; +import java.util.List; + +public class InternshipRepositoryImpl implements InternshipRepositoryCustom { + + @Autowired + private JPAQueryFactory jpaQueryFactory; + + @Override + public List getMostViewedInternship() { + return jpaQueryFactory + .selectFrom(internshipAnnouncement) + .where( + internDeadlineGoe(), + internCreatedAtAfter() + ) //지원 마감된 공고 및 30일 보다 오래된 공고 제외 + .orderBy(internshipAnnouncement.scrapCount.desc(), internshipAnnouncement.createdAt.desc()) + .fetch(); + } + + private BooleanExpression internDeadlineGoe() { + return internshipAnnouncement.deadline.goe(LocalDate.now()); + } + + private BooleanExpression internCreatedAtAfter() { + return internshipAnnouncement.createdAt.after(LocalDate.now().minusDays(30).atStartOfDay()); + } +} diff --git a/src/main/java/org/terning/terningserver/service/Empty.txt b/src/main/java/org/terning/terningserver/service/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java new file mode 100644 index 0000000..823d35d --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -0,0 +1,25 @@ +package org.terning.terningserver.service; + + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; +import org.terning.terningserver.repository.InternshipAnnouncement.InternshipRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class SearchService { + + private final InternshipRepository internshipRepository; + + public PopularAnnouncementListResponse getMostViewedAnnouncements() { + List mostViewedInternships = internshipRepository.getMostViewedInternship(); + return PopularAnnouncementListResponse.of(mostViewedInternships); + } + +} From 5bd51bc1841743c39bdb220dfe54c2a51a056ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 10 Jul 2024 22:22:40 +0900 Subject: [PATCH 049/205] =?UTF-8?q?[=F0=9F=94=80merge/#17]:=20develop?= =?UTF-8?q?=EC=9D=98=20=EB=B3=80=EA=B2=BD=EC=82=AC=ED=95=AD=EC=9D=84=20?= =?UTF-8?q?=EB=B0=98=EC=98=81=ED=95=98=EC=98=80=EC=8A=B5=EB=8B=88=EB=8B=A4?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- build.gradle | 52 ++++++++++-- .../terningserver/domain/QAdvertisement.java | 45 +++++++++++ .../terningserver/domain/QCompany.java | 41 ++++++++++ .../terning/terningserver/domain/QFilter.java | 43 ++++++++++ .../domain/QInternshipAnnouncement.java | 79 +++++++++++++++++++ .../terning/terningserver/domain/QScrap.java | 64 +++++++++++++++ .../terning/terningserver/domain/QUser.java | 71 +++++++++++++++++ .../domain/common/QBaseTimeEntity.java | 39 +++++++++ .../terningserver/config/QuerydslConfig.java | 19 +++++ .../terningserver/controller/api/Empty.txt | 0 .../terningserver/domain/enums/Grade.java | 8 +- .../domain/enums/WorkingPeriod.java | 6 +- .../exception/dto/ErrorResponse.java | 6 +- .../exception/dto/SuccessResponse.java | 9 +-- .../exception/enums/ErrorMessage.java | 2 - .../exception/enums/SuccessMessage.java | 11 ++- 17 files changed, 463 insertions(+), 34 deletions(-) create mode 100644 src/main/generated/org/terning/terningserver/domain/QAdvertisement.java create mode 100644 src/main/generated/org/terning/terningserver/domain/QCompany.java create mode 100644 src/main/generated/org/terning/terningserver/domain/QFilter.java create mode 100644 src/main/generated/org/terning/terningserver/domain/QInternshipAnnouncement.java create mode 100644 src/main/generated/org/terning/terningserver/domain/QScrap.java create mode 100644 src/main/generated/org/terning/terningserver/domain/QUser.java create mode 100644 src/main/generated/org/terning/terningserver/domain/common/QBaseTimeEntity.java create mode 100644 src/main/java/org/terning/terningserver/config/QuerydslConfig.java create mode 100644 src/main/java/org/terning/terningserver/controller/api/Empty.txt diff --git a/.gitignore b/.gitignore index a50b7a1..a402d02 100644 --- a/.gitignore +++ b/.gitignore @@ -189,4 +189,4 @@ Temporary Items # application.yml src/main/resources/application.yml -src/main/resources/application-dev.yml +src/main/resources/application-dev.yml \ No newline at end of file diff --git a/build.gradle b/build.gradle index 72c88dd..27d444c 100644 --- a/build.gradle +++ b/build.gradle @@ -13,16 +13,14 @@ java { } } -configurations { - compileOnly { - extendsFrom annotationProcessor - } -} - repositories { mavenCentral() } +ext { + set('queryDslVersion', "5.0.0") +} + dependencies { //default @@ -42,16 +40,54 @@ dependencies { //Health-check implementation 'org.springframework.boot:spring-boot-starter-actuator' + //QueryDSL + implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta" + annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" + + //validation + implementation 'ort.springframework.boot:spring-boot-starter-validation' + //JWT implementation 'io.jsonwebtoken:jjwt-api:0.11.5' implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' - // Spring Security + // security implementation 'org.springframework.boot:spring-boot-starter-security' + // gson + implementation 'com.google.code.gson:gson:2.8.6' +} + +//QueryDSL 초기 설정 +//1. Q-Class를 생성할 디렉토리 경로를 설정합니다. +def queryDslSrcDir = 'src/main/generated/querydsl/' + +//2. JavaCompile Task를 수행하는 경우 생성될 소스코드의 출력 디렉토리를 queryDslSrcDir로 설정합니다. +tasks.withType(JavaCompile).configureEach { + options.getGeneratedSourceOutputDirectory().set(file(queryDslSrcDir)) +} + +//3. 소스 코드로 인식할 디렉토리 경로에 Q-Class 파일을 추가합니다. 이렇게 하면 Q-Class가 일반 Java 클래스처럼 취급되어 컴파일과 실행 시 classPath에 포함됩니다. +sourceSets { + main.java.srcDirs += [queryDslSrcDir] +} + +//4. clean Task를 수행하는 경우 지정한 디렉토리를 삭제하도록 설정합니다. -> 자동 생성된 Q-Class를 제거합니다. +clean { + delete file(queryDslSrcDir) +} + +//5. QueryDSL과 관련된 라이브러리들이 컴파일 시점에만 필요하도록 설정합니다. 또한, QueryDSL 설정을 컴파일 클래스 패스에 추가합니다. +configurations { + compileOnly { + extendsFrom annotationProcessor + } + querydsl.extendsFrom compileClasspath } tasks.named('test') { useJUnitPlatform() -} +} \ No newline at end of file diff --git a/src/main/generated/org/terning/terningserver/domain/QAdvertisement.java b/src/main/generated/org/terning/terningserver/domain/QAdvertisement.java new file mode 100644 index 0000000..bf8a61a --- /dev/null +++ b/src/main/generated/org/terning/terningserver/domain/QAdvertisement.java @@ -0,0 +1,45 @@ +package org.terning.terningserver.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; + + +/** + * QAdvertisement is a Querydsl query type for Advertisement + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QAdvertisement extends EntityPathBase { + + private static final long serialVersionUID = 558022676L; + + public static final QAdvertisement advertisement = new QAdvertisement("advertisement"); + + public final org.terning.terningserver.domain.common.QBaseTimeEntity _super = new org.terning.terningserver.domain.common.QBaseTimeEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + //inherited + public final DateTimePath modifiedAt = _super.modifiedAt; + + public QAdvertisement(String variable) { + super(Advertisement.class, forVariable(variable)); + } + + public QAdvertisement(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QAdvertisement(PathMetadata metadata) { + super(Advertisement.class, metadata); + } + +} + diff --git a/src/main/generated/org/terning/terningserver/domain/QCompany.java b/src/main/generated/org/terning/terningserver/domain/QCompany.java new file mode 100644 index 0000000..949821f --- /dev/null +++ b/src/main/generated/org/terning/terningserver/domain/QCompany.java @@ -0,0 +1,41 @@ +package org.terning.terningserver.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; + + +/** + * QCompany is a Querydsl query type for Company + */ +@Generated("com.querydsl.codegen.DefaultEmbeddableSerializer") +public class QCompany extends BeanPath { + + private static final long serialVersionUID = -216030772L; + + public static final QCompany company = new QCompany("company"); + + public final EnumPath companyCategory = createEnum("companyCategory", org.terning.terningserver.domain.enums.CompanyCategory.class); + + public final StringPath companyImage = createString("companyImage"); + + public final StringPath companyInfo = createString("companyInfo"); + + public QCompany(String variable) { + super(Company.class, forVariable(variable)); + } + + public QCompany(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QCompany(PathMetadata metadata) { + super(Company.class, metadata); + } + +} + diff --git a/src/main/generated/org/terning/terningserver/domain/QFilter.java b/src/main/generated/org/terning/terningserver/domain/QFilter.java new file mode 100644 index 0000000..c9c3ec1 --- /dev/null +++ b/src/main/generated/org/terning/terningserver/domain/QFilter.java @@ -0,0 +1,43 @@ +package org.terning.terningserver.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; + + +/** + * QFilter is a Querydsl query type for Filter + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QFilter extends EntityPathBase { + + private static final long serialVersionUID = -480837559L; + + public static final QFilter filter = new QFilter("filter"); + + public final EnumPath grade = createEnum("grade", org.terning.terningserver.domain.enums.Grade.class); + + public final NumberPath id = createNumber("id", Long.class); + + public final ComparablePath startDate = createComparable("startDate", java.time.YearMonth.class); + + public final EnumPath workingPeriod = createEnum("workingPeriod", org.terning.terningserver.domain.enums.WorkingPeriod.class); + + public QFilter(String variable) { + super(Filter.class, forVariable(variable)); + } + + public QFilter(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QFilter(PathMetadata metadata) { + super(Filter.class, metadata); + } + +} + diff --git a/src/main/generated/org/terning/terningserver/domain/QInternshipAnnouncement.java b/src/main/generated/org/terning/terningserver/domain/QInternshipAnnouncement.java new file mode 100644 index 0000000..9eb048a --- /dev/null +++ b/src/main/generated/org/terning/terningserver/domain/QInternshipAnnouncement.java @@ -0,0 +1,79 @@ +package org.terning.terningserver.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QInternshipAnnouncement is a Querydsl query type for InternshipAnnouncement + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QInternshipAnnouncement extends EntityPathBase { + + private static final long serialVersionUID = -146716794L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QInternshipAnnouncement internshipAnnouncement = new QInternshipAnnouncement("internshipAnnouncement"); + + public final org.terning.terningserver.domain.common.QBaseTimeEntity _super = new org.terning.terningserver.domain.common.QBaseTimeEntity(this); + + public final QCompany company; + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final DateTimePath deadline = createDateTime("deadline", java.util.Date.class); + + public final StringPath detail = createString("detail"); + + public final NumberPath id = createNumber("id", Long.class); + + public final StringPath jobType = createString("jobType"); + + //inherited + public final DateTimePath modifiedAt = _super.modifiedAt; + + public final StringPath qualifications = createString("qualifications"); + + public final NumberPath scrapCount = createNumber("scrapCount", Integer.class); + + public final ComparablePath startDate = createComparable("startDate", java.time.YearMonth.class); + + public final StringPath title = createString("title"); + + public final StringPath url = createString("url"); + + public final NumberPath viewCount = createNumber("viewCount", Integer.class); + + public final StringPath workingPeriod = createString("workingPeriod"); + + public QInternshipAnnouncement(String variable) { + this(InternshipAnnouncement.class, forVariable(variable), INITS); + } + + public QInternshipAnnouncement(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QInternshipAnnouncement(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QInternshipAnnouncement(PathMetadata metadata, PathInits inits) { + this(InternshipAnnouncement.class, metadata, inits); + } + + public QInternshipAnnouncement(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.company = inits.isInitialized("company") ? new QCompany(forProperty("company")) : null; + } + +} + diff --git a/src/main/generated/org/terning/terningserver/domain/QScrap.java b/src/main/generated/org/terning/terningserver/domain/QScrap.java new file mode 100644 index 0000000..63482fc --- /dev/null +++ b/src/main/generated/org/terning/terningserver/domain/QScrap.java @@ -0,0 +1,64 @@ +package org.terning.terningserver.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QScrap is a Querydsl query type for Scrap + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QScrap extends EntityPathBase { + + private static final long serialVersionUID = 1797436640L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QScrap scrap = new QScrap("scrap"); + + public final org.terning.terningserver.domain.common.QBaseTimeEntity _super = new org.terning.terningserver.domain.common.QBaseTimeEntity(this); + + public final EnumPath color = createEnum("color", org.terning.terningserver.domain.enums.Color.class); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final QInternshipAnnouncement internshipAnnouncement; + + //inherited + public final DateTimePath modifiedAt = _super.modifiedAt; + + public final QUser user; + + public QScrap(String variable) { + this(Scrap.class, forVariable(variable), INITS); + } + + public QScrap(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QScrap(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QScrap(PathMetadata metadata, PathInits inits) { + this(Scrap.class, metadata, inits); + } + + public QScrap(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.internshipAnnouncement = inits.isInitialized("internshipAnnouncement") ? new QInternshipAnnouncement(forProperty("internshipAnnouncement"), inits.get("internshipAnnouncement")) : null; + this.user = inits.isInitialized("user") ? new QUser(forProperty("user"), inits.get("user")) : null; + } + +} + diff --git a/src/main/generated/org/terning/terningserver/domain/QUser.java b/src/main/generated/org/terning/terningserver/domain/QUser.java new file mode 100644 index 0000000..58ab814 --- /dev/null +++ b/src/main/generated/org/terning/terningserver/domain/QUser.java @@ -0,0 +1,71 @@ +package org.terning.terningserver.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QUser is a Querydsl query type for User + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QUser extends EntityPathBase { + + private static final long serialVersionUID = 612245724L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QUser user = new QUser("user"); + + public final org.terning.terningserver.domain.common.QBaseTimeEntity _super = new org.terning.terningserver.domain.common.QBaseTimeEntity(this); + + public final StringPath authId = createString("authId"); + + public final EnumPath authType = createEnum("authType", org.terning.terningserver.domain.enums.AuthType.class); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final QFilter filter; + + public final NumberPath id = createNumber("id", Long.class); + + //inherited + public final DateTimePath modifiedAt = _super.modifiedAt; + + public final StringPath name = createString("name"); + + public final StringPath refreshToken = createString("refreshToken"); + + public final ListPath scrapList = this.createList("scrapList", Scrap.class, QScrap.class, PathInits.DIRECT2); + + public final EnumPath state = createEnum("state", org.terning.terningserver.domain.enums.State.class); + + public QUser(String variable) { + this(User.class, forVariable(variable), INITS); + } + + public QUser(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QUser(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QUser(PathMetadata metadata, PathInits inits) { + this(User.class, metadata, inits); + } + + public QUser(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.filter = inits.isInitialized("filter") ? new QFilter(forProperty("filter")) : null; + } + +} + diff --git a/src/main/generated/org/terning/terningserver/domain/common/QBaseTimeEntity.java b/src/main/generated/org/terning/terningserver/domain/common/QBaseTimeEntity.java new file mode 100644 index 0000000..d632fb0 --- /dev/null +++ b/src/main/generated/org/terning/terningserver/domain/common/QBaseTimeEntity.java @@ -0,0 +1,39 @@ +package org.terning.terningserver.domain.common; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; + + +/** + * QBaseTimeEntity is a Querydsl query type for BaseTimeEntity + */ +@Generated("com.querydsl.codegen.DefaultSupertypeSerializer") +public class QBaseTimeEntity extends EntityPathBase { + + private static final long serialVersionUID = -525087629L; + + public static final QBaseTimeEntity baseTimeEntity = new QBaseTimeEntity("baseTimeEntity"); + + public final DateTimePath createdAt = createDateTime("createdAt", java.time.LocalDateTime.class); + + public final DateTimePath modifiedAt = createDateTime("modifiedAt", java.time.LocalDateTime.class); + + public QBaseTimeEntity(String variable) { + super(BaseTimeEntity.class, forVariable(variable)); + } + + public QBaseTimeEntity(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QBaseTimeEntity(PathMetadata metadata) { + super(BaseTimeEntity.class, metadata); + } + +} + diff --git a/src/main/java/org/terning/terningserver/config/QuerydslConfig.java b/src/main/java/org/terning/terningserver/config/QuerydslConfig.java new file mode 100644 index 0000000..8ffa1dc --- /dev/null +++ b/src/main/java/org/terning/terningserver/config/QuerydslConfig.java @@ -0,0 +1,19 @@ +package org.terning.terningserver.config; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class QuerydslConfig { + + @PersistenceContext + private EntityManager entityManager; + + @Bean + public JPAQueryFactory jpaQueryFactory(){ + return new JPAQueryFactory(entityManager); + } +} diff --git a/src/main/java/org/terning/terningserver/controller/api/Empty.txt b/src/main/java/org/terning/terningserver/controller/api/Empty.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/org/terning/terningserver/domain/enums/Grade.java b/src/main/java/org/terning/terningserver/domain/enums/Grade.java index 3fe639a..cd111ab 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/Grade.java +++ b/src/main/java/org/terning/terningserver/domain/enums/Grade.java @@ -5,10 +5,10 @@ @RequiredArgsConstructor public enum Grade { - FRESHMAN(1, "1학년"), - SOPHOMORE(2, "2학년"), - JUNIOR(3, "3학년"), - SENIOR(4, "4학년"); + FRESHMAN(0, "1학년"), + SOPHOMORE(1, "2학년"), + JUNIOR(2, "3학년"), + SENIOR(3, "4학년"); private final int key; private final String value; diff --git a/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java b/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java index d6c4c17..48e9e21 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java +++ b/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java @@ -5,9 +5,9 @@ @RequiredArgsConstructor public enum WorkingPeriod { - OPTION1(1, "1개월 ~ 3개월"), - OPTION2(2, "4개월 ~ 6개월"), - OPTION3(3, "7개월 이상"); + OPTION1(0, "1개월 ~ 3개월"), + OPTION2(1, "4개월 ~ 6개월"), + OPTION3(2, "7개월 이상"); private final int key; private final String value; diff --git a/src/main/java/org/terning/terningserver/exception/dto/ErrorResponse.java b/src/main/java/org/terning/terningserver/exception/dto/ErrorResponse.java index 3411fc6..81a3e5b 100644 --- a/src/main/java/org/terning/terningserver/exception/dto/ErrorResponse.java +++ b/src/main/java/org/terning/terningserver/exception/dto/ErrorResponse.java @@ -1,6 +1,5 @@ package org.terning.terningserver.exception.dto; -import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Builder; import lombok.Getter; import org.springframework.validation.BindingResult; @@ -11,9 +10,7 @@ @Builder public record ErrorResponse( int status, - String message, - @JsonInclude(JsonInclude.Include.NON_NULL) - List errors + String message ) { public static ErrorResponse of(int status, String message){ return ErrorResponse.builder() @@ -26,7 +23,6 @@ public static ErrorResponse of(int status, String message, BindingResult binding return ErrorResponse.builder() .status(status) .message(message) - .errors(ValidationError.of(bindingResult)) .build(); } diff --git a/src/main/java/org/terning/terningserver/exception/dto/SuccessResponse.java b/src/main/java/org/terning/terningserver/exception/dto/SuccessResponse.java index c94fb68..fa35e84 100644 --- a/src/main/java/org/terning/terningserver/exception/dto/SuccessResponse.java +++ b/src/main/java/org/terning/terningserver/exception/dto/SuccessResponse.java @@ -4,19 +4,18 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import org.terning.terningserver.exception.enums.SuccessMessage; -@JsonPropertyOrder({"isSuccess", "code", "message", "result"}) +@JsonPropertyOrder({"status", "message", "result"}) public record SuccessResponse( - boolean isSuccess, - int code, + int status, String message, @JsonInclude(JsonInclude.Include.NON_NULL) T result ) { public static SuccessResponse of(SuccessMessage successMessage){ - return new SuccessResponse(successMessage.isSuccess(), successMessage.getStatus(), successMessage.getMessage(), null); + return new SuccessResponse(successMessage.getStatus(), successMessage.getMessage(), null); } public static SuccessResponse of(SuccessMessage successMessage, T result){ - return new SuccessResponse(successMessage.isSuccess(), successMessage.getStatus(), successMessage.getMessage(), result); + return new SuccessResponse(successMessage.getStatus(), successMessage.getMessage(), result); } } diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index a9cd7b5..a0911b9 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -1,7 +1,5 @@ package org.terning.terningserver.exception.enums; - - import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 48ab89e..5d6594d 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -7,14 +7,13 @@ @AllArgsConstructor public enum SuccessMessage { - SUCCESS_CREATE_CATEGORY(201, true, "카테고리를 성공적으로 추가하였습니다."), - SUCCESS_GET_CATEGORIES(200, true, "카테고리 리스트 조회를 성공하였습니다."), - SUCCESS_CREATE_WORD(201, true, "단어를 성공적으로 추가하였습니다."), - SUCCESS_GET_WORDS(200, true, "단어 리스트 조회를 성공하였습니다."), - SUCCESS_GET_WORD(200, true, "특정 단어 조회를 성공하였습니다."); + SUCCESS_CREATE_CATEGORY(201, "카테고리를 성공적으로 추가하였습니다."), + SUCCESS_GET_CATEGORIES(200, "카테고리 리스트 조회를 성공하였습니다."), + SUCCESS_CREATE_WORD(201, "단어를 성공적으로 추가하였습니다."), + SUCCESS_GET_WORDS(200, "단어 리스트 조회를 성공하였습니다."), + SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."); private final int status; - private final boolean success; private final String message; } From 429681897007c0f101b8c8c0ed79fd25655cfeeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 10 Jul 2024 22:25:54 +0900 Subject: [PATCH 050/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20RestTemplate=20?= =?UTF-8?q?=EB=B9=88=20=EA=B5=AC=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RestTemplateConfig 클래스를 생성하여 RestTemplate 객체를 Spring 빈으로 등록하였습니다. --- .../terningserver/config/RestTemplateConfig.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/config/RestTemplateConfig.java diff --git a/src/main/java/org/terning/terningserver/config/RestTemplateConfig.java b/src/main/java/org/terning/terningserver/config/RestTemplateConfig.java new file mode 100644 index 0000000..24d47d9 --- /dev/null +++ b/src/main/java/org/terning/terningserver/config/RestTemplateConfig.java @@ -0,0 +1,14 @@ +package org.terning.terningserver.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} From 51a90aa433572a7e55acb3f63e0c3dbc6e32a6d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 10 Jul 2024 22:27:04 +0900 Subject: [PATCH 051/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=B0=BE=EA=B8=B0=20=EC=8B=A4?= =?UTF-8?q?=ED=8C=A8=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AuthService에서 findUser 메서드의 예외 처리를 UserException에 CustomException으로 변경하였습니다. --- .../org/terning/terningserver/service/AuthServiceImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index 5ee0b73..80f0b1f 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -13,6 +13,7 @@ import org.terning.terningserver.domain.auth.response.SignInServiceResponse; import org.terning.terningserver.domain.auth.response.TokenGetServiceResponse; import org.terning.terningserver.domain.enums.AuthType; +import org.terning.terningserver.exception.CustomException; import org.terning.terningserver.exception.UserException; import org.terning.terningserver.jwt.JwtTokenProvider; import org.terning.terningserver.jwt.UserAuthentication; @@ -97,12 +98,12 @@ private Token generateToken(Authentication authentication) { } private User findUser(long id) { - return userRepository.findById(id).orElseThrow(() -> new UserException(INVALID_USER)); + return userRepository.findById(id).orElseThrow(() -> new CustomException(INVALID_USER)); } private User findUser(String refreshToken) { return userRepository.findByRefreshToken(getTokenFromBearerString(refreshToken)) - .orElseThrow(() -> new UserException(INVALID_USER)); + .orElseThrow(() -> new CustomException(INVALID_USER)); } private String getTokenFromBearerString(String token) { From f81f3185f47bd50cfef6931f31a73709786caf15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 10 Jul 2024 22:30:10 +0900 Subject: [PATCH 052/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20Apple=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A1=B0=ED=9A=8C=EB=A5=BC=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Apple 서비스 관련 데이터를 조회하기 위한 AppleService 인터페이스를 추가했습니다. - 이 인터페이스는 인증 토큰을 사용하여 Apple 데이터를 조회하는 getAppleData 메서드를 포함하고 있습니다. --- .../org/terning/terningserver/service/AppleService.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/service/AppleService.java diff --git a/src/main/java/org/terning/terningserver/service/AppleService.java b/src/main/java/org/terning/terningserver/service/AppleService.java new file mode 100644 index 0000000..5e22a53 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/AppleService.java @@ -0,0 +1,7 @@ +package org.terning.terningserver.service; + +public interface AppleService { + + String getAppleData(String authAccessToken); + +} From e427ea0b6f524580258051a69903e5561474ed09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 10 Jul 2024 22:30:49 +0900 Subject: [PATCH 053/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20=EC=B9=B4?= =?UTF-8?q?=EC=B9=B4=EC=98=A4=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EC=9D=B8=ED=84=B0?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 카카오 서비스 관련 데이터를 조회하기 위한 KakaoService 인터페이스를 추가했습니다. - 이 인터페이스는 인증 토큰을 사용하여 카카오 데이터를 조회하는 getKakaoData 메서드를 포함하고 있습니다. --- .../org/terning/terningserver/service/KakaoService.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/service/KakaoService.java diff --git a/src/main/java/org/terning/terningserver/service/KakaoService.java b/src/main/java/org/terning/terningserver/service/KakaoService.java new file mode 100644 index 0000000..5e65aca --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/KakaoService.java @@ -0,0 +1,7 @@ +package org.terning.terningserver.service; + +public interface KakaoService { + + String getKakaoData(String authAccessToken); + +} From 506951708e8fda02f9f5dd77fb3fbb9985f24726 Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Thu, 11 Jul 2024 03:41:34 +0900 Subject: [PATCH 054/205] =?UTF-8?q?[=E2=9C=A8=20feat/#22]=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EC=8B=9C=20=EC=8A=A4=ED=81=AC=EB=9E=A9=EC=88=9C?= =?UTF-8?q?=EC=9D=B4=20=EC=95=84=EB=8B=8C=20=EC=A1=B0=ED=9A=8C=EC=88=98?= =?UTF-8?q?=EC=88=9C=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/controller/SearchController.java | 14 +++++++++----- .../controller/swagger/SearchSwagger.java | 13 ++++++++++++- .../domain/InternshipAnnouncement.java | 2 ++ .../InternshipRepositoryImpl.java | 7 ++++--- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index 6d3231b..6457a80 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -6,25 +6,29 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.terning.terningserver.controller.swagger.SearchSwagger; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.exception.enums.SuccessMessage; import org.terning.terningserver.service.SearchService; +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS; + @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") -public class SearchController { +public class SearchController implements SearchSwagger { private final SearchService searchService; @GetMapping("/search/views") - public ResponseEntity> getPopularAnnouncements() { + public ResponseEntity> getMostViewedAnnouncements() { + return ResponseEntity.ok(SuccessResponse.of( - SuccessMessage.SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS, - searchService.getMostViewedAnnouncements()) - ); + SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS, + searchService.getMostViewedAnnouncements() + )); } } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java index 76b2d20..7c674f3 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java @@ -2,11 +2,22 @@ import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; +import org.terning.terningserver.exception.dto.SuccessResponse; @Tag(name = "Search", description = "탐색 관련 API") public interface SearchSwagger { -// @Operation(summary = "탐색 > 지금 조회수 많은 공고", description = "탐색 화면에서 조회수 많은 공고를 불러오는 API") + @Operation(summary = "탐색 > 지금 조회수 많은 공고", description = "탐색 화면에서 조회수 많은 공고를 불러오는 API") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "요청에 성공하였습니다.", content = @Content(mediaType = "application/json")) + }) + ResponseEntity> getMostViewedAnnouncements( + ); } diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java index e337b07..291298a 100644 --- a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -4,10 +4,12 @@ import lombok.Getter; import lombok.NoArgsConstructor; import org.terning.terningserver.domain.common.BaseTimeEntity; +import org.terning.terningserver.domain.enums.Grade; import java.time.LocalDate; import java.time.YearMonth; import java.util.Date; +import java.util.List; import static jakarta.persistence.GenerationType.IDENTITY; import static lombok.AccessLevel.PROTECTED; diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java index d042c4d..064524b 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java @@ -2,6 +2,7 @@ import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.terning.terningserver.domain.InternshipAnnouncement; @@ -10,10 +11,10 @@ import java.time.LocalDate; import java.util.List; +@RequiredArgsConstructor public class InternshipRepositoryImpl implements InternshipRepositoryCustom { - @Autowired - private JPAQueryFactory jpaQueryFactory; + private final JPAQueryFactory jpaQueryFactory; @Override public List getMostViewedInternship() { @@ -23,7 +24,7 @@ public List getMostViewedInternship() { internDeadlineGoe(), internCreatedAtAfter() ) //지원 마감된 공고 및 30일 보다 오래된 공고 제외 - .orderBy(internshipAnnouncement.scrapCount.desc(), internshipAnnouncement.createdAt.desc()) + .orderBy(internshipAnnouncement.viewCount.desc(), internshipAnnouncement.createdAt.desc()) .fetch(); } From 86d7257af8f2b14ad6e6f9443985ec87516f707b Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Thu, 11 Jul 2024 14:19:49 +0900 Subject: [PATCH 055/205] =?UTF-8?q?[=E2=9C=A8=20feat/#27]=20=ED=83=90?= =?UTF-8?q?=EC=83=89=20>=20=EC=8A=A4=ED=81=AC=EB=9E=A9=EC=88=98=20?= =?UTF-8?q?=EB=A7=8E=EC=9D=80=20=EA=B3=B5=EA=B3=A0=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/controller/SearchController.java | 10 ++++++++++ .../exception/enums/SuccessMessage.java | 3 ++- .../InternshipRepositoryCustom.java | 1 + .../InternshipRepositoryImpl.java | 12 ++++++++++++ .../terning/terningserver/service/SearchService.java | 5 +++++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index 6457a80..918f6b2 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -12,6 +12,7 @@ import org.terning.terningserver.exception.enums.SuccessMessage; import org.terning.terningserver.service.SearchService; +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS; @@ -31,4 +32,13 @@ public ResponseEntity> getMostV )); } + @GetMapping("/search/scraps") + public ResponseEntity> getMostScrappedAnnouncements() { + + return ResponseEntity.ok(SuccessResponse.of( + SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS, + searchService.getMostScrappedAnnouncements() + )); + } + } diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 3077f56..d5207f8 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -14,7 +14,8 @@ public enum SuccessMessage { SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."), // Search (탐색 화면) - SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다."),; + SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다."), + SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS(200, "탐색 > 스크랩 수 많은 공고를 조회하는데 성공했습니다."); private final int status; diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java index 3507dec..3de76c6 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java @@ -6,4 +6,5 @@ public interface InternshipRepositoryCustom { List getMostViewedInternship(); + List getMostScrappedInternship(); } diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java index 064524b..170e944 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java @@ -28,6 +28,18 @@ public List getMostViewedInternship() { .fetch(); } + @Override + public List getMostScrappedInternship() { + return jpaQueryFactory + .selectFrom(internshipAnnouncement) + .where( + internDeadlineGoe(), + internCreatedAtAfter() + ) //지원 마감된 공고 및 30일 보다 오래된 공고 제외 + .orderBy(internshipAnnouncement.scrapCount.desc(), internshipAnnouncement.createdAt.desc()) + .fetch(); + } + private BooleanExpression internDeadlineGoe() { return internshipAnnouncement.deadline.goe(LocalDate.now()); } diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index 823d35d..74d41ea 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -22,4 +22,9 @@ public PopularAnnouncementListResponse getMostViewedAnnouncements() { return PopularAnnouncementListResponse.of(mostViewedInternships); } + public PopularAnnouncementListResponse getMostScrappedAnnouncements() { + List mostViewedInternships = internshipRepository.getMostViewedInternship(); + return PopularAnnouncementListResponse.of(mostViewedInternships); + } + } From 49b0c9d7991a20e4cb3e6a78062ec4ddfd704252 Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Thu, 11 Jul 2024 17:26:52 +0900 Subject: [PATCH 056/205] =?UTF-8?q?[=E2=9C=92=EF=B8=8F=20comment/#27]=20qu?= =?UTF-8?q?erydsl=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InternshipAnnouncement/InternshipRepositoryImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java index 170e944..685ba76 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java @@ -40,10 +40,12 @@ public List getMostScrappedInternship() { .fetch(); } + //지원 마감일이 지나지 않은 공고 private BooleanExpression internDeadlineGoe() { return internshipAnnouncement.deadline.goe(LocalDate.now()); } + // 현재 시점으로부터 30일 이내의 공고 private BooleanExpression internCreatedAtAfter() { return internshipAnnouncement.createdAt.after(LocalDate.now().minusDays(30).atStartOfDay()); } From 73d192283ba47955bd04fa6504f7130bf7ad6984 Mon Sep 17 00:00:00 2001 From: JungYoonShin Date: Thu, 11 Jul 2024 17:36:35 +0900 Subject: [PATCH 057/205] =?UTF-8?q?[=E2=9C=85=20chore/#27]=20SuccessMessag?= =?UTF-8?q?e=20=ED=86=B5=EC=9D=BC=EC=84=B1=20=EC=9C=84=ED=95=B4=20message?= =?UTF-8?q?=EC=97=90=20=EB=AC=B8=EC=9E=A5=EB=81=9D=20'.'=20=EC=83=9D?= =?UTF-8?q?=EB=9E=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/exception/enums/SuccessMessage.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index d5207f8..8eb213b 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -7,15 +7,9 @@ @AllArgsConstructor public enum SuccessMessage { - SUCCESS_CREATE_CATEGORY(201, "카테고리를 성공적으로 추가하였습니다."), - SUCCESS_GET_CATEGORIES(200, "카테고리 리스트 조회를 성공하였습니다."), - SUCCESS_CREATE_WORD(201, "단어를 성공적으로 추가하였습니다."), - SUCCESS_GET_WORDS(200, "단어 리스트 조회를 성공하였습니다."), - SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."), - // Search (탐색 화면) - SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다."), - SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS(200, "탐색 > 스크랩 수 많은 공고를 조회하는데 성공했습니다."); + SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다"), + SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS(200, "탐색 > 스크랩 수 많은 공고를 조회하는데 성공했습니다"); private final int status; From 74af5380daffbd61810e0a35f515afcdc7ef46bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 11 Jul 2024 22:47:51 +0900 Subject: [PATCH 058/205] =?UTF-8?q?[=E2=9C=A8=20feat/#27]=20D-Day=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=EC=9D=84=20=EC=9C=84=ED=95=9C=20DateUtil=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SearchController.java | 4 ++- .../terningserver/service/SearchService.java | 2 ++ .../terning/terningserver/util/DateUtil.java | 28 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/terning/terningserver/util/DateUtil.java diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index 918f6b2..1eaf9b3 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -11,6 +11,9 @@ import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.exception.enums.SuccessMessage; import org.terning.terningserver.service.SearchService; +import org.terning.terningserver.util.DateUtil; + +import java.time.LocalDate; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS; @@ -34,7 +37,6 @@ public ResponseEntity> getMostV @GetMapping("/search/scraps") public ResponseEntity> getMostScrappedAnnouncements() { - return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS, searchService.getMostScrappedAnnouncements() diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index 74d41ea..6e5d98c 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -7,7 +7,9 @@ import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; import org.terning.terningserver.repository.InternshipAnnouncement.InternshipRepository; +import org.terning.terningserver.util.DateUtil; +import java.time.LocalDate; import java.util.List; @Service diff --git a/src/main/java/org/terning/terningserver/util/DateUtil.java b/src/main/java/org/terning/terningserver/util/DateUtil.java new file mode 100644 index 0000000..6db949d --- /dev/null +++ b/src/main/java/org/terning/terningserver/util/DateUtil.java @@ -0,0 +1,28 @@ +package org.terning.terningserver.util; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.chrono.ChronoLocalDate; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +public class DateUtil { + + public static String convert(LocalDate deadline) { + ZonedDateTime nowInKorea = ZonedDateTime.now(ZoneId.of("Asia/Seoul")); + LocalDate currentDate = nowInKorea.toLocalDate(); + + if (deadline.isEqual(currentDate)) { + return "D-DAY"; + } else if (deadline.isBefore(currentDate)) { + return "지원마감"; + } else { + long daysUntilDeadline = currentDate.until(deadline).getDays(); + return "D-" + daysUntilDeadline; + } + } +} + From 158d943e326d358edb1bfbb363d02862ea8f6e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 11 Jul 2024 23:45:40 +0900 Subject: [PATCH 059/205] =?UTF-8?q?[=F0=9F=94=A8=C2=A0fix/#27]=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=EC=88=98=20=EB=A7=8E=EC=9D=80=20=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20service=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 조회수가 아닌 스크랩 수가 많은 공고를 가져오도록 호출하는 메서드를 수정했습니다 --- .../java/org/terning/terningserver/service/SearchService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index 6e5d98c..784f35f 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -25,7 +25,7 @@ public PopularAnnouncementListResponse getMostViewedAnnouncements() { } public PopularAnnouncementListResponse getMostScrappedAnnouncements() { - List mostViewedInternships = internshipRepository.getMostViewedInternship(); + List mostViewedInternships = internshipRepository.getMostScrappedInternship(); return PopularAnnouncementListResponse.of(mostViewedInternships); } From 7c6d1d9bad0c59126d98a659a0bd43422d4a11d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 11 Jul 2024 23:57:31 +0900 Subject: [PATCH 060/205] =?UTF-8?q?[=E2=9C=85=C2=A0chore/#27]:=20Swagger?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terning/terningserver/controller/swagger/Empty.txt | 0 .../terningserver/controller/swagger/SearchSwagger.java | 8 ++++++++ 2 files changed, 8 insertions(+) delete mode 100644 src/main/java/org/terning/terningserver/controller/swagger/Empty.txt diff --git a/src/main/java/org/terning/terningserver/controller/swagger/Empty.txt b/src/main/java/org/terning/terningserver/controller/swagger/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java index 7c674f3..7298c49 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java @@ -20,4 +20,12 @@ public interface SearchSwagger { ResponseEntity> getMostViewedAnnouncements( ); + + @Operation(summary = "탐색 > 지금 스크랩 수 많은 공고", description = "탐색 화면에서 스크랩 수 많은 공고를 불러오는 API") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "요청에 성공하였습니다.", content = @Content(mediaType = "application/json")) + }) + ResponseEntity> getMostScrappedAnnouncements( + + ); } From 1fdee68b7020f67b402bb5580050100dbe1f5e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 12 Jul 2024 00:17:02 +0900 Subject: [PATCH 061/205] =?UTF-8?q?[=E2=98=81=EF=B8=8F=C2=A0db/#27]:=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=ED=95=84=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - User 엔티티 프로필 이미지 필드(int 타입) 추가 - InternshipAnnouncement, Filter 엔티티 startDate를 startYear, startMonth(int 타입)으로 분리 --- src/main/java/org/terning/terningserver/domain/Filter.java | 5 +++-- .../terningserver/domain/InternshipAnnouncement.java | 6 +++++- src/main/java/org/terning/terningserver/domain/User.java | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/terning/terningserver/domain/Filter.java b/src/main/java/org/terning/terningserver/domain/Filter.java index a9554d9..7948cbb 100644 --- a/src/main/java/org/terning/terningserver/domain/Filter.java +++ b/src/main/java/org/terning/terningserver/domain/Filter.java @@ -26,6 +26,7 @@ public class Filter { @Column(nullable = false) private WorkingPeriod workingPeriod; - @Column(nullable = false) - private YearMonth startDate; + private int startYear; + + private int startMonth; } diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java index 291298a..e9bfe2d 100644 --- a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -31,7 +31,11 @@ public class InternshipAnnouncement extends BaseTimeEntity { @Column(length = 16) private String workingPeriod; // 근무 기간 - private YearMonth startDate; // 시작 날짜 + @Column(nullable = false) + private int startYear; + + @Column(nullable = false) + private int startMonth; @Column(nullable = false) private int viewCount; // 조회 수 diff --git a/src/main/java/org/terning/terningserver/domain/User.java b/src/main/java/org/terning/terningserver/domain/User.java index 11351a9..c4cb7ee 100644 --- a/src/main/java/org/terning/terningserver/domain/User.java +++ b/src/main/java/org/terning/terningserver/domain/User.java @@ -37,7 +37,8 @@ public class User extends BaseTimeEntity { // private String email; //이메일 -// private String userImage; //유저 아이콘 + @Column(nullable = false) + private int profileImage; @Enumerated(STRING) @Column(nullable = false) From e20dab37cb782dda1abed3779d71f5cd01f4a6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 12 Jul 2024 02:58:03 +0900 Subject: [PATCH 062/205] =?UTF-8?q?[=F0=9F=94=A8fix/#29]:=20Scrap=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20InternshipAnnouncement=EA=B3=BC?= =?UTF-8?q?=EC=9D=98=20=EA=B4=80=EA=B3=84=20N:1=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InternshipDetailController.java | 18 ++++++++ .../controller/swagger/Empty.txt | 0 .../domain/InternshipAnnouncement.java | 8 +++- .../terning/terningserver/domain/Scrap.java | 2 +- .../domain/enums/CompanyCategory.java | 2 + .../InternshipDetailResponse.java | 43 +++++++++++++++++++ .../exception/enums/ErrorMessage.java | 3 +- .../InternshipRepository.java | 2 +- .../InternshipRepositoryCustom.java | 5 ++- .../InternshipRepositoryImpl.java | 11 ++++- .../repository/scrap/ScrapRepository.java | 9 ++++ .../service/InternshipDetailService.java | 34 +++++++++++++++ .../terningserver/service/SearchService.java | 2 +- .../terning/terningserver/util/DateUtil.java | 28 ++++++++++++ 14 files changed, 157 insertions(+), 10 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/controller/InternshipDetailController.java delete mode 100644 src/main/java/org/terning/terningserver/controller/swagger/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java rename src/main/java/org/terning/terningserver/repository/{InternshipAnnouncement => internship_announcement}/InternshipRepository.java (78%) rename src/main/java/org/terning/terningserver/repository/{InternshipAnnouncement => internship_announcement}/InternshipRepositoryCustom.java (55%) rename src/main/java/org/terning/terningserver/repository/{InternshipAnnouncement => internship_announcement}/InternshipRepositoryImpl.java (81%) create mode 100644 src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java create mode 100644 src/main/java/org/terning/terningserver/service/InternshipDetailService.java create mode 100644 src/main/java/org/terning/terningserver/util/DateUtil.java diff --git a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java new file mode 100644 index 0000000..2ee7107 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java @@ -0,0 +1,18 @@ +package org.terning.terningserver.controller; + + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class InternshipDetailController { + +// @GetMapping("/announcements/{internshipAnnouncementId}") +// public ResponseEntity<> + + +} + diff --git a/src/main/java/org/terning/terningserver/controller/swagger/Empty.txt b/src/main/java/org/terning/terningserver/controller/swagger/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java index 291298a..ea80471 100644 --- a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -31,7 +31,11 @@ public class InternshipAnnouncement extends BaseTimeEntity { @Column(length = 16) private String workingPeriod; // 근무 기간 - private YearMonth startDate; // 시작 날짜 + @Column(nullable = false) + private int startYear; + + @Column(nullable = false) + private int startMonth; @Column(nullable = false) private int viewCount; // 조회 수 @@ -53,4 +57,4 @@ public class InternshipAnnouncement extends BaseTimeEntity { @Column(columnDefinition = "TEXT") private String detail; // 상세 내용 -} +} \ No newline at end of file diff --git a/src/main/java/org/terning/terningserver/domain/Scrap.java b/src/main/java/org/terning/terningserver/domain/Scrap.java index c46bf9e..98aec6c 100644 --- a/src/main/java/org/terning/terningserver/domain/Scrap.java +++ b/src/main/java/org/terning/terningserver/domain/Scrap.java @@ -26,7 +26,7 @@ public class Scrap extends BaseTimeEntity { @JoinColumn(name = "user_id", nullable = false) private User user; // 스크랩한 사용자 - @OneToOne(fetch = LAZY) + @ManyToOne(fetch = LAZY) @JoinColumn(name = "internshipAnnouncement_id", nullable = false) private InternshipAnnouncement internshipAnnouncement; // 스크랩한 인턴십 공고 diff --git a/src/main/java/org/terning/terningserver/domain/enums/CompanyCategory.java b/src/main/java/org/terning/terningserver/domain/enums/CompanyCategory.java index ce8ad40..d2f65de 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/CompanyCategory.java +++ b/src/main/java/org/terning/terningserver/domain/enums/CompanyCategory.java @@ -1,8 +1,10 @@ package org.terning.terningserver.domain.enums; +import lombok.Getter; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor +@Getter public enum CompanyCategory { LARGE_AND_MEDIUM_COMPANIES(0, "대기업/중견기업"), diff --git a/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java b/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java new file mode 100644 index 0000000..7d06c0f --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java @@ -0,0 +1,43 @@ +package org.terning.terningserver.dto.internship_detail; + +import lombok.Builder; +import org.terning.terningserver.domain.Company; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.util.DateUtil; + +@Builder +public record InternshipDetailResponse( + String dDay, + String title, + String deadline, + String workingPeriod, + String startDate, + int viewCount, + String company, + String companyCategory, + String companyImage, + String qualification, + String jobType, + String detail, + String url, + boolean isScrapped +) { + public static InternshipDetailResponse of(InternshipAnnouncement announcement, Company company, boolean isScrapped) { + return InternshipDetailResponse.builder() + .dDay(DateUtil.convert(announcement.getDeadline())) + .title(announcement.getTitle()) + .deadline(DateUtil.convertDeadline(announcement.getDeadline())) + .workingPeriod(announcement.getWorkingPeriod()) + .startDate(announcement.getStartYear() + "년 " + announcement.getStartMonth() + "월") + .viewCount(announcement.getViewCount()) + .company(company.getCompanyInfo()) + .companyCategory(company.getCompanyCategory().getValue()) + .companyImage(company.getCompanyImage()) + .qualification(announcement.getQualifications()) + .jobType(announcement.getJobType()) + .detail(announcement.getDetail()) + .url(announcement.getUrl()) + .isScrapped(isScrapped) + .build(); + } +} diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index 77d8202..e6ad142 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -7,8 +7,7 @@ @AllArgsConstructor public enum ErrorMessage { - NOT_FOUND_INTERN_CATEGORY(404, "해당 인턴 공고는 존재하지 않습니다."), - WRONG_PERIOD(404, "해당 단어가 존재하지 않습니다."); + INTERNSHIP_NOT_FOUND(404, "해당 id에 해당하는 인턴 공고가 존재하지 않습니다"); private final int status; private final String message; diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepository.java similarity index 78% rename from src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java rename to src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepository.java index 8e3de69..f3489d3 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepository.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.repository.InternshipAnnouncement; +package org.terning.terningserver.repository.internship_announcement; import org.springframework.data.jpa.repository.JpaRepository; import org.terning.terningserver.domain.InternshipAnnouncement; diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java similarity index 55% rename from src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java rename to src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java index 3507dec..270ad5f 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java @@ -1,9 +1,12 @@ -package org.terning.terningserver.repository.InternshipAnnouncement; +package org.terning.terningserver.repository.internship_announcement; import org.terning.terningserver.domain.InternshipAnnouncement; import java.util.List; +import java.util.Optional; public interface InternshipRepositoryCustom { List getMostViewedInternship(); + + Optional findByInternshipId(); } diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java similarity index 81% rename from src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java rename to src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index 064524b..b10201b 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -1,15 +1,15 @@ -package org.terning.terningserver.repository.InternshipAnnouncement; +package org.terning.terningserver.repository.internship_announcement; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; import org.terning.terningserver.domain.InternshipAnnouncement; import static org.terning.terningserver.domain.QInternshipAnnouncement.internshipAnnouncement; import java.time.LocalDate; import java.util.List; +import java.util.Optional; @RequiredArgsConstructor public class InternshipRepositoryImpl implements InternshipRepositoryCustom { @@ -28,6 +28,13 @@ public List getMostViewedInternship() { .fetch(); } + @Override + public Optional findByInternshipId() { + return jpaQueryFactory + .selectFrom(internshipAnnouncement) + .leftjoin(intern) + } + private BooleanExpression internDeadlineGoe() { return internshipAnnouncement.deadline.goe(LocalDate.now()); } diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java new file mode 100644 index 0000000..b48f690 --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java @@ -0,0 +1,9 @@ +package org.terning.terningserver.repository.scrap; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.terning.terningserver.domain.Scrap; + +import java.util.Optional; + +public interface ScrapRepository extends JpaRepository { +} diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java new file mode 100644 index 0000000..97eee6a --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java @@ -0,0 +1,34 @@ +package org.terning.terningserver.service; + + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.dto.internship_detail.InternshipDetailResponse; +import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.exception.enums.ErrorMessage; +import org.terning.terningserver.repository.internship_announcement.InternshipRepository; +import org.terning.terningserver.repository.scrap.ScrapRepository; + +import static org.terning.terningserver.exception.enums.ErrorMessage.INTERNSHIP_NOT_FOUND; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class InternshipDetailService { + + private final InternshipRepository internshipRepository; + private final ScrapRepository scrapRepository; + + public InternshipDetailResponse getInternshipDetailService(Long internshipAnnouncementId) { + InternshipAnnouncement announcement = internshipRepository.findById(internshipAnnouncementId) + .orElseThrow(() -> new CustomException(INTERNSHIP_NOT_FOUND)); + + + + + + return InternshipDetailResponse.of(announcement, announcement.getCompany(), ) + } +} diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index 823d35d..4f422c9 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -6,7 +6,7 @@ import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; -import org.terning.terningserver.repository.InternshipAnnouncement.InternshipRepository; +import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import java.util.List; diff --git a/src/main/java/org/terning/terningserver/util/DateUtil.java b/src/main/java/org/terning/terningserver/util/DateUtil.java new file mode 100644 index 0000000..419ebc0 --- /dev/null +++ b/src/main/java/org/terning/terningserver/util/DateUtil.java @@ -0,0 +1,28 @@ +package org.terning.terningserver.util; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +public class DateUtil { + + public static String convert(LocalDate deadline) { + ZonedDateTime nowInKorea = ZonedDateTime.now(ZoneId.of("Asia/Seoul")); + LocalDate currentDate = nowInKorea.toLocalDate(); + + if (deadline.isEqual(currentDate)) { + return "D-DAY"; + } else if (deadline.isBefore(currentDate)) { + return "지원마감"; + } else { + long daysUntilDeadline = currentDate.until(deadline).getDays(); + return "D-" + daysUntilDeadline; + } + } + + public static String convertDeadline(LocalDate deadline) { + return deadline.getYear() + "년 " + + deadline.getMonthValue() + "월 " + + deadline.getDayOfYear() + "일"; + } +} From cd20f3c491088ddf12783b9403b0e7dfab74ec8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 12 Jul 2024 03:59:28 +0900 Subject: [PATCH 063/205] =?UTF-8?q?[=E2=9C=A8feat/#29]:=20=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20=EC=83=81=EC=84=B8=20=EC=A0=95=EB=B3=B4=20API=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InternshipDetailController.java | 19 +++++++++++++++++-- .../exception/enums/SuccessMessage.java | 5 ++++- .../InternshipRepositoryCustom.java | 2 -- .../InternshipRepositoryImpl.java | 8 +------- .../repository/scrap/ScrapRepository.java | 2 ++ .../service/InternshipDetailService.java | 10 +++++----- .../terning/terningserver/util/DateUtil.java | 2 +- 7 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java index 2ee7107..8a57ad4 100644 --- a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java +++ b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java @@ -2,16 +2,31 @@ import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.terning.terningserver.dto.internship_detail.InternshipDetailResponse; +import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.service.InternshipDetailService; + +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_INTERNSHIP_DETAIL; @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") public class InternshipDetailController { -// @GetMapping("/announcements/{internshipAnnouncementId}") -// public ResponseEntity<> + private final InternshipDetailService internshipDetailService; + + @GetMapping("/announcements/{internshipAnnouncementId}") + public ResponseEntity> getInternshipDetail(@PathVariable("internshipAnnouncementId") Long internshipAnnouncementId) { + return ResponseEntity.ok(SuccessResponse.of( + SUCCESS_GET_INTERNSHIP_DETAIL, + internshipDetailService.getInternshipDetail(internshipAnnouncementId) + )); + } } diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 3077f56..a04c324 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -14,7 +14,10 @@ public enum SuccessMessage { SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."), // Search (탐색 화면) - SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다."),; + SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다."), + + // 인턴 공고 + SUCCESS_GET_INTERNSHIP_DETAIL(200, "공고 상세 정보 불러오기에 성공했습니다"); private final int status; diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java index 270ad5f..c0798e3 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java @@ -7,6 +7,4 @@ public interface InternshipRepositoryCustom { List getMostViewedInternship(); - - Optional findByInternshipId(); } diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index b10201b..7c62a2f 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -6,6 +6,7 @@ import org.terning.terningserver.domain.InternshipAnnouncement; import static org.terning.terningserver.domain.QInternshipAnnouncement.internshipAnnouncement; +import static org.terning.terningserver.domain.QScrap.scrap; import java.time.LocalDate; import java.util.List; @@ -28,13 +29,6 @@ public List getMostViewedInternship() { .fetch(); } - @Override - public Optional findByInternshipId() { - return jpaQueryFactory - .selectFrom(internshipAnnouncement) - .leftjoin(intern) - } - private BooleanExpression internDeadlineGoe() { return internshipAnnouncement.deadline.goe(LocalDate.now()); } diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java index b48f690..dc07ac9 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java @@ -6,4 +6,6 @@ import java.util.Optional; public interface ScrapRepository extends JpaRepository { + + Boolean existsByInternshipAnnouncementId(Long internshipId); } diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java index 97eee6a..eb15243 100644 --- a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java @@ -21,14 +21,14 @@ public class InternshipDetailService { private final InternshipRepository internshipRepository; private final ScrapRepository scrapRepository; - public InternshipDetailResponse getInternshipDetailService(Long internshipAnnouncementId) { + public InternshipDetailResponse getInternshipDetail(Long internshipAnnouncementId) { InternshipAnnouncement announcement = internshipRepository.findById(internshipAnnouncementId) .orElseThrow(() -> new CustomException(INTERNSHIP_NOT_FOUND)); - - - - return InternshipDetailResponse.of(announcement, announcement.getCompany(), ) + return InternshipDetailResponse.of( + announcement, announcement.getCompany(), + scrapRepository.existsByInternshipAnnouncementId(announcement.getId()) + ); } } diff --git a/src/main/java/org/terning/terningserver/util/DateUtil.java b/src/main/java/org/terning/terningserver/util/DateUtil.java index 419ebc0..2e7af41 100644 --- a/src/main/java/org/terning/terningserver/util/DateUtil.java +++ b/src/main/java/org/terning/terningserver/util/DateUtil.java @@ -23,6 +23,6 @@ public static String convert(LocalDate deadline) { public static String convertDeadline(LocalDate deadline) { return deadline.getYear() + "년 " + deadline.getMonthValue() + "월 " - + deadline.getDayOfYear() + "일"; + + deadline.getDayOfMonth() + "일"; } } From fabcfec5d4470dc291b1fda4f152f7104a7b4e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 12 Jul 2024 04:08:17 +0900 Subject: [PATCH 064/205] =?UTF-8?q?[=E2=98=81=EF=B8=8Fdb/#29]:=20Filter=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=ED=95=84=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존의 startDate(YearMonth) 필드를 startYear, startMonth로 분리 --- src/main/java/org/terning/terningserver/domain/Filter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/domain/Filter.java b/src/main/java/org/terning/terningserver/domain/Filter.java index a9554d9..7948cbb 100644 --- a/src/main/java/org/terning/terningserver/domain/Filter.java +++ b/src/main/java/org/terning/terningserver/domain/Filter.java @@ -26,6 +26,7 @@ public class Filter { @Column(nullable = false) private WorkingPeriod workingPeriod; - @Column(nullable = false) - private YearMonth startDate; + private int startYear; + + private int startMonth; } From aca162cf0ebb4fe94afc24f1e6466c9a0a6127de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 12 Jul 2024 04:50:47 +0900 Subject: [PATCH 065/205] =?UTF-8?q?[=F0=9F=94=A8fix/#29]=20InternshipRepos?= =?UTF-8?q?itoryImpl=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 탐색 > 조회수, 스크랩 수 많은 공고 조회시 데이터 5개만 보내주도록 수정 --- .../internship_announcement/InternshipRepositoryImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index 7c62a2f..aef259b 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -26,6 +26,7 @@ public List getMostViewedInternship() { internCreatedAtAfter() ) //지원 마감된 공고 및 30일 보다 오래된 공고 제외 .orderBy(internshipAnnouncement.viewCount.desc(), internshipAnnouncement.createdAt.desc()) + .limit(5) .fetch(); } From 68c4e401f2653d32b19608d9d129622243532d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 12 Jul 2024 15:13:14 +0900 Subject: [PATCH 066/205] =?UTF-8?q?[=E2=98=81=EF=B8=8Fdb/#29]:=20Internshi?= =?UTF-8?q?pAnnouncement=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 앱잼단에서는 채용시 공고는 제외하므로, 마감일이 필수이게 되어 deadline 필드에 @Column(nullable = false) 추가 --- .../terning/terningserver/domain/InternshipAnnouncement.java | 3 ++- src/main/java/org/terning/terningserver/util/DateUtil.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java index ea80471..a18672b 100644 --- a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -26,6 +26,7 @@ public class InternshipAnnouncement extends BaseTimeEntity { @Column(nullable = false, length = 64) private String title; // 인턴십 제목 + @Column(nullable = false) private LocalDate deadline; // 지원 마감일 @Column(length = 16) @@ -57,4 +58,4 @@ public class InternshipAnnouncement extends BaseTimeEntity { @Column(columnDefinition = "TEXT") private String detail; // 상세 내용 -} \ No newline at end of file +} diff --git a/src/main/java/org/terning/terningserver/util/DateUtil.java b/src/main/java/org/terning/terningserver/util/DateUtil.java index cee45d7..b59a766 100644 --- a/src/main/java/org/terning/terningserver/util/DateUtil.java +++ b/src/main/java/org/terning/terningserver/util/DateUtil.java @@ -13,7 +13,7 @@ public static String convert(LocalDate deadline) { if (deadline.isEqual(currentDate)) { return "D-DAY"; } else if (deadline.isBefore(currentDate)) { - return "지원마감"; + return "지원 마감"; } else { long daysUntilDeadline = currentDate.until(deadline).getDays(); return "D-" + daysUntilDeadline; From 06a4af1f1cc2aad843f92792e2604ee5eb959076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 12 Jul 2024 15:41:16 +0900 Subject: [PATCH 067/205] =?UTF-8?q?[=E2=9C=A8feat/#29]=20InternshipDetail?= =?UTF-8?q?=20Swagger=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 공고 상세페이지, InternshipDetailController에 대한 Swagger 설정 --- .../InternshipDetailController.java | 6 +++-- .../swagger/InternshipDetailSwagger.java | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java diff --git a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java index 8a57ad4..f29bc33 100644 --- a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java +++ b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.terning.terningserver.controller.swagger.InternshipDetailSwagger; import org.terning.terningserver.dto.internship_detail.InternshipDetailResponse; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.service.InternshipDetailService; @@ -16,12 +17,13 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") -public class InternshipDetailController { +public class InternshipDetailController implements InternshipDetailSwagger { private final InternshipDetailService internshipDetailService; @GetMapping("/announcements/{internshipAnnouncementId}") - public ResponseEntity> getInternshipDetail(@PathVariable("internshipAnnouncementId") Long internshipAnnouncementId) { + public ResponseEntity> getInternshipDetail( + @PathVariable("internshipAnnouncementId") Long internshipAnnouncementId) { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_INTERNSHIP_DETAIL, internshipDetailService.getInternshipDetail(internshipAnnouncementId) diff --git a/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java new file mode 100644 index 0000000..5f37062 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java @@ -0,0 +1,27 @@ +package org.terning.terningserver.controller.swagger; + + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.terning.terningserver.dto.internship_detail.InternshipDetailResponse; +import org.terning.terningserver.exception.dto.SuccessResponse; + +@Tag(name = "InternshipDetail", description = "공고 상세 페이지 관련 API") +public interface InternshipDetailSwagger { + + @Operation(summary = "공고 상세 페이지", description = "인턴 공고의 상세 정보를 불러오는 API") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "공고 상세 정보 불러오기에 성공했습니다", content = @Content(mediaType = "application/json")), + @ApiResponse(responseCode = "404", description = "해당 id에 해당하는 인턴 공고가 존재하지 않습니다", content = @Content(mediaType = "application/json")) + }) + ResponseEntity> getInternshipDetail( + @PathVariable("internshipAnnouncementId") Long internshipAnnouncementId + ); +} From bf393fdbc82eb3cc2f4aaef994b194d83a2161e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Sat, 13 Jul 2024 00:01:52 +0900 Subject: [PATCH 068/205] =?UTF-8?q?[=E2=9C=A8feat/#31]:=20=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20=EC=83=81=EC=84=B8=20=EC=A0=95=EB=B3=B4=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20response=20body=20scrapCount=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/controller/SearchController.java | 9 +++++++++ .../terningserver/domain/InternshipAnnouncement.java | 3 +++ .../java/org/terning/terningserver/domain/Scrap.java | 2 +- .../InternshipRepository.java | 2 +- .../InternshipRepositoryCustom.java | 6 +++++- .../InternshipRepositoryImpl.java | 11 +++++++++-- .../terning/terningserver/service/SearchService.java | 10 +++++++--- 7 files changed, 35 insertions(+), 8 deletions(-) rename src/main/java/org/terning/terningserver/repository/{InternshipAnnouncement => internship_announcement}/InternshipRepository.java (78%) rename src/main/java/org/terning/terningserver/repository/{InternshipAnnouncement => internship_announcement}/InternshipRepositoryCustom.java (54%) rename src/main/java/org/terning/terningserver/repository/{InternshipAnnouncement => internship_announcement}/InternshipRepositoryImpl.java (84%) diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index 1eaf9b3..d92d51f 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -5,6 +5,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.terning.terningserver.controller.swagger.SearchSwagger; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; @@ -13,6 +14,7 @@ import org.terning.terningserver.service.SearchService; import org.terning.terningserver.util.DateUtil; +import java.awt.print.Pageable; import java.time.LocalDate; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS; @@ -43,4 +45,11 @@ public ResponseEntity> getMostS )); } + @GetMapping("/search") + public void searchInternshipAnnouncement( + @RequestParam String keyword, + @RequestParam String sortBy, Pageable pageable) { + searchService.searchInternshipAnnouncement(keyword, sortBy, pageable); + } + } diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java index e9bfe2d..e336b00 100644 --- a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -46,6 +46,9 @@ public class InternshipAnnouncement extends BaseTimeEntity { @Column(nullable = false, length = 256) private String url; // 인턴십 공고 URL + @OneToMany(mappedBy = "internshipAnnouncement") + private List scraps; + @Embedded private Company company; diff --git a/src/main/java/org/terning/terningserver/domain/Scrap.java b/src/main/java/org/terning/terningserver/domain/Scrap.java index c46bf9e..98aec6c 100644 --- a/src/main/java/org/terning/terningserver/domain/Scrap.java +++ b/src/main/java/org/terning/terningserver/domain/Scrap.java @@ -26,7 +26,7 @@ public class Scrap extends BaseTimeEntity { @JoinColumn(name = "user_id", nullable = false) private User user; // 스크랩한 사용자 - @OneToOne(fetch = LAZY) + @ManyToOne(fetch = LAZY) @JoinColumn(name = "internshipAnnouncement_id", nullable = false) private InternshipAnnouncement internshipAnnouncement; // 스크랩한 인턴십 공고 diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepository.java similarity index 78% rename from src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java rename to src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepository.java index 8e3de69..f3489d3 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepository.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.repository.InternshipAnnouncement; +package org.terning.terningserver.repository.internship_announcement; import org.springframework.data.jpa.repository.JpaRepository; import org.terning.terningserver.domain.InternshipAnnouncement; diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java similarity index 54% rename from src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java rename to src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java index 3de76c6..3230d87 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java @@ -1,10 +1,14 @@ -package org.terning.terningserver.repository.InternshipAnnouncement; +package org.terning.terningserver.repository.internship_announcement; import org.terning.terningserver.domain.InternshipAnnouncement; +import java.awt.print.Pageable; import java.util.List; public interface InternshipRepositoryCustom { List getMostViewedInternship(); + List getMostScrappedInternship(); + + List searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable); } diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java similarity index 84% rename from src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java rename to src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index 685ba76..8191268 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -1,13 +1,13 @@ -package org.terning.terningserver.repository.InternshipAnnouncement; +package org.terning.terningserver.repository.internship_announcement; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; import org.terning.terningserver.domain.InternshipAnnouncement; import static org.terning.terningserver.domain.QInternshipAnnouncement.internshipAnnouncement; +import java.awt.print.Pageable; import java.time.LocalDate; import java.util.List; @@ -40,6 +40,13 @@ public List getMostScrappedInternship() { .fetch(); } + @Override + public List searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { + jpaQueryFactory + .selectFrom(InternshipAnnouncement) + .where + } + //지원 마감일이 지나지 않은 공고 private BooleanExpression internDeadlineGoe() { return internshipAnnouncement.deadline.goe(LocalDate.now()); diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index 784f35f..05d7ef2 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -2,14 +2,14 @@ import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; -import org.terning.terningserver.repository.InternshipAnnouncement.InternshipRepository; -import org.terning.terningserver.util.DateUtil; +import org.terning.terningserver.repository.internship_announcement.InternshipRepository; -import java.time.LocalDate; +import java.awt.print.Pageable; import java.util.List; @Service @@ -29,4 +29,8 @@ public PopularAnnouncementListResponse getMostScrappedAnnouncements() { return PopularAnnouncementListResponse.of(mostViewedInternships); } + public void searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { + internshipRepository.searchInternshipAnnouncement(keyword, sortBy, pageable); + } + } From dc2b0f63467335644c2c6f3c42ba797e9f94e23c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Sat, 13 Jul 2024 00:09:45 +0900 Subject: [PATCH 069/205] =?UTF-8?q?[=E2=9C=A8feat/#29]:=20=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20=EC=83=81=EC=84=B8=ED=8E=98=EC=9D=B4=EC=A7=80=20res?= =?UTF-8?q?ponse=20body=20scrapCount=20=ED=95=84=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/internship_detail/InternshipDetailResponse.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java b/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java index 7d06c0f..b08dbfe 100644 --- a/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java +++ b/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java @@ -12,6 +12,7 @@ public record InternshipDetailResponse( String deadline, String workingPeriod, String startDate, + int scrapCount, int viewCount, String company, String companyCategory, @@ -29,6 +30,7 @@ public static InternshipDetailResponse of(InternshipAnnouncement announcement, C .deadline(DateUtil.convertDeadline(announcement.getDeadline())) .workingPeriod(announcement.getWorkingPeriod()) .startDate(announcement.getStartYear() + "년 " + announcement.getStartMonth() + "월") + .scrapCount(announcement.getScrapCount()) .viewCount(announcement.getViewCount()) .company(company.getCompanyInfo()) .companyCategory(company.getCompanyCategory().getValue()) From 60a93179783244d0eb29df007caf01a0e33c7774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Sat, 13 Jul 2024 01:44:52 +0900 Subject: [PATCH 070/205] =?UTF-8?q?[=E2=9C=A8feat/#31]:=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=A1=B0=EA=B1=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 동적 정렬을 위해 OrderSpecifier 사용 --- .../search/response/SearchResultResponse.java | 6 +++ .../InternshipRepositoryCustom.java | 2 +- .../InternshipRepositoryImpl.java | 52 +++++++++++++++++-- .../terningserver/service/SearchService.java | 2 +- 4 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java diff --git a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java new file mode 100644 index 0000000..c45cfc6 --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java @@ -0,0 +1,6 @@ +package org.terning.terningserver.dto.search.response; + +public record SearchResultResponse( + +) { +} diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java index 3230d87..ecd0153 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java @@ -1,8 +1,8 @@ package org.terning.terningserver.repository.internship_announcement; +import org.springframework.data.domain.Pageable; import org.terning.terningserver.domain.InternshipAnnouncement; -import java.awt.print.Pageable; import java.util.List; public interface InternshipRepositoryCustom { diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index 8191268..2515542 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -1,13 +1,17 @@ package org.terning.terningserver.repository.internship_announcement; +import com.querydsl.core.types.Order; +import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.core.types.dsl.NumberTemplate; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; import org.terning.terningserver.domain.InternshipAnnouncement; import static org.terning.terningserver.domain.QInternshipAnnouncement.internshipAnnouncement; -import java.awt.print.Pageable; import java.time.LocalDate; import java.util.List; @@ -42,9 +46,49 @@ public List getMostScrappedInternship() { @Override public List searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { - jpaQueryFactory - .selectFrom(InternshipAnnouncement) - .where + LocalDate today = LocalDate.now(); + + // 현재 시점보다 마감일이 지난 경우 + BooleanExpression isExpired = internshipAnnouncement.deadline.before(today); + + // 현재 시점보다 마감일이 지나지 않은 경우 + BooleanExpression isNotExpired = internshipAnnouncement.deadline.after(today) + .or(internshipAnnouncement.deadline.eq(today)); + + // 우선순위를 위한 Expression(지원된 공고는 정렬 우선순위 낮게 -> 밑에 깔리게) + NumberTemplate priority = Expressions.numberTemplate( + Integer.class, + "CASE WHEN {0} THEN 1 ELSE 2 END", + isNotExpired + ); + return jpaQueryFactory + .selectFrom(internshipAnnouncement) + .leftJoin(internshipAnnouncement.scraps).fetchJoin() + .orderBy(priority.asc(), createOrderSpecifier(sortBy)) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + } + private OrderSpecifier createOrderSpecifier(String sortBy) { + return switch (sortBy) { + case "mostViewed" -> new OrderSpecifier<>(Order.DESC, internshipAnnouncement.viewCount); + case "shortestDuration" -> new OrderSpecifier<>(Order.ASC, getWorkingPeriodAsNumber()); + case "longestDuration" -> new OrderSpecifier<>(Order.DESC, getWorkingPeriodAsNumber()); + case "mostScrapped" -> new OrderSpecifier<>(Order.DESC, internshipAnnouncement.scrapCount); + default -> new OrderSpecifier<>(Order.ASC, internshipAnnouncement.deadline); + }; + } + + /** + * String 타입의 workingPeriod를 숫자로 정렬하게 하기 위한 메서드 + * @return + */ + private NumberTemplate getWorkingPeriodAsNumber() { + return Expressions.numberTemplate( + Integer.class, + "CAST(SUBSTRING({0}, 1, LENGTH({0}) - 2) AS INTEGER)", + internshipAnnouncement.workingPeriod + ); } //지원 마감일이 지나지 않은 공고 diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index 05d7ef2..fb8060d 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -3,13 +3,13 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; -import java.awt.print.Pageable; import java.util.List; @Service From ce0d099ac1b44c22af50260566d5018512b7ec6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Sat, 13 Jul 2024 03:15:22 +0900 Subject: [PATCH 071/205] =?UTF-8?q?[=E2=9C=A8feat/#31]:=20SearchResultResp?= =?UTF-8?q?onse=20dto=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Terning | 1 + .../controller/SearchController.java | 12 ++++--- .../search/response/SearchResultResponse.java | 35 ++++++++++++++++++- .../InternshipRepositoryImpl.java | 4 +-- .../terningserver/service/SearchService.java | 6 ++-- 5 files changed, 48 insertions(+), 10 deletions(-) create mode 160000 Terning diff --git a/Terning b/Terning new file mode 160000 index 0000000..e53017f --- /dev/null +++ b/Terning @@ -0,0 +1 @@ +Subproject commit e53017fc3ff5bbab45222818feb966ca912c1917 diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index d92d51f..e99fa9e 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -2,20 +2,22 @@ import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.terning.terningserver.controller.swagger.SearchSwagger; +import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.exception.enums.SuccessMessage; import org.terning.terningserver.service.SearchService; import org.terning.terningserver.util.DateUtil; -import java.awt.print.Pageable; import java.time.LocalDate; +import java.util.List; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS; @@ -46,10 +48,10 @@ public ResponseEntity> getMostS } @GetMapping("/search") - public void searchInternshipAnnouncement( - @RequestParam String keyword, - @RequestParam String sortBy, Pageable pageable) { - searchService.searchInternshipAnnouncement(keyword, sortBy, pageable); + public List searchInternshipAnnouncement( + @RequestParam(value = "keyword", required = false) String keyword, + @RequestParam("sortBy") String sortBy, Pageable pageable) { + return searchService.searchInternshipAnnouncement(keyword, sortBy, pageable); } } diff --git a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java index c45cfc6..1833c2e 100644 --- a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java +++ b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java @@ -1,6 +1,39 @@ package org.terning.terningserver.dto.search.response; -public record SearchResultResponse( +import lombok.Builder; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.util.DateUtil; + +import java.util.List; +import java.util.stream.Collectors; +public record SearchResultResponse( + List announcements ) { + @Builder + public record SearchAnnouncementResponse( + Long internshipAnnouncementId, + Long scrapId, + String dDay, + String companyImage, + String title, + String workingPeriod, + Boolean isScrapped + ) { + public static SearchAnnouncementResponse from(InternshipAnnouncement announcement, Long scrapId, Boolean isScrapped) { + return SearchAnnouncementResponse.builder() + .internshipAnnouncementId(announcement.getId()) + .scrapId(scrapId) + .dDay(DateUtil.convert(announcement.getDeadline())) + .companyImage(announcement.getCompany().getCompanyImage()) + .title(announcement.getTitle()) + .workingPeriod(announcement.getWorkingPeriod()) + .isScrapped(isScrapped) + .build(); + } + } + public static SearchResultResponse of(List announcements) { + return new SearchResultResponse(announcements); + } + } diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index 2515542..6b57154 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -52,8 +52,7 @@ public List searchInternshipAnnouncement(String keyword, BooleanExpression isExpired = internshipAnnouncement.deadline.before(today); // 현재 시점보다 마감일이 지나지 않은 경우 - BooleanExpression isNotExpired = internshipAnnouncement.deadline.after(today) - .or(internshipAnnouncement.deadline.eq(today)); + BooleanExpression isNotExpired = internshipAnnouncement.deadline.goe(today); // 우선순위를 위한 Expression(지원된 공고는 정렬 우선순위 낮게 -> 밑에 깔리게) NumberTemplate priority = Expressions.numberTemplate( @@ -61,6 +60,7 @@ public List searchInternshipAnnouncement(String keyword, "CASE WHEN {0} THEN 1 ELSE 2 END", isNotExpired ); + return jpaQueryFactory .selectFrom(internshipAnnouncement) .leftJoin(internshipAnnouncement.scraps).fetchJoin() diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index fb8060d..d1ad441 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.Scrap; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; @@ -29,8 +30,9 @@ public PopularAnnouncementListResponse getMostScrappedAnnouncements() { return PopularAnnouncementListResponse.of(mostViewedInternships); } - public void searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { - internshipRepository.searchInternshipAnnouncement(keyword, sortBy, pageable); + public List searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { + List announcements = internshipRepository.searchInternshipAnnouncement(keyword, sortBy, pageable); + announcements.stream().map(announcement -> } } From 15226ff53e76df413c24e5a568c3f94ebaeaf811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Sat, 13 Jul 2024 12:40:48 +0900 Subject: [PATCH 072/205] =?UTF-8?q?[=E2=9C=A8feat/#31]:=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B2=B0=EA=B3=BC=ED=99=94=EB=A9=B4=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - querydsl을 사용하여 검색 결과 화면 로직 구현 --- .../controller/SearchController.java | 3 +- .../search/response/SearchResultResponse.java | 7 ++--- .../repository/scarp/ScrapRepository.java | 12 ++++++++ .../scarp/ScrapRepositoryCustom.java | 12 ++++++++ .../repository/scarp/ScrapRepositoryImpl.java | 24 ++++++++++++++++ .../terningserver/service/SearchService.java | 28 +++++++++++++++++-- 6 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/repository/scarp/ScrapRepository.java create mode 100644 src/main/java/org/terning/terningserver/repository/scarp/ScrapRepositoryCustom.java create mode 100644 src/main/java/org/terning/terningserver/repository/scarp/ScrapRepositoryImpl.java diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index e99fa9e..4781d6b 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -11,6 +11,7 @@ import org.terning.terningserver.controller.swagger.SearchSwagger; import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; +import org.terning.terningserver.dto.search.response.SearchResultResponse; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.exception.enums.SuccessMessage; import org.terning.terningserver.service.SearchService; @@ -48,7 +49,7 @@ public ResponseEntity> getMostS } @GetMapping("/search") - public List searchInternshipAnnouncement( + public SearchResultResponse searchInternshipAnnouncement( @RequestParam(value = "keyword", required = false) String keyword, @RequestParam("sortBy") String sortBy, Pageable pageable) { return searchService.searchInternshipAnnouncement(keyword, sortBy, pageable); diff --git a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java index 1833c2e..31abc09 100644 --- a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java +++ b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java @@ -17,10 +17,9 @@ public record SearchAnnouncementResponse( String dDay, String companyImage, String title, - String workingPeriod, - Boolean isScrapped + String workingPeriod ) { - public static SearchAnnouncementResponse from(InternshipAnnouncement announcement, Long scrapId, Boolean isScrapped) { + public static SearchAnnouncementResponse from(InternshipAnnouncement announcement, Long scrapId) { return SearchAnnouncementResponse.builder() .internshipAnnouncementId(announcement.getId()) .scrapId(scrapId) @@ -28,7 +27,7 @@ public static SearchAnnouncementResponse from(InternshipAnnouncement announcemen .companyImage(announcement.getCompany().getCompanyImage()) .title(announcement.getTitle()) .workingPeriod(announcement.getWorkingPeriod()) - .isScrapped(isScrapped) +// .isScrapped(isScrapped) .build(); } } diff --git a/src/main/java/org/terning/terningserver/repository/scarp/ScrapRepository.java b/src/main/java/org/terning/terningserver/repository/scarp/ScrapRepository.java new file mode 100644 index 0000000..5f2e58d --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/scarp/ScrapRepository.java @@ -0,0 +1,12 @@ +package org.terning.terningserver.repository.scarp; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.Scrap; + +import java.util.List; +import java.util.Optional; + +public interface ScrapRepository extends JpaRepository, ScrapRepositoryCustom { + Boolean existsByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); +} \ No newline at end of file diff --git a/src/main/java/org/terning/terningserver/repository/scarp/ScrapRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/scarp/ScrapRepositoryCustom.java new file mode 100644 index 0000000..120e179 --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/scarp/ScrapRepositoryCustom.java @@ -0,0 +1,12 @@ +package org.terning.terningserver.repository.scarp; + +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.Scrap; + +import java.util.List; + +public interface ScrapRepositoryCustom { + + List findAllByInternshipAndUserId(List internshipAnnouncements, Long userId); + +} diff --git a/src/main/java/org/terning/terningserver/repository/scarp/ScrapRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/scarp/ScrapRepositoryImpl.java new file mode 100644 index 0000000..b5177da --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/scarp/ScrapRepositoryImpl.java @@ -0,0 +1,24 @@ +package org.terning.terningserver.repository.scarp; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.Scrap; + +import java.util.List; +import static org.terning.terningserver.domain.QScrap.scrap; + + +@RequiredArgsConstructor +public class ScrapRepositoryImpl implements ScrapRepositoryCustom{ + + private final JPAQueryFactory jpaQueryFactory; + + @Override + public List findAllByInternshipAndUserId(List internshipAnnouncements, Long userId) { + return jpaQueryFactory + .selectFrom(scrap) + .where(scrap.internshipAnnouncement.in(internshipAnnouncements), scrap.user.id.eq(userId)) + .fetch(); + } +} diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index d1ad441..b8b777e 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -9,9 +9,15 @@ import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.domain.Scrap; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; +import org.terning.terningserver.dto.search.response.SearchResultResponse; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; +import org.terning.terningserver.repository.scarp.ScrapRepository; +import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -19,6 +25,7 @@ public class SearchService { private final InternshipRepository internshipRepository; + private final ScrapRepository scrapRepository; public PopularAnnouncementListResponse getMostViewedAnnouncements() { List mostViewedInternships = internshipRepository.getMostViewedInternship(); @@ -30,9 +37,26 @@ public PopularAnnouncementListResponse getMostScrappedAnnouncements() { return PopularAnnouncementListResponse.of(mostViewedInternships); } - public List searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { + public SearchResultResponse searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { List announcements = internshipRepository.searchInternshipAnnouncement(keyword, sortBy, pageable); - announcements.stream().map(announcement -> + + List searchAnnouncementResponses = new ArrayList<>(); + + List scraps = scrapRepository.findAllByInternshipAndUserId(announcements, 1L); + + //스크랩 정보를 매핑 (인턴 공고 ID -> 스크랩 ID) + Map scrapMap = scraps.stream() + .collect(Collectors.toMap( + scrap -> scrap.getInternshipAnnouncement().getId(), + Scrap::getId + )); + + + return new SearchResultResponse( + announcements.stream() + .map(a -> SearchResultResponse.SearchAnnouncementResponse.from(a, scrapMap.get(a.getId()))) + .collect(Collectors.toList()) + ); } } From 32437cdb818c9336822aa76c3784efc6a2eaad95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Sun, 14 Jul 2024 01:37:42 +0900 Subject: [PATCH 073/205] =?UTF-8?q?[=E2=9C=A8feat/#31]:=20User=20=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EB=B8=94=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - User 테이블 모든 필드 nullable=false 제거 --- .../terning/terningserver/domain/User.java | 7 ++----- .../terningserver/domain/enums/Grade.java | 3 ++- .../InternshipRepositoryImpl.java | 19 ++++++++++--------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/terning/terningserver/domain/User.java b/src/main/java/org/terning/terningserver/domain/User.java index c4cb7ee..16f2143 100644 --- a/src/main/java/org/terning/terningserver/domain/User.java +++ b/src/main/java/org/terning/terningserver/domain/User.java @@ -32,23 +32,20 @@ public class User extends BaseTimeEntity { @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private List scrapList = new ArrayList<>(); // 스크랩 공고 - @Column(nullable = false, length = 12) + @Column(length = 12) private String name; // 사용자 이름 // private String email; //이메일 - @Column(nullable = false) private int profileImage; @Enumerated(STRING) - @Column(nullable = false) private AuthType authType; // 인증 유형 (예: 카카오, 애플) - @Column(nullable = false, length = 256) + @Column(length = 256) private String authId; // 인증 서비스에서 제공하는 고유 ID @Enumerated(STRING) - @Column(nullable = false) private State state; // 사용자 상태 (예: 활성, 비활성, 정지) } diff --git a/src/main/java/org/terning/terningserver/domain/enums/Grade.java b/src/main/java/org/terning/terningserver/domain/enums/Grade.java index cd111ab..2532dbc 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/Grade.java +++ b/src/main/java/org/terning/terningserver/domain/enums/Grade.java @@ -1,8 +1,9 @@ package org.terning.terningserver.domain.enums; +import lombok.Getter; import lombok.RequiredArgsConstructor; - +@Getter @RequiredArgsConstructor public enum Grade { FRESHMAN(0, "1학년"), diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index 6b57154..716bba7 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -9,8 +9,12 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.enums.Grade; +import org.terning.terningserver.domain.enums.WorkingPeriod; import static org.terning.terningserver.domain.QInternshipAnnouncement.internshipAnnouncement; +import static org.terning.terningserver.domain.QUser.user; + import java.time.LocalDate; import java.util.List; @@ -48,9 +52,6 @@ public List getMostScrappedInternship() { public List searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { LocalDate today = LocalDate.now(); - // 현재 시점보다 마감일이 지난 경우 - BooleanExpression isExpired = internshipAnnouncement.deadline.before(today); - // 현재 시점보다 마감일이 지나지 않은 경우 BooleanExpression isNotExpired = internshipAnnouncement.deadline.goe(today); @@ -71,16 +72,16 @@ public List searchInternshipAnnouncement(String keyword, } private OrderSpecifier createOrderSpecifier(String sortBy) { return switch (sortBy) { - case "mostViewed" -> new OrderSpecifier<>(Order.DESC, internshipAnnouncement.viewCount); - case "shortestDuration" -> new OrderSpecifier<>(Order.ASC, getWorkingPeriodAsNumber()); - case "longestDuration" -> new OrderSpecifier<>(Order.DESC, getWorkingPeriodAsNumber()); - case "mostScrapped" -> new OrderSpecifier<>(Order.DESC, internshipAnnouncement.scrapCount); - default -> new OrderSpecifier<>(Order.ASC, internshipAnnouncement.deadline); + case "mostViewed" -> internshipAnnouncement.viewCount.desc(); + case "shortestDuration" -> getWorkingPeriodAsNumber().asc(); + case "longestDuration" -> getWorkingPeriodAsNumber().desc(); + case "mostScrapped" -> internshipAnnouncement.scrapCount.desc(); + default -> internshipAnnouncement.deadline.asc(); }; } /** - * String 타입의 workingPeriod를 숫자로 정렬하게 하기 위한 메서드 + * String 타입의 workingPeriod를 숫자로 정렬하게 하기 위한 메서드ㅜ₩ ₩₩₩₩₩₩ * @return */ private NumberTemplate getWorkingPeriodAsNumber() { From 7bc076a0a6c9c71c5e0750c01621a26d10b0ffac Mon Sep 17 00:00:00 2001 From: Willy Date: Sun, 14 Jul 2024 02:58:09 +0900 Subject: [PATCH 074/205] =?UTF-8?q?[=E2=9C=A8feat/#25]=20=ED=99=88?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20>=20=EB=94=B1=20=EB=A7=9E=EB=8A=94=20?= =?UTF-8?q?=EB=8C=80=ED=95=99=EC=83=9D=20=EC=9D=B8=ED=84=B4=20=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/controller/Empty.txt | 0 .../controller/HomeController.java | 31 +++++ .../controller/swagger/Empty.txt | 0 .../controller/swagger/HomeSwagger.java | 28 ++++ .../terning/terningserver/domain/Company.java | 7 + .../terning/terningserver/domain/Filter.java | 5 +- .../domain/InternshipAnnouncement.java | 17 ++- .../terning/terningserver/domain/Scrap.java | 4 +- .../terning/terningserver/domain/User.java | 5 +- .../terningserver/domain/enums/Grade.java | 2 + .../domain/enums/WorkingPeriod.java | 2 + .../terningserver/dto/user/response/Empty.txt | 0 .../dto/user/response/HomeResponseDto.java | 29 +++++ .../exception/enums/ErrorMessage.java | 5 +- .../exception/enums/SuccessMessage.java | 8 +- .../terningserver/repository/Empty.txt | 0 .../InternshipRepository.java | 7 + .../InternshipRepositoryCustom.java | 14 ++ .../InternshipRepositoryImpl.java | 120 ++++++++++++++++++ .../repository/scrap/ScrapRespository.java | 9 ++ .../repository/user/UserRepository.java | 7 + .../terning/terningserver/service/Empty.txt | 0 .../terningserver/service/HomeService.java | 10 ++ .../service/HomeServiceImpl.java | 45 +++++++ .../terning/terningserver/util/DateUtil.java | 22 ++++ src/main/resources/application-dev.yml | 1 + 26 files changed, 362 insertions(+), 16 deletions(-) delete mode 100644 src/main/java/org/terning/terningserver/controller/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/controller/HomeController.java delete mode 100644 src/main/java/org/terning/terningserver/controller/swagger/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java delete mode 100644 src/main/java/org/terning/terningserver/dto/user/response/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java delete mode 100644 src/main/java/org/terning/terningserver/repository/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java create mode 100644 src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java create mode 100644 src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java create mode 100644 src/main/java/org/terning/terningserver/repository/scrap/ScrapRespository.java create mode 100644 src/main/java/org/terning/terningserver/repository/user/UserRepository.java delete mode 100644 src/main/java/org/terning/terningserver/service/Empty.txt create mode 100644 src/main/java/org/terning/terningserver/service/HomeService.java create mode 100644 src/main/java/org/terning/terningserver/service/HomeServiceImpl.java create mode 100644 src/main/java/org/terning/terningserver/util/DateUtil.java diff --git a/src/main/java/org/terning/terningserver/controller/Empty.txt b/src/main/java/org/terning/terningserver/controller/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/controller/HomeController.java b/src/main/java/org/terning/terningserver/controller/HomeController.java new file mode 100644 index 0000000..4c83749 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/HomeController.java @@ -0,0 +1,31 @@ +package org.terning.terningserver.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.terning.terningserver.controller.swagger.HomeSwagger; +import org.terning.terningserver.dto.user.response.HomeResponseDto; +import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.exception.enums.SuccessMessage; +import org.terning.terningserver.service.HomeService; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class HomeController implements HomeSwagger { + + private final HomeService homeService; + + @GetMapping("/home") + public ResponseEntity>> getAnnouncements( + @RequestHeader("Authorization") String token, + @RequestParam(value = "sortBy", required = false, defaultValue = "deadlineSoon") String sortBy, + @RequestParam("startYear") int startYear, + @RequestParam("startMonth") int startMonth + ){ + List announcements = homeService.getAnnouncements(token, sortBy, startYear, startMonth); + return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.SUCCESS_GET_ANNOUNCEMENTS, announcements)); + } +} diff --git a/src/main/java/org/terning/terningserver/controller/swagger/Empty.txt b/src/main/java/org/terning/terningserver/controller/swagger/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java new file mode 100644 index 0000000..b15c1e7 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java @@ -0,0 +1,28 @@ +package org.terning.terningserver.controller.swagger; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.terning.terningserver.dto.user.response.HomeResponseDto; +import org.terning.terningserver.exception.dto.SuccessResponse; + +import java.util.List; + +@Tag(name = "Home", description = "홈화면 관련 API") +public interface HomeSwagger { + + @Operation(summary = "홈화면 > 나에게 딱맞는 인턴 공고 조회", description = "특정 사용자에 필터링 조건에 맞는 인턴 공고 정보를 조회하는 API") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "인턴 공고를 성공적으로 조회했습니다.", content = + @Content(mediaType = "application/json")) + }) + ResponseEntity>> getAnnouncements( + String token, + String sortBy, + int startYear, + int startMonth + ); +} diff --git a/src/main/java/org/terning/terningserver/domain/Company.java b/src/main/java/org/terning/terningserver/domain/Company.java index aa11de8..6426b6d 100644 --- a/src/main/java/org/terning/terningserver/domain/Company.java +++ b/src/main/java/org/terning/terningserver/domain/Company.java @@ -5,9 +5,16 @@ import jakarta.persistence.Embeddable; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; import org.terning.terningserver.domain.enums.CompanyCategory; +import static lombok.AccessLevel.PROTECTED; + @Embeddable +@Getter +@NoArgsConstructor(access = PROTECTED) public class Company { @Column(nullable = false, length = 64) diff --git a/src/main/java/org/terning/terningserver/domain/Filter.java b/src/main/java/org/terning/terningserver/domain/Filter.java index a9554d9..ac8431a 100644 --- a/src/main/java/org/terning/terningserver/domain/Filter.java +++ b/src/main/java/org/terning/terningserver/domain/Filter.java @@ -26,6 +26,7 @@ public class Filter { @Column(nullable = false) private WorkingPeriod workingPeriod; - @Column(nullable = false) - private YearMonth startDate; + private int startYear; // 근무 시작 연도 + + private int startMonth; // 근무 시작 월 } diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java index 328b80b..8efb0fb 100644 --- a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -5,8 +5,11 @@ import lombok.NoArgsConstructor; import org.terning.terningserver.domain.common.BaseTimeEntity; +import java.time.LocalDate; import java.time.YearMonth; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import static jakarta.persistence.GenerationType.IDENTITY; import static lombok.AccessLevel.PROTECTED; @@ -23,12 +26,16 @@ public class InternshipAnnouncement extends BaseTimeEntity { @Column(nullable = false, length = 64) private String title; // 인턴십 제목 - private Date deadline; // 지원 마감일 + private LocalDate deadline; // 지원 마감일 @Column(length = 16) private String workingPeriod; // 근무 기간 - private YearMonth startDate; // 시작 날짜 + @Column(nullable = false) + private int startYear; // 시작 연도 + + @Column(nullable = false) + private int startMonth; // 시작 월 @Column(nullable = false) private int viewCount; // 조회 수 @@ -50,4 +57,10 @@ public class InternshipAnnouncement extends BaseTimeEntity { @Column(columnDefinition = "TEXT") private String detail; // 상세 내용 + + @Column(nullable = false) + private boolean isGraduating; // 졸업 예정 여부 + + @OneToMany(mappedBy = "internshipAnnouncement", cascade = CascadeType.ALL) + private List scrapList = new ArrayList<>(); //스크랩 리스트 } diff --git a/src/main/java/org/terning/terningserver/domain/Scrap.java b/src/main/java/org/terning/terningserver/domain/Scrap.java index c46bf9e..0c4b0a3 100644 --- a/src/main/java/org/terning/terningserver/domain/Scrap.java +++ b/src/main/java/org/terning/terningserver/domain/Scrap.java @@ -26,8 +26,8 @@ public class Scrap extends BaseTimeEntity { @JoinColumn(name = "user_id", nullable = false) private User user; // 스크랩한 사용자 - @OneToOne(fetch = LAZY) - @JoinColumn(name = "internshipAnnouncement_id", nullable = false) + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "internship_announcement_id", nullable = false) private InternshipAnnouncement internshipAnnouncement; // 스크랩한 인턴십 공고 @Enumerated(STRING) diff --git a/src/main/java/org/terning/terningserver/domain/User.java b/src/main/java/org/terning/terningserver/domain/User.java index 11351a9..0ba4cac 100644 --- a/src/main/java/org/terning/terningserver/domain/User.java +++ b/src/main/java/org/terning/terningserver/domain/User.java @@ -35,9 +35,8 @@ public class User extends BaseTimeEntity { @Column(nullable = false, length = 12) private String name; // 사용자 이름 -// private String email; //이메일 - -// private String userImage; //유저 아이콘 + @Column(nullable = false) + private int profileImage; //유저 아이콘 @Enumerated(STRING) @Column(nullable = false) diff --git a/src/main/java/org/terning/terningserver/domain/enums/Grade.java b/src/main/java/org/terning/terningserver/domain/enums/Grade.java index cd111ab..ab7acf1 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/Grade.java +++ b/src/main/java/org/terning/terningserver/domain/enums/Grade.java @@ -1,8 +1,10 @@ package org.terning.terningserver.domain.enums; +import lombok.Getter; import lombok.RequiredArgsConstructor; +@Getter @RequiredArgsConstructor public enum Grade { FRESHMAN(0, "1학년"), diff --git a/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java b/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java index 48e9e21..a5add77 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java +++ b/src/main/java/org/terning/terningserver/domain/enums/WorkingPeriod.java @@ -1,8 +1,10 @@ package org.terning.terningserver.domain.enums; +import lombok.Getter; import lombok.RequiredArgsConstructor; +@Getter @RequiredArgsConstructor public enum WorkingPeriod { OPTION1(0, "1개월 ~ 3개월"), diff --git a/src/main/java/org/terning/terningserver/dto/user/response/Empty.txt b/src/main/java/org/terning/terningserver/dto/user/response/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java b/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java new file mode 100644 index 0000000..a38a182 --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java @@ -0,0 +1,29 @@ +package org.terning.terningserver.dto.user.response; + +import lombok.Builder; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.util.DateUtil; + +@Builder +public record HomeResponseDto( + Long intershipAnnouncementId, + String title, + String dDay, + String workingPeriod, + String companyImage, + boolean isScrapped +) { + public static HomeResponseDto of(final InternshipAnnouncement internshipAnnouncement, final boolean isScrapped){ + String dDay = DateUtil.convert(internshipAnnouncement.getDeadline()); // dDay 계산 로직 추가 + + return HomeResponseDto.builder() + .intershipAnnouncementId(internshipAnnouncement.getId()) + .title(internshipAnnouncement.getTitle()) + .dDay(dDay) + .workingPeriod(internshipAnnouncement.getWorkingPeriod()) + .companyImage(internshipAnnouncement.getCompany().getCompanyImage()) + .isScrapped(isScrapped) + .build(); + } + +} diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index 77d8202..1b56bcd 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -7,8 +7,9 @@ @AllArgsConstructor public enum ErrorMessage { - NOT_FOUND_INTERN_CATEGORY(404, "해당 인턴 공고는 존재하지 않습니다."), - WRONG_PERIOD(404, "해당 단어가 존재하지 않습니다."); + NOT_FOUND_INTERN_CATEGORY(404, "해당 인턴 공고는 존재하지 않습니다"), + WRONG_PERIOD(404, "해당 단어가 존재하지 않습니다"), + NOT_FOUND_USER_EXCEPTION(404, "해당 유저가 존재하지 않습니다"); private final int status; private final String message; diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 5d6594d..8489d39 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -6,12 +6,10 @@ @Getter @AllArgsConstructor public enum SuccessMessage { + // 홈 화면 + SUCCESS_GET_ANNOUNCEMENTS(200, "인턴 공고 불러오기를 성공했습니다"), - SUCCESS_CREATE_CATEGORY(201, "카테고리를 성공적으로 추가하였습니다."), - SUCCESS_GET_CATEGORIES(200, "카테고리 리스트 조회를 성공하였습니다."), - SUCCESS_CREATE_WORD(201, "단어를 성공적으로 추가하였습니다."), - SUCCESS_GET_WORDS(200, "단어 리스트 조회를 성공하였습니다."), - SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."); + ; private final int status; private final String message; diff --git a/src/main/java/org/terning/terningserver/repository/Empty.txt b/src/main/java/org/terning/terningserver/repository/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java new file mode 100644 index 0000000..50b8879 --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepository.java @@ -0,0 +1,7 @@ +package org.terning.terningserver.repository.InternshipAnnouncement; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.terning.terningserver.domain.InternshipAnnouncement; + +public interface InternshipRepository extends JpaRepository, InternshipRepositoryCustom { +} \ No newline at end of file diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java new file mode 100644 index 0000000..74055da --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryCustom.java @@ -0,0 +1,14 @@ +package org.terning.terningserver.repository.InternshipAnnouncement; + +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.User; + +import java.time.YearMonth; +import java.util.List; + +public interface InternshipRepositoryCustom { + List getMostViewedInternship(); + + List findFilteredInternships(User user, String sortBy, int startYear, int startMonth); + +} diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java new file mode 100644 index 0000000..26ed186 --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java @@ -0,0 +1,120 @@ +package org.terning.terningserver.repository.InternshipAnnouncement; + +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.*; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.QInternshipAnnouncement; +import org.terning.terningserver.domain.QUser; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.domain.enums.Grade; +import org.terning.terningserver.domain.enums.WorkingPeriod; +import org.terning.terningserver.util.DateUtil; + +import static org.terning.terningserver.domain.QInternshipAnnouncement.internshipAnnouncement; +import static org.terning.terningserver.domain.QScrap.scrap; +import static org.terning.terningserver.domain.QUser.user; + +import java.time.LocalDate; +import java.util.List; + +@RequiredArgsConstructor +public class InternshipRepositoryImpl implements InternshipRepositoryCustom { + + private final JPAQueryFactory jpaQueryFactory; + + @Override + public List getMostViewedInternship() { + return jpaQueryFactory + .selectFrom(internshipAnnouncement) + .where( + internDeadlineGoe(), + internCreatedAtAfter() + ) //지원 마감된 공고 및 30일 보다 오래된 공고 제외 + .orderBy(internshipAnnouncement.scrapCount.desc(), internshipAnnouncement.createdAt.desc()) + .fetch(); + } + + private BooleanExpression internDeadlineGoe() { + return internshipAnnouncement.deadline.goe(LocalDate.now()); + } + + private BooleanExpression internCreatedAtAfter() { + return internshipAnnouncement.createdAt.after(LocalDate.now().minusDays(30).atStartOfDay()); + } + + @Override + public List findFilteredInternships(User user, String sortBy, int startYear, int startMonth){ + return jpaQueryFactory + .selectFrom(internshipAnnouncement) + .leftJoin(internshipAnnouncement.scrapList, scrap).on(scrap.user.eq(user)) + .where( + getGraduatingFilter(user), + getWorkingPeriodFilter(user), + getStartDateFilter(startYear, startMonth) + ) + .orderBy( + priority.asc(), + getSortOrder(sortBy) + ) + .fetch(); + } + + private BooleanExpression getGraduatingFilter(User user){ + if(user.getFilter().getGrade() != Grade.SENIOR){ + return internshipAnnouncement.isGraduating.isFalse(); + } + return null; + } + + private BooleanExpression getWorkingPeriodFilter(User user){ + if(user.getFilter().getWorkingPeriod() == WorkingPeriod.OPTION1){ + return getWorkingPeriodAsNumber().between(1,3); + } else if(user.getFilter().getWorkingPeriod() == WorkingPeriod.OPTION2){ + return getWorkingPeriodAsNumber().between(4,6); + } else { + return getWorkingPeriodAsNumber().goe(7); + } + } + + private BooleanExpression getStartDateFilter(int startYear, int startMonth){ + return internshipAnnouncement.startYear.eq(startYear) + .and(internshipAnnouncement.startMonth.eq(startMonth)); + } + + // 정렬 옵션 (5가지) + private OrderSpecifier getSortOrder(String sortBy) { + return switch (sortBy) { + case "shortestDuration" // 짧은 근무 기간 순 + -> getWorkingPeriodAsNumber().asc(); + case "longestDuration" // 긴 근무 기간 순 + -> getWorkingPeriodAsNumber().desc(); + case "mostScrapped" // 스크랩 많은 순 + -> internshipAnnouncement.scrapCount.desc(); + case "mostViewed" // 조회 수 많은 순 + -> internshipAnnouncement.viewCount.desc(); + default // 채용 마감 이른 순 + -> internshipAnnouncement.deadline.asc(); + }; + } + + // 문자열 -> 숫자로 변경(순서 비교) + private NumberTemplate getWorkingPeriodAsNumber(){ + return Expressions.numberTemplate( + Integer.class, + "CAST(SUBSTRING({0}, 1, LENGTH({0}) - 2) AS INTEGER)", + internshipAnnouncement.workingPeriod + ); + } + + + //서류 마감일이 지난 공고는 가장 아래로 보여주는 로직 + BooleanExpression isNotExpired = internshipAnnouncement.deadline.goe(LocalDate.now()); + + NumberTemplate priority = Expressions.numberTemplate( + Integer.class, + "CASE WHEN {0} THEN 1 ELSE 2 END", + isNotExpired + ); +} diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRespository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRespository.java new file mode 100644 index 0000000..25a6036 --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRespository.java @@ -0,0 +1,9 @@ +package org.terning.terningserver.repository.scrap; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.terning.terningserver.domain.Scrap; + +public interface ScrapRespository extends JpaRepository { + + Boolean existsByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); +} diff --git a/src/main/java/org/terning/terningserver/repository/user/UserRepository.java b/src/main/java/org/terning/terningserver/repository/user/UserRepository.java new file mode 100644 index 0000000..711230f --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/user/UserRepository.java @@ -0,0 +1,7 @@ +package org.terning.terningserver.repository.user; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.terning.terningserver.domain.User; + +public interface UserRepository extends JpaRepository{ +} diff --git a/src/main/java/org/terning/terningserver/service/Empty.txt b/src/main/java/org/terning/terningserver/service/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/service/HomeService.java b/src/main/java/org/terning/terningserver/service/HomeService.java new file mode 100644 index 0000000..216c754 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/HomeService.java @@ -0,0 +1,10 @@ +package org.terning.terningserver.service; + +import org.terning.terningserver.dto.user.response.HomeResponseDto; + +import java.util.List; + +public interface HomeService { + + List getAnnouncements(String token, String sortBy, int startYear, int startMonth); +} diff --git a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java new file mode 100644 index 0000000..ed90bf8 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java @@ -0,0 +1,45 @@ +package org.terning.terningserver.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.dto.user.response.HomeResponseDto; +import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.exception.enums.ErrorMessage; +import org.terning.terningserver.repository.InternshipAnnouncement.InternshipRepository; +import org.terning.terningserver.repository.scrap.ScrapRespository; +import org.terning.terningserver.repository.user.UserRepository; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class HomeServiceImpl implements HomeService{ + + private final InternshipRepository internshipRepository; + private final UserRepository userRepository; + private final ScrapRespository scrapRepository; + + @Override + public List getAnnouncements(String token, String sortBy, int startYear, int startMonth){ + Long userId = getUserIdFromToken(token); + User user = userRepository.findById(userId).orElseThrow( + () -> new CustomException(ErrorMessage.NOT_FOUND_USER_EXCEPTION) + ); + List announcements = internshipRepository.findFilteredInternships(user, sortBy, startYear, startMonth); + + return announcements.stream() + .map(announcement -> { + boolean isScrapped = scrapRepository.existsByInternshipAnnouncementIdAndUserId(announcement.getId(), userId); + return HomeResponseDto.of(announcement, isScrapped); + }) + .collect(Collectors.toList()); + } + + private Long getUserIdFromToken(String token){ + //실제 토큰에서 userId를 가져오는 로직 구현 + return 1L; //임시로 사용자 ID 1로 반환 + } +} diff --git a/src/main/java/org/terning/terningserver/util/DateUtil.java b/src/main/java/org/terning/terningserver/util/DateUtil.java new file mode 100644 index 0000000..78f7998 --- /dev/null +++ b/src/main/java/org/terning/terningserver/util/DateUtil.java @@ -0,0 +1,22 @@ +package org.terning.terningserver.util; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +public class DateUtil { + + public static String convert(LocalDate deadline){ + ZonedDateTime nowInKorea = ZonedDateTime.now(ZoneId.of("Asia/Seoul")); + LocalDate currentDate = nowInKorea.toLocalDate(); + + if(deadline.isEqual(currentDate)) { + return "D-DAY"; + } else if (deadline.isBefore(currentDate)) { + return "지원 마감"; + } else { + long daysUntilDeadline = currentDate.until(deadline).getDays(); + return "D-" + daysUntilDeadline; + } + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 07ab368..7331780 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -27,6 +27,7 @@ spring: prometheus: enabled: true # Prometheus 메트릭스 리포터 활성화 여부 step: 60s # 측정 간격 + jpa: show-sql: true hibernate: From fe69f975bae16f033285348429ec812dcd5fbfba Mon Sep 17 00:00:00 2001 From: Willy Date: Sun, 14 Jul 2024 04:01:23 +0900 Subject: [PATCH 075/205] =?UTF-8?q?[=E2=9C=A8feat/#25]=20=ED=99=88?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20>=20=EB=94=B1=20=EB=A7=9E=EB=8A=94=20?= =?UTF-8?q?=EB=8C=80=ED=95=99=EC=83=9D=20=EC=9D=B8=ED=84=B4=20=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InternshipRepositoryImpl.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java index b20a9db..dd936aa 100644 --- a/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/InternshipAnnouncement/InternshipRepositoryImpl.java @@ -128,10 +128,6 @@ private NumberTemplate getWorkingPeriodAsNumber(){ isNotExpired ); - .orderBy(internshipAnnouncement.viewCount.desc(), internshipAnnouncement.createdAt.desc()) - .fetch(); - } - @Override public List getMostScrappedInternship() { return jpaQueryFactory @@ -143,15 +139,4 @@ public List getMostScrappedInternship() { .orderBy(internshipAnnouncement.scrapCount.desc(), internshipAnnouncement.createdAt.desc()) .fetch(); } - - //지원 마감일이 지나지 않은 공고 - private BooleanExpression internDeadlineGoe() { - return internshipAnnouncement.deadline.goe(LocalDate.now()); - } - - // 현재 시점으로부터 30일 이내의 공고 - private BooleanExpression internCreatedAtAfter() { - return internshipAnnouncement.createdAt.after(LocalDate.now().minusDays(30).atStartOfDay()); - } - } From 0d147d4a49c004e1d25f68c7dc2abf31681c1436 Mon Sep 17 00:00:00 2001 From: Willy Date: Sun, 14 Jul 2024 04:45:49 +0900 Subject: [PATCH 076/205] =?UTF-8?q?[=F0=9F=94=80merge/#25]=20Conflict=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/enums/ErrorMessage.java | 2 + .../exception/enums/SuccessMessage.java | 6 ++- .../InternshipRepositoryImpl.java | 42 +++++++------------ .../service/InternshipDetailService.java | 3 +- .../terning/terningserver/util/DateUtil.java | 7 +++- 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index 1b56bcd..88fbba2 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -7,7 +7,9 @@ @AllArgsConstructor public enum ErrorMessage { + //404(NotFound) NOT_FOUND_INTERN_CATEGORY(404, "해당 인턴 공고는 존재하지 않습니다"), + NOT_FOUND_INTERN_EXCEPTION(404, "해당 인턴 공고는 존재하지 않습니다"), WRONG_PERIOD(404, "해당 단어가 존재하지 않습니다"), NOT_FOUND_USER_EXCEPTION(404, "해당 유저가 존재하지 않습니다"); diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 77b9e68..a295e2d 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -9,9 +9,13 @@ public enum SuccessMessage { // 홈 화면 SUCCESS_GET_ANNOUNCEMENTS(200, "인턴 공고 불러오기를 성공했습니다"), + // Search (탐색 화면) SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다"), - SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS(200, "탐색 > 스크랩 수 많은 공고를 조회하는데 성공했습니다") + SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS(200, "탐색 > 스크랩 수 많은 공고를 조회하는데 성공했습니다"), + + // 인턴 공고 + SUCCESS_GET_INTERNSHIP_DETAIL(200, "공고 상세 정보 불러오기에 성공했습니다"); ; private final int status; diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index dd936aa..cdfb3fc 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.repository.InternshipAnnouncement; +package org.terning.terningserver.repository.internship_announcement; import com.querydsl.core.types.OrderSpecifier; @@ -6,29 +6,19 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; import org.terning.terningserver.domain.InternshipAnnouncement; -import org.terning.terningserver.domain.QInternshipAnnouncement; -import org.terning.terningserver.domain.QUser; import org.terning.terningserver.domain.User; import org.terning.terningserver.domain.enums.Grade; import org.terning.terningserver.domain.enums.WorkingPeriod; -import org.terning.terningserver.util.DateUtil; - -import static org.terning.terningserver.domain.QInternshipAnnouncement.internshipAnnouncement; -import static org.terning.terningserver.domain.QScrap.scrap; -import static org.terning.terningserver.domain.QUser.user; import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.jpa.impl.JPAQueryFactory; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; -import org.terning.terningserver.domain.InternshipAnnouncement; - -import static org.terning.terningserver.domain.QInternshipAnnouncement.internshipAnnouncement; import java.time.LocalDate; import java.util.List; +import static org.terning.terningserver.domain.QInternshipAnnouncement.internshipAnnouncement; +import static org.terning.terningserver.domain.QScrap.scrap; + @RequiredArgsConstructor public class InternshipRepositoryImpl implements InternshipRepositoryCustom { @@ -46,6 +36,18 @@ public List getMostViewedInternship() { .fetch(); } + @Override + public List getMostScrappedInternship() { + return jpaQueryFactory + .selectFrom(internshipAnnouncement) + .where( + internDeadlineGoe(), + internCreatedAtAfter() + ) //지원 마감된 공고 및 30일 보다 오래된 공고 제외 + .orderBy(internshipAnnouncement.scrapCount.desc(), internshipAnnouncement.createdAt.desc()) + .fetch(); + } + private BooleanExpression internDeadlineGoe() { return internshipAnnouncement.deadline.goe(LocalDate.now()); } @@ -127,16 +129,4 @@ private NumberTemplate getWorkingPeriodAsNumber(){ "CASE WHEN {0} THEN 1 ELSE 2 END", isNotExpired ); - - @Override - public List getMostScrappedInternship() { - return jpaQueryFactory - .selectFrom(internshipAnnouncement) - .where( - internDeadlineGoe(), - internCreatedAtAfter() - ) //지원 마감된 공고 및 30일 보다 오래된 공고 제외 - .orderBy(internshipAnnouncement.scrapCount.desc(), internshipAnnouncement.createdAt.desc()) - .fetch(); - } } diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java index 584205e..fbc04c5 100644 --- a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java @@ -7,6 +7,7 @@ import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.dto.internship_detail.InternshipDetailResponse; import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.exception.enums.ErrorMessage; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import org.terning.terningserver.repository.scrap.ScrapRepository; @@ -22,7 +23,7 @@ public class InternshipDetailService { public InternshipDetailResponse getInternshipDetail(Long internshipAnnouncementId) { InternshipAnnouncement announcement = internshipRepository.findById(internshipAnnouncementId) - .orElseThrow(() -> new CustomException(NOT_FOUND_INTERN_EXCEPTION)); + .orElseThrow(() -> new CustomException(ErrorMessage.NOT_FOUND_INTERN_EXCEPTION)); return InternshipDetailResponse.of( diff --git a/src/main/java/org/terning/terningserver/util/DateUtil.java b/src/main/java/org/terning/terningserver/util/DateUtil.java index 216ea22..2e7af41 100644 --- a/src/main/java/org/terning/terningserver/util/DateUtil.java +++ b/src/main/java/org/terning/terningserver/util/DateUtil.java @@ -3,7 +3,6 @@ import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.time.chrono.ChronoLocalDate; public class DateUtil { @@ -20,4 +19,10 @@ public static String convert(LocalDate deadline) { return "D-" + daysUntilDeadline; } } + + public static String convertDeadline(LocalDate deadline) { + return deadline.getYear() + "년 " + + deadline.getMonthValue() + "월 " + + deadline.getDayOfMonth() + "일"; + } } From 08230432222748de8a32bfa66f45ed462d6a6329 Mon Sep 17 00:00:00 2001 From: Willy Date: Sun, 14 Jul 2024 06:11:07 +0900 Subject: [PATCH 077/205] =?UTF-8?q?[=E2=9C=A8feat/#33]=20=ED=99=88?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20>=20=EC=98=A4=EB=8A=98=20=EB=A7=88?= =?UTF-8?q?=EA=B0=90=EB=90=98=EB=8A=94=20=EB=8C=80=ED=95=99=EC=83=9D=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B4=20=EA=B3=B5=EA=B3=A0=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/HomeController.java | 24 ++++++++++++- .../controller/swagger/HomeSwagger.java | 10 +++--- .../terningserver/domain/enums/Color.java | 4 +++ .../user/response/TodayScrapResponseDto.java | 34 +++++++++++++++++++ .../exception/enums/SuccessMessage.java | 2 +- .../repository/scrap/ScrapRepository.java | 3 ++ .../repository/scrap/ScrapRespository.java | 9 ----- .../service/HomeServiceImpl.java | 4 +-- .../terningserver/service/ScrapService.java | 9 +++++ .../service/ScrapServiceImpl.java | 25 ++++++++++++++ 10 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/dto/user/response/TodayScrapResponseDto.java delete mode 100644 src/main/java/org/terning/terningserver/repository/scrap/ScrapRespository.java create mode 100644 src/main/java/org/terning/terningserver/service/ScrapService.java create mode 100644 src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java diff --git a/src/main/java/org/terning/terningserver/controller/HomeController.java b/src/main/java/org/terning/terningserver/controller/HomeController.java index 4c83749..b213155 100644 --- a/src/main/java/org/terning/terningserver/controller/HomeController.java +++ b/src/main/java/org/terning/terningserver/controller/HomeController.java @@ -5,18 +5,26 @@ import org.springframework.web.bind.annotation.*; import org.terning.terningserver.controller.swagger.HomeSwagger; import org.terning.terningserver.dto.user.response.HomeResponseDto; +import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; +import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.exception.dto.ErrorResponse; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.exception.enums.SuccessMessage; import org.terning.terningserver.service.HomeService; +import org.terning.terningserver.service.ScrapService; import java.util.List; +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_ANNOUNCEMENTS; +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_TODAY_ANNOUNCEMENTS; + @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") public class HomeController implements HomeSwagger { private final HomeService homeService; + private final ScrapService scrapService; @GetMapping("/home") public ResponseEntity>> getAnnouncements( @@ -26,6 +34,20 @@ public ResponseEntity>> getAnnouncements( @RequestParam("startMonth") int startMonth ){ List announcements = homeService.getAnnouncements(token, sortBy, startYear, startMonth); - return ResponseEntity.ok(SuccessResponse.of(SuccessMessage.SUCCESS_GET_ANNOUNCEMENTS, announcements)); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_ANNOUNCEMENTS, announcements)); + } + + @GetMapping("/home/today") + public ResponseEntity>> getTodayScraps( + @RequestHeader("Authorization") String token + ){ + Long userId = getUserIdFromToken(token); + List scrapList = scrapService.getTodayScrap(userId); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_TODAY_ANNOUNCEMENTS, scrapList)); + } + + private Long getUserIdFromToken(String token){ + //실제 토큰에서 userId를 가져오는 로직 구현 + return 1L; //임시로 사용자 ID 1로 반환 } } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java index b15c1e7..7a30afd 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java @@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; import org.terning.terningserver.dto.user.response.HomeResponseDto; +import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; import java.util.List; @@ -15,14 +16,15 @@ public interface HomeSwagger { @Operation(summary = "홈화면 > 나에게 딱맞는 인턴 공고 조회", description = "특정 사용자에 필터링 조건에 맞는 인턴 공고 정보를 조회하는 API") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "인턴 공고를 성공적으로 조회했습니다.", content = - @Content(mediaType = "application/json")) - }) ResponseEntity>> getAnnouncements( String token, String sortBy, int startYear, int startMonth ); + + @Operation(summary = "홈화면 > 오늘 마감인 스크랩 공고 조회", description = "오늘 마감인 스크랩 공고를 조회하는 API") + ResponseEntity>> getTodayScraps( + String token + ); } diff --git a/src/main/java/org/terning/terningserver/domain/enums/Color.java b/src/main/java/org/terning/terningserver/domain/enums/Color.java index 123ed79..c8a5beb 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/Color.java +++ b/src/main/java/org/terning/terningserver/domain/enums/Color.java @@ -19,4 +19,8 @@ public enum Color { private final int key; private final String value; + + public String getColorValue() { + return "#" + value; + } } diff --git a/src/main/java/org/terning/terningserver/dto/user/response/TodayScrapResponseDto.java b/src/main/java/org/terning/terningserver/dto/user/response/TodayScrapResponseDto.java new file mode 100644 index 0000000..bfe228e --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/user/response/TodayScrapResponseDto.java @@ -0,0 +1,34 @@ +package org.terning.terningserver.dto.user.response; + +import lombok.Builder; +import org.terning.terningserver.domain.Scrap; +import org.terning.terningserver.util.DateUtil; + +@Builder +public record TodayScrapResponseDto( + Long scrapId, + Long internshipAnnouncementId, + String companyImage, + String title, + String dDay, + String deadline, + String workingPeriod, + String startYearMonth, + String color +) { + public static TodayScrapResponseDto of(final Scrap scrap){ + String startYearMonth = scrap.getInternshipAnnouncement().getStartYear() + "년 " + scrap.getInternshipAnnouncement().getStartMonth() + "월"; + + return TodayScrapResponseDto.builder() + .scrapId(scrap.getId()) + .internshipAnnouncementId(scrap.getInternshipAnnouncement().getId()) + .companyImage(scrap.getInternshipAnnouncement().getCompany().getCompanyImage()) + .title(scrap.getInternshipAnnouncement().getTitle()) + .dDay(DateUtil.convert(scrap.getInternshipAnnouncement().getDeadline())) + .deadline(DateUtil.convertDeadline(scrap.getInternshipAnnouncement().getDeadline())) + .workingPeriod(scrap.getInternshipAnnouncement().getWorkingPeriod()) + .startYearMonth(startYearMonth) + .color(scrap.getColor().getColorValue()) + .build(); + } +} diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index a295e2d..ba592d7 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -8,7 +8,7 @@ public enum SuccessMessage { // 홈 화면 SUCCESS_GET_ANNOUNCEMENTS(200, "인턴 공고 불러오기를 성공했습니다"), - + SUCCESS_GET_TODAY_ANNOUNCEMENTS(200, "오늘 마감인 인턴 공고 요청을 성공했습니다"), // Search (탐색 화면) SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다"), diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java index 7eaca34..f4648fd 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java @@ -3,9 +3,12 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.terning.terningserver.domain.Scrap; +import java.time.LocalDate; +import java.util.List; import java.util.Optional; public interface ScrapRepository extends JpaRepository { Boolean existsByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); + List findByUserIdAndInternshipAnnouncement_Deadline(Long userId, LocalDate deadline); } diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRespository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRespository.java deleted file mode 100644 index 25a6036..0000000 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRespository.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.terning.terningserver.repository.scrap; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.terning.terningserver.domain.Scrap; - -public interface ScrapRespository extends JpaRepository { - - Boolean existsByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); -} diff --git a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java index bed02f2..664c725 100644 --- a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java @@ -8,7 +8,7 @@ import org.terning.terningserver.exception.CustomException; import org.terning.terningserver.exception.enums.ErrorMessage; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; -import org.terning.terningserver.repository.scrap.ScrapRespository; +import org.terning.terningserver.repository.scrap.ScrapRepository; import org.terning.terningserver.repository.user.UserRepository; import java.util.List; @@ -20,7 +20,7 @@ public class HomeServiceImpl implements HomeService{ private final InternshipRepository internshipRepository; private final UserRepository userRepository; - private final ScrapRespository scrapRepository; + private final ScrapRepository scrapRepository; @Override public List getAnnouncements(String token, String sortBy, int startYear, int startMonth){ diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java new file mode 100644 index 0000000..d940a73 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -0,0 +1,9 @@ +package org.terning.terningserver.service; + +import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; + +import java.util.List; + +public interface ScrapService { + List getTodayScrap(Long userId); +} diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java new file mode 100644 index 0000000..71c14af --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -0,0 +1,25 @@ +package org.terning.terningserver.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; +import org.terning.terningserver.repository.scrap.ScrapRepository; + +import java.time.LocalDate; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class ScrapServiceImpl implements ScrapService { + + private final ScrapRepository scrapRepository; + + @Override + public List getTodayScrap(Long userId){ + LocalDate today = LocalDate.now(); + return scrapRepository.findByUserIdAndInternshipAnnouncement_Deadline(userId, today).stream() + .map(TodayScrapResponseDto::of) + .collect(Collectors.toList()); + } +} From afcb18219eacd56c1362c1ffff2e9ded3c2b3671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 03:06:52 +0900 Subject: [PATCH 078/205] =?UTF-8?q?[=F0=9F=93=82=C2=A0file/#31]:=20SearchS?= =?UTF-8?q?ervice=EC=99=80=20SearchServiceImpl=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/response/SearchResultResponse.java | 5 +- .../InternshipRepositoryCustom.java | 3 +- .../InternshipRepositoryImpl.java | 26 +++++++- .../terningserver/service/SearchService.java | 40 ++---------- .../service/SearchServiceImpl.java | 63 +++++++++++++++++++ 5 files changed, 97 insertions(+), 40 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/service/SearchServiceImpl.java diff --git a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java index 31abc09..96851ee 100644 --- a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java +++ b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java @@ -8,6 +8,8 @@ import java.util.stream.Collectors; public record SearchResultResponse( + int totalPages, + Boolean hasNext, List announcements ) { @Builder @@ -32,7 +34,8 @@ public static SearchAnnouncementResponse from(InternshipAnnouncement announcemen } } public static SearchResultResponse of(List announcements) { - return new SearchResultResponse(announcements); + public static SearchResultResponse of(int totalPages, Boolean hasNext, List announcements) { + return new SearchResultResponse(totalPages, hasNext, announcements); } } diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java index ecd0153..42a1ac7 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryCustom.java @@ -1,5 +1,6 @@ package org.terning.terningserver.repository.internship_announcement; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.terning.terningserver.domain.InternshipAnnouncement; @@ -10,5 +11,5 @@ public interface InternshipRepositoryCustom { List getMostScrappedInternship(); - List searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable); + Page searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable); } diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index 716bba7..6b59cea 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -7,6 +7,8 @@ import com.querydsl.core.types.dsl.NumberTemplate; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.domain.enums.Grade; @@ -49,7 +51,7 @@ public List getMostScrappedInternship() { } @Override - public List searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { + public Page searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { LocalDate today = LocalDate.now(); // 현재 시점보다 마감일이 지나지 않은 경우 @@ -62,14 +64,32 @@ public List searchInternshipAnnouncement(String keyword, isNotExpired ); - return jpaQueryFactory + List internshipAnnouncements = jpaQueryFactory .selectFrom(internshipAnnouncement) .leftJoin(internshipAnnouncement.scraps).fetchJoin() + .where(contentLike(keyword)) .orderBy(priority.asc(), createOrderSpecifier(sortBy)) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) .fetch(); + + Long count =jpaQueryFactory + .select(internshipAnnouncement.count()) + .from(internshipAnnouncement) + .leftJoin(internshipAnnouncement.scraps) + .where(contentLike(keyword)) + .fetchOne(); + + + return new PageImpl<>(internshipAnnouncements, pageable, count); } + + private BooleanExpression contentLike(String keyword) { + return internshipAnnouncement.title.contains(keyword); + } + + + //정렬 조건(5가지, 채용 마감 이른 순, 짧은 근무 기간 순, 긴 근무 기간 순, private OrderSpecifier createOrderSpecifier(String sortBy) { return switch (sortBy) { case "mostViewed" -> internshipAnnouncement.viewCount.desc(); @@ -81,7 +101,7 @@ private OrderSpecifier createOrderSpecifier(String sortBy) { } /** - * String 타입의 workingPeriod를 숫자로 정렬하게 하기 위한 메서드ㅜ₩ ₩₩₩₩₩₩ + * String 타입의 workingPeriod를 숫자로 정렬하게 하기 위한 메서드 * @return */ private NumberTemplate getWorkingPeriodAsNumber() { diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index b8b777e..1243014 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -19,44 +20,13 @@ import java.util.Optional; import java.util.stream.Collectors; -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class SearchService { - private final InternshipRepository internshipRepository; - private final ScrapRepository scrapRepository; +public interface SearchService { - public PopularAnnouncementListResponse getMostViewedAnnouncements() { - List mostViewedInternships = internshipRepository.getMostViewedInternship(); - return PopularAnnouncementListResponse.of(mostViewedInternships); - } + PopularAnnouncementListResponse getMostViewedAnnouncements(); - public PopularAnnouncementListResponse getMostScrappedAnnouncements() { - List mostViewedInternships = internshipRepository.getMostScrappedInternship(); - return PopularAnnouncementListResponse.of(mostViewedInternships); - } + PopularAnnouncementListResponse getMostScrappedAnnouncements(); - public SearchResultResponse searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { - List announcements = internshipRepository.searchInternshipAnnouncement(keyword, sortBy, pageable); - - List searchAnnouncementResponses = new ArrayList<>(); - - List scraps = scrapRepository.findAllByInternshipAndUserId(announcements, 1L); - - //스크랩 정보를 매핑 (인턴 공고 ID -> 스크랩 ID) - Map scrapMap = scraps.stream() - .collect(Collectors.toMap( - scrap -> scrap.getInternshipAnnouncement().getId(), - Scrap::getId - )); - - - return new SearchResultResponse( - announcements.stream() - .map(a -> SearchResultResponse.SearchAnnouncementResponse.from(a, scrapMap.get(a.getId()))) - .collect(Collectors.toList()) - ); - } + SearchResultResponse searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable); } diff --git a/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java b/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java new file mode 100644 index 0000000..548f044 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java @@ -0,0 +1,63 @@ +package org.terning.terningserver.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.Scrap; +import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; +import org.terning.terningserver.dto.search.response.SearchResultResponse; +import org.terning.terningserver.repository.internship_announcement.InternshipRepository; +import org.terning.terningserver.repository.scarp.ScrapRepository; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class SearchServiceImpl implements SearchService { + + private final InternshipRepository internshipRepository; + private final ScrapRepository scrapRepository; + + @Override + public PopularAnnouncementListResponse getMostViewedAnnouncements() { + List mostViewedInternships = internshipRepository.getMostViewedInternship(); + return PopularAnnouncementListResponse.of(mostViewedInternships); + } + + @Override + public PopularAnnouncementListResponse getMostScrappedAnnouncements() { + List mostViewedInternships = internshipRepository.getMostScrappedInternship(); + return PopularAnnouncementListResponse.of(mostViewedInternships); + } + + @Override + public SearchResultResponse searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { + Page pageAnnouncements = internshipRepository.searchInternshipAnnouncement(keyword, sortBy, pageable); + + List announcements = pageAnnouncements.getContent(); + + List searchAnnouncementResponses = new ArrayList<>(); + + List scraps = scrapRepository.findAllByInternshipAndUserId(announcements, 1L); + + //스크랩 정보를 매핑 (인턴 공고 ID -> 스크랩 ID) + Map scrapMap = scraps.stream() + .collect(Collectors.toMap( + scrap -> scrap.getInternshipAnnouncement().getId(), + Scrap::getId + )); + + return new SearchResultResponse( + pageAnnouncements.getTotalPages(), pageAnnouncements.hasNext(), announcements.stream() + .map(a -> SearchResultResponse.SearchAnnouncementResponse.from(a, scrapMap.get(a.getId()))) + .toList()); + } + +} From e924ebdd1a4185e4ee86dc442deb3664e4e834bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 03:11:12 +0900 Subject: [PATCH 079/205] =?UTF-8?q?[=E2=9A=B0=EF=B8=8F=C2=A0del/#31]:=20Sw?= =?UTF-8?q?agger=20-=20@ApiResponses=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 클라와 논의후 크게 이 어노테이션의 이점이 없다는 판단하에 제거했습니다. --- .../terningserver/controller/SearchController.java | 10 ++++++---- .../controller/swagger/SearchSwagger.java | 6 ------ .../terningserver/exception/enums/SuccessMessage.java | 3 ++- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index 4781d6b..acf9afa 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -20,8 +20,7 @@ import java.time.LocalDate; import java.util.List; -import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS; -import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS; +import static org.terning.terningserver.exception.enums.SuccessMessage.*; @RestController @@ -49,10 +48,13 @@ public ResponseEntity> getMostS } @GetMapping("/search") - public SearchResultResponse searchInternshipAnnouncement( + public ResponseEntity> searchInternshipAnnouncement( @RequestParam(value = "keyword", required = false) String keyword, @RequestParam("sortBy") String sortBy, Pageable pageable) { - return searchService.searchInternshipAnnouncement(keyword, sortBy, pageable); + return ResponseEntity.ok(SuccessResponse.of( + SUCCESS_GET_SEARCH_ANNOUNCEMENTS, + searchService.searchInternshipAnnouncement(keyword, sortBy, pageable) + )); } } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java index 7298c49..26a0d4c 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java @@ -14,17 +14,11 @@ public interface SearchSwagger { @Operation(summary = "탐색 > 지금 조회수 많은 공고", description = "탐색 화면에서 조회수 많은 공고를 불러오는 API") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "요청에 성공하였습니다.", content = @Content(mediaType = "application/json")) - }) ResponseEntity> getMostViewedAnnouncements( ); @Operation(summary = "탐색 > 지금 스크랩 수 많은 공고", description = "탐색 화면에서 스크랩 수 많은 공고를 불러오는 API") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "요청에 성공하였습니다.", content = @Content(mediaType = "application/json")) - }) ResponseEntity> getMostScrappedAnnouncements( ); diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 8eb213b..f86ffea 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -9,7 +9,8 @@ public enum SuccessMessage { // Search (탐색 화면) SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS(200, "탐색 > 조회수 많은 공고를 조회하는데 성공했습니다"), - SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS(200, "탐색 > 스크랩 수 많은 공고를 조회하는데 성공했습니다"); + SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS(200, "탐색 > 스크랩 수 많은 공고를 조회하는데 성공했습니다"), + SUCCESS_GET_SEARCH_ANNOUNCEMENTS(200, "검색에 성공했습니다"); private final int status; From 8b17eebeaf8cc1f169464132e6dee2f2b9aa596f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 03:13:19 +0900 Subject: [PATCH 080/205] =?UTF-8?q?[=E2=9C=A8feat/#31]:=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B2=B0=EA=B3=BC=ED=99=94=EB=A9=B4=20Swagger=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/controller/swagger/SearchSwagger.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java index 26a0d4c..f3b78b6 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java @@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; +import org.terning.terningserver.dto.search.response.SearchResultResponse; import org.terning.terningserver.exception.dto.SuccessResponse; @Tag(name = "Search", description = "탐색 관련 API") @@ -22,4 +23,9 @@ ResponseEntity> getMostViewedAn ResponseEntity> getMostScrappedAnnouncements( ); + + @Operation(summary = "탐색 > 검색 결과 화면", description = "탐색 화면에서 인턴 공고를 검색하는 API") + ResponseEntity> searchInternshipAnnouncement( + + ); } From 72f8b28fa15fecf615d86e3ce6f30528a82268d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 12:48:02 +0900 Subject: [PATCH 081/205] =?UTF-8?q?[=E2=9C=85chore/#17]:=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C=20=ED=99=98=EA=B2=BD=20=EC=84=A4=EC=A0=95=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EB=B0=8F=20Q-Class=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EC=83=9D=EC=84=B1=20=EC=BD=94=EB=93=9C=20=EA=B0=B1?= =?UTF-8?q?=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - application-dev.yml 파일에서 개발 환경 설정을 조정함 - Q-Class 관련 자동 생성된 소스 코드를 최신 상태로 갱신 --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a402d02..05c52d9 100644 --- a/.gitignore +++ b/.gitignore @@ -189,4 +189,7 @@ Temporary Items # application.yml src/main/resources/application.yml -src/main/resources/application-dev.yml \ No newline at end of file +src/main/resources/application-dev.yml + +# Q-Class +src/main/generated \ No newline at end of file From f6fed36464dbb15101d6a9c6beb43884927fd067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 12:51:31 +0900 Subject: [PATCH 082/205] =?UTF-8?q?[=F0=9F=94=80merge/#17]:=20git=20pull?= =?UTF-8?q?=20from=20develop=20branch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generated/org/terning/terningserver/domain/QFilter.java | 4 +++- .../generated/org/terning/terningserver/domain/QUser.java | 4 ++++ src/main/java/org/terning/terningserver/controller/Empty.txt | 0 .../java/org/terning/terningserver/controller/api/Empty.txt | 0 4 files changed, 7 insertions(+), 1 deletion(-) delete mode 100644 src/main/java/org/terning/terningserver/controller/Empty.txt delete mode 100644 src/main/java/org/terning/terningserver/controller/api/Empty.txt diff --git a/src/main/generated/org/terning/terningserver/domain/QFilter.java b/src/main/generated/org/terning/terningserver/domain/QFilter.java index c9c3ec1..71f8301 100644 --- a/src/main/generated/org/terning/terningserver/domain/QFilter.java +++ b/src/main/generated/org/terning/terningserver/domain/QFilter.java @@ -23,7 +23,9 @@ public class QFilter extends EntityPathBase { public final NumberPath id = createNumber("id", Long.class); - public final ComparablePath startDate = createComparable("startDate", java.time.YearMonth.class); + public final NumberPath startMonth = createNumber("startMonth", Integer.class); + + public final NumberPath startYear = createNumber("startYear", Integer.class); public final EnumPath workingPeriod = createEnum("workingPeriod", org.terning.terningserver.domain.enums.WorkingPeriod.class); diff --git a/src/main/generated/org/terning/terningserver/domain/QUser.java b/src/main/generated/org/terning/terningserver/domain/QUser.java index 58ab814..8b76997 100644 --- a/src/main/generated/org/terning/terningserver/domain/QUser.java +++ b/src/main/generated/org/terning/terningserver/domain/QUser.java @@ -24,6 +24,8 @@ public class QUser extends EntityPathBase { public final org.terning.terningserver.domain.common.QBaseTimeEntity _super = new org.terning.terningserver.domain.common.QBaseTimeEntity(this); + public final StringPath authAccessToken = createString("authAccessToken"); + public final StringPath authId = createString("authId"); public final EnumPath authType = createEnum("authType", org.terning.terningserver.domain.enums.AuthType.class); @@ -40,6 +42,8 @@ public class QUser extends EntityPathBase { public final StringPath name = createString("name"); + public final NumberPath profileImage = createNumber("profileImage", Integer.class); + public final StringPath refreshToken = createString("refreshToken"); public final ListPath scrapList = this.createList("scrapList", Scrap.class, QScrap.class, PathInits.DIRECT2); diff --git a/src/main/java/org/terning/terningserver/controller/Empty.txt b/src/main/java/org/terning/terningserver/controller/Empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/org/terning/terningserver/controller/api/Empty.txt b/src/main/java/org/terning/terningserver/controller/api/Empty.txt deleted file mode 100644 index e69de29..0000000 From aa80e51aafe8574248e6bd3193abd568395cf2fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 12:53:56 +0900 Subject: [PATCH 083/205] =?UTF-8?q?[=E2=9A=B0=EF=B8=8Fdel/#17]:=20Service?= =?UTF-8?q?=20layer=20dto=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 코드의 복잡성을 줄이고 가독성을 키우기 위해 service layer의 dto를 제거. - 추후에 dto 방향 재설정 --- .../auth/request/SignInServiceRequest.java | 21 ------------------- .../auth/request/TokenGetServiceRequest.java | 18 ---------------- .../auth/response/SignInServiceResponse.java | 21 ------------------- .../response/TokenGetServiceResponse.java | 18 ---------------- 4 files changed, 78 deletions(-) delete mode 100644 src/main/java/org/terning/terningserver/domain/auth/request/SignInServiceRequest.java delete mode 100644 src/main/java/org/terning/terningserver/domain/auth/request/TokenGetServiceRequest.java delete mode 100644 src/main/java/org/terning/terningserver/domain/auth/response/SignInServiceResponse.java delete mode 100644 src/main/java/org/terning/terningserver/domain/auth/response/TokenGetServiceResponse.java diff --git a/src/main/java/org/terning/terningserver/domain/auth/request/SignInServiceRequest.java b/src/main/java/org/terning/terningserver/domain/auth/request/SignInServiceRequest.java deleted file mode 100644 index e964d79..0000000 --- a/src/main/java/org/terning/terningserver/domain/auth/request/SignInServiceRequest.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.terning.terningserver.domain.auth.request; - -import lombok.Builder; -import lombok.NonNull; -import org.terning.terningserver.domain.enums.AuthType; - -import static lombok.AccessLevel.*; - -@Builder(access = PRIVATE) -public record SignInServiceRequest( - @NonNull String authAccessToken, - @NonNull AuthType authType -) { - - public static SignInServiceRequest of(String authAccessToken, SignInRequest request) { - return SignInServiceRequest.builder() - .authAccessToken(authAccessToken) - .authType(request.authType()) - .build(); - } -} diff --git a/src/main/java/org/terning/terningserver/domain/auth/request/TokenGetServiceRequest.java b/src/main/java/org/terning/terningserver/domain/auth/request/TokenGetServiceRequest.java deleted file mode 100644 index 5e2c127..0000000 --- a/src/main/java/org/terning/terningserver/domain/auth/request/TokenGetServiceRequest.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.terning.terningserver.domain.auth.request; - -import lombok.Builder; -import lombok.NonNull; - -import static lombok.AccessLevel.*; - -@Builder(access = PRIVATE) -public record TokenGetServiceRequest( - @NonNull String refreshToken -) { - - public static TokenGetServiceRequest of(String refreshToken) { - return TokenGetServiceRequest.builder() - .refreshToken(refreshToken) - .build(); - } -} diff --git a/src/main/java/org/terning/terningserver/domain/auth/response/SignInServiceResponse.java b/src/main/java/org/terning/terningserver/domain/auth/response/SignInServiceResponse.java deleted file mode 100644 index 0476c57..0000000 --- a/src/main/java/org/terning/terningserver/domain/auth/response/SignInServiceResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.terning.terningserver.domain.auth.response; - -import lombok.Builder; -import lombok.NonNull; -import org.terning.terningserver.domain.Token; - -import static lombok.AccessLevel.PRIVATE; - -@Builder(access = PRIVATE) -public record SignInServiceResponse( - @NonNull String accessToken, - @NonNull String refreshToken -) { - - public static SignInServiceResponse of(Token token) { - return SignInServiceResponse.builder() - .accessToken(token.getAccessToken()) - .refreshToken(token.getRefreshToken()) - .build(); - } -} diff --git a/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetServiceResponse.java b/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetServiceResponse.java deleted file mode 100644 index 6de0e9d..0000000 --- a/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetServiceResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.terning.terningserver.domain.auth.response; - -import lombok.Builder; -import lombok.NonNull; - -import static lombok.AccessLevel.*; - -@Builder(access = PRIVATE) -public record TokenGetServiceResponse( - @NonNull String accessToken -) { - - public static TokenGetServiceResponse of(String accessToken) { - return TokenGetServiceResponse.builder() - .accessToken(accessToken) - .build(); - } -} From f66e749dca4ee8e64798a64131de189048fed08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 12:56:14 +0900 Subject: [PATCH 084/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Use?= =?UTF-8?q?rException=20->=20CustomException?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UserException 사용을 중단하고 CustomException을 사용하도록 변경 --- .../terningserver/exception/UserException.java | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/main/java/org/terning/terningserver/exception/UserException.java diff --git a/src/main/java/org/terning/terningserver/exception/UserException.java b/src/main/java/org/terning/terningserver/exception/UserException.java deleted file mode 100644 index 9abca99..0000000 --- a/src/main/java/org/terning/terningserver/exception/UserException.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.terning.terningserver.exception; - -import lombok.Getter; -import org.terning.terningserver.exception.enums.ErrorMessage; - -@Getter -public class UserException extends RuntimeException { - - private final ErrorMessage errorMessage; - - public UserException(ErrorMessage errorMessage) { - super("[UserException] : " + errorMessage.getMessage()); - this.errorMessage = errorMessage; - } -} From e0476aafad556cedbd6a0c14728dbc69debcc230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 12:57:17 +0900 Subject: [PATCH 085/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20ValueConfig?= =?UTF-8?q?=EC=97=90=20=EC=83=88=EB=A1=9C=EC=9A=B4=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - QUOTES와 POSITIVE_NUMBER라는 두 개의 상수를 ValueConfig 클래스에 추가 --- src/main/java/org/terning/terningserver/config/ValueConfig.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/terning/terningserver/config/ValueConfig.java b/src/main/java/org/terning/terningserver/config/ValueConfig.java index bbff185..34277b3 100644 --- a/src/main/java/org/terning/terningserver/config/ValueConfig.java +++ b/src/main/java/org/terning/terningserver/config/ValueConfig.java @@ -43,6 +43,8 @@ public class ValueConfig { public static final String RSA = "RSA"; public static final String KEY = "keys"; public static final String ID = "sub"; + public static final int QUOTES = 1; + public static final int POSITIVE_NUMBER = 1; @PostConstruct protected void init() { From 1bc9493ea073e3196d6be2eac6685764f86df5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:05:15 +0900 Subject: [PATCH 086/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20SignInResponse?= =?UTF-8?q?=20=EB=A0=88=EC=BD=94=EB=93=9C=EC=97=90=20userId=EC=99=80=20aut?= =?UTF-8?q?hType=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SignInResponse의 생성자 매개변수에 userId와 AuthType을 추가하여 인증 타입과 사용자 ID를 포함시킴 - 기존 Token 객체에서 accessToken과 refreshToken을 추출하여 사용하도록 변경 - 생성자 오버로딩을 통해 기존 Token과 함께 userId 및 authType도 인자로 받도록 수정 --- .../domain/auth/response/SignInResponse.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/domain/auth/response/SignInResponse.java b/src/main/java/org/terning/terningserver/domain/auth/response/SignInResponse.java index 252e9a0..7a35da1 100644 --- a/src/main/java/org/terning/terningserver/domain/auth/response/SignInResponse.java +++ b/src/main/java/org/terning/terningserver/domain/auth/response/SignInResponse.java @@ -2,18 +2,23 @@ import lombok.Builder; import org.terning.terningserver.domain.Token; +import org.terning.terningserver.domain.enums.AuthType; import static lombok.AccessLevel.PRIVATE; @Builder(access = PRIVATE) public record SignInResponse( String accessToken, - String refreshToken + String refreshToken, + Long userId, + AuthType authType ) { - public static SignInResponse of(Token token) { + public static SignInResponse of(Token token, Long userId, AuthType authType) { return SignInResponse.builder() .accessToken(token.getAccessToken()) .refreshToken(token.getRefreshToken()) + .userId(userId) + .authType(authType) .build(); } } From 3f94ef126c3271b789fceeab6cacc5ae9219ffec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:06:18 +0900 Subject: [PATCH 087/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Fil?= =?UTF-8?q?ter=20=ED=81=B4=EB=9E=98=EC=8A=A4=EC=9D=98=20startDate=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=EB=A5=BC=20startYear=EC=99=80=20startMonth?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Filter 클래스에서 YearMonth 타입의 startDate 필드를 제거하고, 정수 타입의 startYear와 startMonth 필드를 추가함 --- .../terning/terningserver/domain/Filter.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/domain/Filter.java b/src/main/java/org/terning/terningserver/domain/Filter.java index a9554d9..79389fb 100644 --- a/src/main/java/org/terning/terningserver/domain/Filter.java +++ b/src/main/java/org/terning/terningserver/domain/Filter.java @@ -1,6 +1,7 @@ package org.terning.terningserver.domain; import jakarta.persistence.*; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.terning.terningserver.domain.enums.Grade; @@ -27,5 +28,19 @@ public class Filter { private WorkingPeriod workingPeriod; @Column(nullable = false) - private YearMonth startDate; + private int startYear; + + @Column(nullable = false) + private int startMonth; + + + @Builder + public Filter(Long id, Grade grade, WorkingPeriod workingPeriod, int startYear, int startMonth) { + this.id = id; + this.grade = grade; + this.workingPeriod = workingPeriod; + this.startYear = startYear; + this.startMonth = startMonth; + } + } From 930595c243a3289faeb251350fc294771321f7b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:07:15 +0900 Subject: [PATCH 088/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Use?= =?UTF-8?q?r=20=ED=81=B4=EB=9E=98=EC=8A=A4=EC=97=90=20=ED=95=84=EB=93=9C?= =?UTF-8?q?=20=EB=B0=8F=20=EC=83=9D=EC=84=B1=EC=9E=90=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - @AllArgsConstructor 어노테이션 추가로 전체 속성 생성자 자동 생성 - 'filter_id' 필드의 @JoinColumn에서 nullable 제약 조건 제거 - 'name', 'authId' 필드에 대한 @Column 어노테이션에서 nullable 제약 조건을 제거하고, 문자열 길이 제약만 명시 - 'authAccessToken' 및 'refreshToken' 필드 추가로 인증 토큰 관리 개선 - 'updateRefreshToken' 메서드 내 예외 처리 로직 추가 --- .../terning/terningserver/domain/User.java | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/terning/terningserver/domain/User.java b/src/main/java/org/terning/terningserver/domain/User.java index 689e75e..5275ce7 100644 --- a/src/main/java/org/terning/terningserver/domain/User.java +++ b/src/main/java/org/terning/terningserver/domain/User.java @@ -1,13 +1,13 @@ package org.terning.terningserver.domain; import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; import org.terning.terningserver.domain.common.BaseTimeEntity; import org.terning.terningserver.domain.enums.AuthType; +import org.terning.terningserver.domain.enums.Grade; import org.terning.terningserver.domain.enums.State; +import org.terning.terningserver.domain.enums.WorkingPeriod; +import org.terning.terningserver.exception.CustomException; import java.util.ArrayList; import java.util.List; @@ -15,10 +15,13 @@ import static jakarta.persistence.EnumType.STRING; import static jakarta.persistence.FetchType.LAZY; import static jakarta.persistence.GenerationType.IDENTITY; +import static org.terning.terningserver.exception.enums.ErrorMessage.*; @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@Builder @Table(name = "Users") public class User extends BaseTimeEntity { @@ -27,44 +30,63 @@ public class User extends BaseTimeEntity { private Long id; // 사용자 고유 ID @OneToOne(fetch = LAZY) - @JoinColumn(name="filter_id", nullable = false) + @JoinColumn(name="filter_id") private Filter filter; // 사용자 필터 설정 @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private List scrapList = new ArrayList<>(); // 스크랩 공고 - @Column(nullable = false, length = 12) + // TODO: 특수문자, 첫글자 , 12자리 이내 + @Column(length = 12) private String name; // 사용자 이름 -// private String email; //이메일 - -// private String userImage; //유저 아이콘 + private Integer profileImage; //유저 아이콘 @Enumerated(STRING) - @Column(nullable = false) private AuthType authType; // 인증 유형 (예: 카카오, 애플) - @Column(nullable = false, length = 256) + @Column(length = 256) private String authId; // 인증 서비스에서 제공하는 고유 ID + @Column(length = 256) + private String authAccessToken; // 엑세스 토큰 + + @Column(length = 256) private String refreshToken; // 리프레시 토큰 + // TODO: User가 생기면 active default로 바꾸기 @Enumerated(STRING) - @Column(nullable = false) private State state; // 사용자 상태 (예: 활성, 비활성, 정지) - @Builder - public User(AuthType authType, String authId) { - this.authType = authType; - this.authId = authId; - } public void updateRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } public void resetRefreshToken() { - this.refreshToken = null; + try { + this.refreshToken = null; + } catch (Exception e) { + throw new CustomException(REFRESH_TOKEN_RESET_FAILED); + } } + public void updateProfile(String name, Integer profileImage) { + if (name != null && !name.isEmpty()) { + this.name = name; + } + if (profileImage != null) { + this.profileImage = profileImage; + } + } + + @Builder + public void updateFilter(Grade grade, WorkingPeriod workingPeriod, int startYear, int startMonth) { + this.filter = Filter.builder() + .grade(grade) + .workingPeriod(workingPeriod) + .startYear(startYear) + .startMonth(startMonth) + .build(); + } } From 6a7f9eaa4bb5b3ac0d7cc514dd61039a32c5e6ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:08:09 +0900 Subject: [PATCH 089/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20ErrorMessage=20?= =?UTF-8?q?=EC=97=B4=EA=B1=B0=ED=98=95=EC=97=90=20=EC=83=88=EB=A1=9C?= =?UTF-8?q?=EC=9A=B4=20=EC=97=90=EB=9F=AC=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 소셜 로그인 관련 에러 메시지 추가 및 업데이트 - `INVALID_TOKEN`, `INVALID_KEY`, `SOCIAL_LOGIN_FAILED` 등 기존 메시지 정리 - `TOKEN_REISSUE_FAILED` 메시지 추가로 토큰 재발급 실패 시나리오 처리 - 회원가입 및 로그인 프로세스 강화: - `SIGN_UP_FAILED`, `USER_ALREADY_EXISTS` 에러 메시지 추가로 회원가입 실패 및 중복 가입 관리 - 사용자 필터링 정보 생성, 로그아웃, 계정 탈퇴 관련 에러 메시지 추가: - `SIGN_UP_FILTER_FAILED`, `SIGN_OUT_FAILED`, `REFRESH_TOKEN_RESET_FAILED`, `WITHDRAW_FAILED` 메시지 추가로 각 시나리오별 에러 처리 강화 --- .../exception/enums/ErrorMessage.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index a0911b9..dbac32f 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -7,10 +7,26 @@ @AllArgsConstructor public enum ErrorMessage { + // 소셜 로그인 INVALID_TOKEN(401, "유효하지 않은 토큰입니다."), INVALID_KEY(401, "유효하지 않은 키입니다."), + SOCIAL_LOGIN_FAILED(404, "소셜 로그인애 실패하였습니다"), + INVALID_USER(404, "유효하지 않은 유저입니다."), + TOKEN_REISSUE_FAILED(404, "토큰 재발급에 실패하였습니다."), - INVALID_USER(404, "유효하지 않은 유저입니다."); + // 회원가입 + SIGN_UP_FAILED(401, "회원가입에 실패하였습니다"), + USER_ALREADY_EXISTS(401, "이미 존재하는 유저입니다"), + + // 사용자 필터링 정보 생성 + SIGN_UP_FILTER_FAILED(404, "회원가입 필터링 정보 생성에 실패하였습니다"), + + // 로그 아웃 + SIGN_OUT_FAILED(404, "로그아웃에 실패하였습니다"), + REFRESH_TOKEN_RESET_FAILED(400, "리프레쉬 토큰 초기화에 실패하였습니다"), + + // 계정 탈퇴 + WITHDRAW_FAILED(404, "계정 탈퇴에 실패하였습니다"); private final int status; private final String message; From 7806a04e65046cde8bf466d123e1cf23a2818fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:08:44 +0900 Subject: [PATCH 090/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20SuccessMessage?= =?UTF-8?q?=20=EC=97=B4=EA=B1=B0=ED=98=95=EC=97=90=20=EC=83=88=EB=A1=9C?= =?UTF-8?q?=EC=9A=B4=20=EC=84=B1=EA=B3=B5=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 다양한 API 작업에 대한 성공 메시지 확장: - `SUCCESS_SIGN_IN`, `SUCCESS_REISSUE_TOKEN`, `SUCCESS_SIGN_UP`, `SUCCESS_SIGN_UP_FILTER`, `SUCCESS_SIGN_OUT`, `SUCCESS_REFRESH_TOKEN_RESET`, `SUCCESS_WITHDRAW` 추가 - 각 메시지는 특정 작업의 성공을 알리며, 관련 상태 코드와 설명이 함께 제공됨 --- .../exception/enums/SuccessMessage.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 5d6594d..ed7bb20 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -11,7 +11,27 @@ public enum SuccessMessage { SUCCESS_GET_CATEGORIES(200, "카테고리 리스트 조회를 성공하였습니다."), SUCCESS_CREATE_WORD(201, "단어를 성공적으로 추가하였습니다."), SUCCESS_GET_WORDS(200, "단어 리스트 조회를 성공하였습니다."), - SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."); + SUCCESS_GET_WORD(200, "특정 단어 조회를 성공하였습니다."), + + // 소셜 로그인 + SUCCESS_SIGN_IN(200, "소셜 로그인에 성공하였습니다"), + + // 토큰 재발급 + SUCCESS_REISSUE_TOKEN(200, "토큰 재발급에 성공하였습니다."), + + // 회원가입 + SUCCESS_SIGN_UP(201, "회원가입에 성공하였습니다"), + + // 사용자 정보 필터링 + SUCCESS_SIGN_UP_FILTER(200, "사용자 필터링 정보 생성에 성공하였습니다"), + + // 로그 아웃 + SUCCESS_SIGN_OUT(200, "로그아웃에 성공하였습니다"), + SUCCESS_REFRESH_TOKEN_RESET(200, "리프레쉬 토큰 초기화에 성공하였습니다"), + + // 계정 탈퇴 + SUCCESS_WITHDRAW(200, "계정 탈퇴에 성공하였습니다"); + private final int status; private final String message; From 67faf306614a4739758ac6a5dcba24dc12ae8567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:09:26 +0900 Subject: [PATCH 091/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20JWT?= =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=20=EC=8B=A4=ED=8C=A8=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=EC=9D=84=20CustomException=EC=9D=84=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `CustomJwtAuthenticationEntryPoint` 클래스의 응답 생성 부분에서 `ErrorResponse` 객체 대신 `CustomException` 객체를 사용하도록 수정 --- .../terningserver/jwt/CustomJwtAuthenticationEntryPoint.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/terning/terningserver/jwt/CustomJwtAuthenticationEntryPoint.java b/src/main/java/org/terning/terningserver/jwt/CustomJwtAuthenticationEntryPoint.java index d19c1a4..b719b5d 100644 --- a/src/main/java/org/terning/terningserver/jwt/CustomJwtAuthenticationEntryPoint.java +++ b/src/main/java/org/terning/terningserver/jwt/CustomJwtAuthenticationEntryPoint.java @@ -1,14 +1,13 @@ package org.terning.terningserver.jwt; import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; -import org.terning.terningserver.exception.dto.ErrorResponse; +import org.terning.terningserver.exception.CustomException; import java.io.IOException; @@ -35,6 +34,6 @@ private void setResponse(HttpServletResponse response) throws IOException { response.setCharacterEncoding("UTF-8"); response.setContentType(APPLICATION_JSON_VALUE); response.setStatus(SC_UNAUTHORIZED); - response.getWriter().println(objectMapper.writeValueAsString(ErrorResponse.of(INVALID_TOKEN.getStatus(), INVALID_TOKEN.getMessage()))); + response.getWriter().println(objectMapper.writeValueAsString(new CustomException(INVALID_TOKEN))); } } From 010eab7df142e0ec51a2ec1555f2a8803fcae669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:11:11 +0900 Subject: [PATCH 092/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Jwt?= =?UTF-8?q?AuthenticationFilter=20=ED=81=B4=EB=9E=98=EC=8A=A4=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=95=84=ED=84=B0=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0=20=EB=B0=8F=20=EC=A4=91=EB=B3=B5=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `JwtAuthenticationFilter` 클래스의 `jwtTokenProvider` 필드를 final로 선언하여 불변성 강화 - `doFilterInternal` 메서드 내에서 토큰 유효성 검사 로직을 간결하게 조정하여 가독성 향상 - 중복되는 `getUserId` 메서드를 제거하고, 토큰에서 사용자 ID를 추출하는 로직을 한 곳에서만 관리하도록 변경 - 요청에서 액세스 토큰을 가져오는 `getAccessTokenFromRequest` 메서드에서의 접근 방식을 일관되게 조정하여 코드의 통일성 유지 --- .../terningserver/jwt/JwtAuthenticationFilter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java b/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java index 86a7594..8ce185b 100644 --- a/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/org/terning/terningserver/jwt/JwtAuthenticationFilter.java @@ -24,11 +24,10 @@ @RequiredArgsConstructor public class JwtAuthenticationFilter extends OncePerRequestFilter { - private static JwtTokenProvider jwtTokenProvider; + private final JwtTokenProvider jwtTokenProvider; @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { val token = getAccessTokenFromRequest(request); if (hasText(token) && jwtTokenProvider.validateToken(token) == VALID_JWT) { @@ -43,6 +42,10 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse filterChain.doFilter(request, response); } + private long getUserId(String token) { + return jwtTokenProvider.getUserFromJwt(token); + } + private String getAccessTokenFromRequest(HttpServletRequest request) { return isContainsAccessToken(request) ? getAuthorizationAccessToken(request) : null; } @@ -60,7 +63,4 @@ private String getTokenFromBearerString(String token) { return token.replaceFirst(ValueConfig.BEARER_HEADER, ValueConfig.BLANK); } - private long getUserId(String token) { - return jwtTokenProvider.getUserFromJwt(token); - } } From eb3ab8c31b032efdee5dbd2ed330e2af1d4b78a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:11:51 +0900 Subject: [PATCH 093/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Jwt?= =?UTF-8?q?TokenProvider=20=ED=81=B4=EB=9E=98=EC=8A=A4=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20JSON=20?= =?UTF-8?q?=EC=9C=A0=ED=8B=B8=EB=A6=AC=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `JSONUtils` 라이브러리 추가하여 JSON 관련 작업을 간소화하고자 함 - `getSigningKey` 메서드의 중복 정의 제거하여 코드의 중복성 감소 - `getUserFromJwt` 메서드 및 `getBody` 메서드의 로직에 대한 작은 정리를 통해 코드 유지관리 향상 --- .../terning/terningserver/jwt/JwtTokenProvider.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java b/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java index 7e80c27..7677f23 100644 --- a/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java +++ b/src/main/java/org/terning/terningserver/jwt/JwtTokenProvider.java @@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; +import nonapi.io.github.classgraph.json.JSONUtils; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; import org.terning.terningserver.config.ValueConfig; @@ -59,11 +60,6 @@ private Claims generateClaims(Authentication authentication) { return claims; } - private SecretKey getSigningKey() { - val encodedKey = getEncoder().encodeToString(valueConfig.getSecretKey().getBytes()); - return hmacShaKeyFor(encodedKey.getBytes()); - } - public Long getUserFromJwt(String token) { val claims = getBody(token); return Long.parseLong(claims.get("userId").toString()); @@ -76,4 +72,10 @@ private Claims getBody(final String token) { .parseClaimsJws(token) .getBody(); } + + private SecretKey getSigningKey() { + val encodedKey = getEncoder().encodeToString(valueConfig.getSecretKey().getBytes()); + return hmacShaKeyFor(encodedKey.getBytes()); + } + } From 4f87a1e4d6a200c663643276a06e9d0d189e0d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:13:19 +0900 Subject: [PATCH 094/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20JWT=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20=EC=9C=A0=ED=98=95?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20enum=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - JwtValidationType enum 추가로 JWT 유효성 검사 상태 명확화 - `INVALID_JWT_SIGNATURE`: 서명이 유효하지 않은 JWT --- .../java/org/terning/terningserver/jwt/JwtValidationType.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/terning/terningserver/jwt/JwtValidationType.java b/src/main/java/org/terning/terningserver/jwt/JwtValidationType.java index 3e5c98c..cd26a72 100644 --- a/src/main/java/org/terning/terningserver/jwt/JwtValidationType.java +++ b/src/main/java/org/terning/terningserver/jwt/JwtValidationType.java @@ -2,6 +2,7 @@ public enum JwtValidationType { VALID_JWT, + INVALID_JWT_SIGNATURE, INVALID_JWT_TOKEN, EXPIRED_JWT_TOKEN, UNSUPPORTED_JWT_TOKEN, From b81b025c915b9b9292041f0a98336d000555e72a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:16:33 +0900 Subject: [PATCH 095/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Use?= =?UTF-8?q?rRepository=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4?= =?UTF-8?q?=EC=97=90=20=EC=83=88=EB=A1=9C=EC=9A=B4=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 인증 유형과 액세스 토큰을 사용하여 사용자를 조회하는`findByAuthTypeAndAuthAccessToken` 메서드 추가 --- .../org/terning/terningserver/repository/UserRepository.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/repository/UserRepository.java b/src/main/java/org/terning/terningserver/repository/UserRepository.java index c8e3d23..144882f 100644 --- a/src/main/java/org/terning/terningserver/repository/UserRepository.java +++ b/src/main/java/org/terning/terningserver/repository/UserRepository.java @@ -8,7 +8,8 @@ public interface UserRepository extends JpaRepository { - Optional findByAuthTypeAndAuthId(AuthType authTypeType, String authId); + Optional findByAuthTypeAndAuthAccessToken(AuthType authType, String authId); Optional findByRefreshToken(String refreshToken); + } From e268cb0478901745491f0ab4b44a3238b715fe5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:18:06 +0900 Subject: [PATCH 096/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Aut?= =?UTF-8?q?hService=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4?= =?UTF-8?q?=EC=9D=98=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=8B=9C=EA=B7=B8?= =?UTF-8?q?=EB=8B=88=EC=B2=98=20=EB=B0=8F=20=EB=B0=98=ED=99=98=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `signIn`, `reissueToken` 메서드의 파라미터와 반환 타입을 현대화된 요청 및 응답 클래스로 업데이트 - `SignInServiceRequest` 및 `SignInServiceResponse`를 `SignInRequest` 및 `SignInResponse`로 변경 - `TokenGetServiceRequest` 및 `TokenGetServiceResponse`를 `TokenGetResponse`로 변경 - `signIn` 메서드에 `User` 객체를 직접 전달할 수 있도록 오버로드 버전 추가 - `saveUser` 메서드 추가로 인증 토큰과 요청을 기반으로 사용자 저장 로직 구현 - 사용자 로그아웃 및 탈퇴 처리를 위한 `signOut`, `withdraw` 메서드 명확화 --- .../terning/terningserver/service/AuthService.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/AuthService.java b/src/main/java/org/terning/terningserver/service/AuthService.java index 6889cdb..444de1f 100644 --- a/src/main/java/org/terning/terningserver/service/AuthService.java +++ b/src/main/java/org/terning/terningserver/service/AuthService.java @@ -1,17 +1,19 @@ package org.terning.terningserver.service; -import org.terning.terningserver.domain.auth.request.SignInServiceRequest; -import org.terning.terningserver.domain.auth.request.TokenGetServiceRequest; -import org.terning.terningserver.domain.auth.response.SignInServiceResponse; -import org.terning.terningserver.domain.auth.response.TokenGetServiceResponse; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.domain.auth.request.SignInRequest; +import org.terning.terningserver.domain.auth.response.SignInResponse; +import org.terning.terningserver.domain.auth.response.TokenGetResponse; public interface AuthService { - SignInServiceResponse signIn(SignInServiceRequest request); + SignInResponse signIn(User user, SignInRequest request); + + User saveUser(String authAccessToken, SignInRequest request); void signOut(long userId); void withdraw(long userId); - TokenGetServiceResponse reissueToken(TokenGetServiceRequest request); + TokenGetResponse reissueToken(String refreshToken); } From cba67c832661ae59104451386c24fac785d9e6fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:19:07 +0900 Subject: [PATCH 097/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Aut?= =?UTF-8?q?hServiceImpl=EC=97=90=EC=84=9C=20=EC=9D=B8=EC=A6=9D=20=EB=B0=8F?= =?UTF-8?q?=20=ED=86=A0=ED=81=B0=20=EA=B4=80=EB=A0=A8=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EA=B0=95=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `signIn`, `reissueToken` 메서드의 요청 및 응답 형식을 최신 클래스로 업데이트하여, 사용자 경험 및 개발 유연성 향상: - `SignInServiceRequest`와 `SignInServiceResponse`를 `SignInRequest`와 `SignInResponse`로 교체 - `TokenGetServiceRequest`와 `TokenGetServiceResponse`를 간소화하여 `TokenGetResponse`로 변경 - 사용자 인증 로직 개선 및 오류 처리 강화: - `getUser` 및 `signUp` 메서드에서 예외 처리 로직 강화하여 인증 실패 시 명확한 에러 메시지 제공 - 인증 ID 조회 로직(`getAuthId`)에 인증 유형에 따른 분기 처리 추가로 유연성 증가 - `saveUser` 메서드에서 User 객체를 빌더 패턴을 이용하여 생성, 리포지토리를 통해 저장하는 방식으로 리팩토링 - Apple 및 Kakao 서비스를 통해 외부 API 호출을 처리하는 방식 통합, 해당 로직을 AuthServiceImpl 내부로 이동하여 서비스 의존성 관리 간소화 --- .../service/AuthServiceImpl.java | 55 ++++++++++++------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index 80f0b1f..59b680c 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -1,5 +1,6 @@ package org.terning.terningserver.service; +import lombok.extern.slf4j.Slf4j; import lombok.val; import org.springframework.security.core.Authentication; import org.springframework.transaction.annotation.Transactional; @@ -8,37 +9,47 @@ import org.terning.terningserver.config.ValueConfig; import org.terning.terningserver.domain.Token; import org.terning.terningserver.domain.User; -import org.terning.terningserver.domain.auth.request.SignInServiceRequest; -import org.terning.terningserver.domain.auth.request.TokenGetServiceRequest; -import org.terning.terningserver.domain.auth.response.SignInServiceResponse; -import org.terning.terningserver.domain.auth.response.TokenGetServiceResponse; +import org.terning.terningserver.domain.auth.request.SignInRequest; +import org.terning.terningserver.domain.auth.response.SignInResponse; +import org.terning.terningserver.domain.auth.response.TokenGetResponse; import org.terning.terningserver.domain.enums.AuthType; import org.terning.terningserver.exception.CustomException; -import org.terning.terningserver.exception.UserException; import org.terning.terningserver.jwt.JwtTokenProvider; import org.terning.terningserver.jwt.UserAuthentication; import org.terning.terningserver.repository.UserRepository; +import java.util.Optional; import static org.terning.terningserver.exception.enums.ErrorMessage.INVALID_USER; +import static org.terning.terningserver.exception.enums.ErrorMessage.TOKEN_REISSUE_FAILED; +@Slf4j @Service @RequiredArgsConstructor @Transactional(readOnly = true) public class AuthServiceImpl implements AuthService { private final JwtTokenProvider jwtTokenProvider; - private final UserRepository userRepository; private final KakaoService kakaoService; private final AppleService appleService; private final UserService userService; private final ValueConfig valueConfig; + private final UserRepository userRepository; @Override @Transactional - public SignInServiceResponse signIn(SignInServiceRequest request) { - val user = getUser(request.authAccessToken(), request.authType()); - val token = getToken(user); - return SignInServiceResponse.of(token); + public SignInResponse signIn(User user, SignInRequest request) { + User authenticatedUser = getUser(user.getAuthAccessToken(), request.authType()); + val token = getToken(authenticatedUser); + return SignInResponse.of(token, authenticatedUser.getId(), authenticatedUser.getAuthType()); + } + + @Transactional + public User saveUser(String authAccessToken, SignInRequest request) { + User user = User.builder() + .authAccessToken(authAccessToken) + .authType(request.authType()) + .build(); + return userRepository.save(user); } @Override @@ -56,18 +67,21 @@ public void withdraw(long userId) { } @Override - public TokenGetServiceResponse reissueToken(TokenGetServiceRequest request) { - val user = findUser(request.refreshToken()); - val token = generateAccessToken(user.getId()); - return TokenGetServiceResponse.of(token); + public TokenGetResponse reissueToken(String refreshToken) { + val user = findUser(refreshToken); + val token = Optional.ofNullable(generateAccessToken(user.getId())) + .orElseThrow(() -> new CustomException(TOKEN_REISSUE_FAILED)); + return TokenGetResponse.of(token); } private User getUser(String authAccessToken, AuthType authType) { - val authId = getAuthId(authAccessToken, authType); + User user = userRepository.findByAuthTypeAndAuthAccessToken(authType, authAccessToken) + .orElseThrow(() -> new CustomException(INVALID_USER)); + val authId = getAuthId(user.getAuthType(), authAccessToken); return signUp(authType, authId); } - private String getAuthId(String authAccessToken, AuthType authType) { + private String getAuthId(AuthType authType, String authAccessToken) { return switch (authType) { case APPLE -> appleService.getAppleData(authAccessToken); case KAKAO -> kakaoService.getKakaoData(authAccessToken); @@ -75,12 +89,16 @@ private String getAuthId(String authAccessToken, AuthType authType) { } private User signUp(AuthType authType, String authId) { - return userRepository.findByAuthTypeAndAuthId(authType, authId) + return userRepository.findByAuthTypeAndAuthAccessToken(authType, authId) .orElseGet(() -> saveUser(authType, authId)); } private User saveUser(AuthType authType, String authId) { - val user = User.builder().authType(authType).authId(authId).build(); + User user = User.builder() + .authType(authType) + .authId(authId) + .build(); + return userRepository.save(user); } @@ -118,5 +136,4 @@ private String generateAccessToken(long userId) { private void deleteUser(User user) { userService.deleteUser(user); } - } From b7f35bc7b925a799988ecd7443a085e8c6f166fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:20:49 +0900 Subject: [PATCH 098/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Kak?= =?UTF-8?q?aoServiceImpl=EC=97=90=EC=84=9C=20=EC=86=8C=EC=85=9C=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `getKakaoUserId` 메서드에서 예외 발생 시 반환하는 예외를 `INVALID_TOKEN`에서 `SOCIAL_LOGIN_FAILED`로 변경 - RestTemplate 호출 부분의 코드 정리 및 중복 제거 - `restTemplate.postForEntity` 호출 시의 줄바꿈 제거하여 코드의 일관성 유지 --- .../terningserver/service/KakaoServiceImpl.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/KakaoServiceImpl.java b/src/main/java/org/terning/terningserver/service/KakaoServiceImpl.java index f826e60..cdce9db 100644 --- a/src/main/java/org/terning/terningserver/service/KakaoServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/KakaoServiceImpl.java @@ -10,12 +10,10 @@ import org.springframework.web.client.RestTemplate; import org.terning.terningserver.config.ValueConfig; import org.terning.terningserver.exception.CustomException; -import org.terning.terningserver.exception.dto.ErrorResponse; -import org.terning.terningserver.exception.enums.ErrorMessage; import java.util.Map; -import static org.terning.terningserver.exception.enums.ErrorMessage.INVALID_TOKEN; +import static org.terning.terningserver.exception.enums.ErrorMessage.SOCIAL_LOGIN_FAILED; @Service @@ -32,12 +30,10 @@ public String getKakaoData(String authAccessToken) { val headers = new HttpHeaders(); headers.add("Authorization", authAccessToken); val httpEntity = new HttpEntity(headers); - val responseData = restTemplate. - postForEntity(valueConfig.getKakaoUri(), httpEntity, Object.class); + val responseData = restTemplate.postForEntity(valueConfig.getKakaoUri(), httpEntity, Object.class); return objectMapper.convertValue(responseData.getBody(), Map.class).get("id").toString(); } catch (Exception exception) { - throw new CustomException(INVALID_TOKEN); - + throw new CustomException(SOCIAL_LOGIN_FAILED); } } } From cf6dd1c74612cc589b88d6aa72974dd5e4c2dc81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:23:59 +0900 Subject: [PATCH 099/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20UserServiceImpl?= =?UTF-8?q?=EC=9D=98=20deleteUser=20=EB=A9=94=EC=84=9C=EB=93=9C=EC=97=90?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `deleteUser` 메서드에서 사용자 삭제 도중 예외 발생 시 `CustomException`을 발생시키도록 변경 - 예외 처리에 `WITHDRAW_FAILED` 에러 메시지 사용하여 계정 탈퇴 실패 시 명확한 에러 반환 - `userRepository.delete(user)` 호출을 try-catch 블록으로 감싸 예외 상황에 대비 --- .../terning/terningserver/service/UserServiceImpl.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/service/UserServiceImpl.java b/src/main/java/org/terning/terningserver/service/UserServiceImpl.java index d32a2ba..2256766 100644 --- a/src/main/java/org/terning/terningserver/service/UserServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/UserServiceImpl.java @@ -4,8 +4,11 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.User; +import org.terning.terningserver.exception.CustomException; import org.terning.terningserver.repository.UserRepository; +import static org.terning.terningserver.exception.enums.ErrorMessage.WITHDRAW_FAILED; + @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -15,7 +18,11 @@ public class UserServiceImpl implements UserService { @Override public void deleteUser(User user) { - userRepository.delete(user); + try { + userRepository.delete(user); + } catch (Exception e) { + throw new CustomException(WITHDRAW_FAILED); + } } } From 8025f833472348079f51b420ab9bb40ed48e457c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:24:43 +0900 Subject: [PATCH 100/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20SignUpService?= =?UTF-8?q?=EC=97=90=20=ED=9A=8C=EC=9B=90=20=EC=A0=95=EB=B3=B4=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `signUp` 메서드에서 주어진 userId를 기반으로 User 객체를 찾고, 이름과 프로필 이미지를 업데이트하는 로직 추가 - 사용자가 존재하지 않을 경우 `CustomException`을 발생시키고, `SIGN_UP_FAILED` 에러 메시지를 사용하여 회원가입 실패를 명확하게 통보 - `userRepository.findById`를 사용하여 사용자 검색 후, 존재하는 경우에만 프로필 업데이트를 수행하고 저장 --- .../terningserver/service/SignUpService.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/service/SignUpService.java diff --git a/src/main/java/org/terning/terningserver/service/SignUpService.java b/src/main/java/org/terning/terningserver/service/SignUpService.java new file mode 100644 index 0000000..0500caa --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/SignUpService.java @@ -0,0 +1,24 @@ +package org.terning.terningserver.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.repository.UserRepository; + +import static org.terning.terningserver.exception.enums.ErrorMessage.SIGN_UP_FAILED; + + +@Service +@RequiredArgsConstructor +public class SignUpService { + + private final UserRepository userRepository; + + public User signUp(Long userId, String name, Integer profileImage) { + return userRepository.findById(userId).map(user -> { + user.updateProfile(name, profileImage); + return userRepository.save(user); + }).orElseThrow(() -> new CustomException(SIGN_UP_FAILED)); + } +} From f4ce4f8bfc08c4f0f99f5341d02ba08f1961c2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:25:53 +0900 Subject: [PATCH 101/205] =?UTF-8?q?[=E2=9C=A8feat:/#17]:=20SignUpFilterSer?= =?UTF-8?q?vice=EC=97=90=20=ED=9A=8C=EC=9B=90=20=ED=95=84=ED=84=B0=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EB=93=B1=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `signUpFilter` 메서드 구현으로 사용자 필터 정보 생성 및 업데이트 기능 제공 - 입력받은 회원 ID를 사용하여 해당 사용자를 찾고, 없을 경우 `CustomException`을 발생시키며 `SIGN_UP_FILTER_FAILED` 에러 메시지 반환 - `SignUpFilterRequest`에서 제공된 grade, workingPeriod, startYear, startMonth를 사용하여 `Filter` 객체 생성 - 생성된 `Filter` 객체를 `filterRepository`를 통해 저장, 실패 시 `CustomException` 발생 - 사용자 모델에 필터 정보를 업데이트 후 `userRepository`를 통해 저장 --- .../service/SignUpFilterService.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/service/SignUpFilterService.java diff --git a/src/main/java/org/terning/terningserver/service/SignUpFilterService.java b/src/main/java/org/terning/terningserver/service/SignUpFilterService.java new file mode 100644 index 0000000..d78838a --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/SignUpFilterService.java @@ -0,0 +1,52 @@ +package org.terning.terningserver.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.terning.terningserver.domain.Filter; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.domain.auth.request.SignUpFilterRequest; +import org.terning.terningserver.domain.enums.Grade; +import org.terning.terningserver.domain.enums.WorkingPeriod; +import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.repository.FilterRepository; +import org.terning.terningserver.repository.UserRepository; + +import static org.terning.terningserver.exception.enums.ErrorMessage.SIGN_UP_FILTER_FAILED; + +@Service +@RequiredArgsConstructor +public class SignUpFilterService { + + private final FilterRepository filterRepository; + private final UserRepository userRepository; + + public void signUpFilter(Long userId, SignUpFilterRequest request) { + User user = userRepository.findById(userId).orElseThrow(() -> new CustomException(SIGN_UP_FILTER_FAILED)); + + int gradeKey = request.grade(); + int workingPeriodKey = request.workingPeriod(); + int startYear = request.startYear(); + int startMonth = request.startMonth(); + + Grade grade = Grade.fromKey(gradeKey); + WorkingPeriod workingPeriod = WorkingPeriod.fromKey(workingPeriodKey); + + Filter filter = Filter.builder() + .grade(grade) + .workingPeriod(workingPeriod) + .startYear(startYear) + .startMonth(startMonth) + .build(); + + try { + filterRepository.save(filter); + } catch (Exception e) { + throw new CustomException(SIGN_UP_FILTER_FAILED); + } + + + user.updateFilter(grade, workingPeriod, startYear, startMonth); + userRepository.save(user); + } + +} From 90eb95c2225a383c064a09e68892a109093ab792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:26:41 +0900 Subject: [PATCH 102/205] =?UTF-8?q?[=E2=9C=A8feat:/#17]:=20AppleServiceImp?= =?UTF-8?q?l=EC=97=90=EC=84=9C=20=EC=95=A0=ED=94=8C=20=EA=B3=B5=EA=B0=9C?= =?UTF-8?q?=20=ED=82=A4=EB=A5=BC=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 애플 로그인을 위한 공개 키 가져오기 및 검증 로직 추가 - HTTP 요청을 통해 애플의 공개 키 목록을 가져오는 `getApplePublicKeys` 메서드 구현 - 받아온 HTTP 응답을 처리하는 `getHttpResponse` 및 `splitResponse` 메서드 구현 - 주어진 액세스 토큰과 공개 키 목록을 사용하여 유효한 공개 키를 생성하는 `makePublicKey` 메서드 구현 - 공개 키 검증 실패 시 `INVALID_KEY` 에러로 `CustomException` 발생 - 공개 키를 RSA 퍼블릭 키로 변환하는 로직을 포함하여 보안 강화 --- .../service/AppleServiceImpl.java | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/service/AppleServiceImpl.java diff --git a/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java b/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java new file mode 100644 index 0000000..47be476 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java @@ -0,0 +1,144 @@ +package org.terning.terningserver.service; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.terning.terningserver.config.ValueConfig; +import org.terning.terningserver.exception.CustomException; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.math.BigInteger; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPublicKeySpec; +import java.util.Base64; +import java.util.Objects; + +import static org.terning.terningserver.exception.enums.ErrorMessage.INVALID_KEY; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class AppleServiceImpl implements AppleService{ + + private final ValueConfig valueConfig; + + @Override + public String getAppleData(String authAccessToken) { + val publicKeyList = getApplePublicKeys(); + val publicKey = makePublicKey(authAccessToken, publicKeyList); + + return ""; + } + + private JsonArray getApplePublicKeys() { + val connection = sendHttpRequest(); + val result = getHttpResponse(connection); + val keys = (JsonObject)JsonParser.parseString(result.toString()); + return (JsonArray)keys.get(ValueConfig.KEY); + } + + private HttpURLConnection sendHttpRequest() { + try{ + val url = new URL(valueConfig.getAppleUri()); + val connection = (HttpURLConnection)url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + return connection; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private StringBuilder getHttpResponse(HttpURLConnection connection) { + try { + val bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + return splitResponse(bufferedReader); + } catch (IOException exception) { + throw new RuntimeException(exception); + } + } + + private StringBuilder splitResponse(BufferedReader bufferedReader) { + try{ + val result = new StringBuilder(); + + String line; + while (Objects.nonNull(line = bufferedReader.readLine())) { + result.append(line); + } + bufferedReader.close(); + + return result; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private PublicKey makePublicKey(String accessToken, JsonArray publicKeyList) { + val decodeArray = accessToken.split(ValueConfig.TOKEN_VALUE_DELIMITER); + val header = new String(Base64.getDecoder().decode(getTokenFromBearerString(decodeArray[0]))); + + val kid = ((JsonObject) JsonParser.parseString(header)).get(ValueConfig.ALG_HEADER_KEY); + val alg = ((JsonObject) JsonParser.parseString(header)).get(ValueConfig.KID_HEADER_KEY); + val matchingPublicKey = findMatchingPublicKey(publicKeyList, kid, alg); + + if (Objects.isNull(matchingPublicKey)) { + throw new CustomException(INVALID_KEY); + } + + return getPublicKey(matchingPublicKey); + } + + private String getTokenFromBearerString(String token) { + return token.replaceFirst(ValueConfig.BEARER_HEADER, ValueConfig.BLANK); + } + + private JsonObject findMatchingPublicKey(JsonArray publicKeyList, JsonElement kid, JsonElement alg) { + for (JsonElement publicKey : publicKeyList) { + val publicKeyObject = publicKey.getAsJsonObject(); + val publicKid = publicKeyObject.get(ValueConfig.KID_HEADER_KEY); + val publicAlg = publicKeyObject.get(ValueConfig.ALG_HEADER_KEY); + + if (Objects.equals(kid, publicKid) && Objects.equals(alg, publicAlg)) { + return publicKeyObject; + } + } + + return null; + } + + private PublicKey getPublicKey(JsonObject object) { + try { + val modulus = object.get(ValueConfig.MODULUS).toString(); + val exponent = object.get(ValueConfig.EXPONENT).toString(); + + val quotes = ValueConfig.QUOTES; + val modulusBytes = Base64.getUrlDecoder().decode(modulus.substring(quotes, modulus.length() - quotes)); + val exponentBytes = Base64.getUrlDecoder().decode(exponent.substring(quotes, exponent.length() - quotes)); + + val positiveNumber = ValueConfig.POSITIVE_NUMBER; + val modulusValue = new BigInteger(positiveNumber, modulusBytes); + val exponentValue = new BigInteger(positiveNumber, exponentBytes); + + val publicKeySpec = new RSAPublicKeySpec(modulusValue, exponentValue); + val keyFactory = KeyFactory.getInstance(ValueConfig.RSA); + + return keyFactory.generatePublic(publicKeySpec); + } catch (InvalidKeySpecException | NoSuchAlgorithmException exception) { + throw new CustomException(INVALID_KEY); + } + } + +} From ced8055fcb9694fa6691c6edf046e86d183813c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:27:24 +0900 Subject: [PATCH 103/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20FilterRepository?= =?UTF-8?q?=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Filter 엔티티에 대한 JpaRepository 인터페이스 `FilterRepository` 추가 - 이 인터페이스는 Filter 객체에 대한 데이터 접근을 추상화하여, CRUD 기능을 자동으로 제공받을 수 있게 함 - Spring Data JPA의 Repository 어노테이션을 사용하여 스프링 컨테이너에 등록 --- .../terningserver/repository/FilterRepository.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/repository/FilterRepository.java diff --git a/src/main/java/org/terning/terningserver/repository/FilterRepository.java b/src/main/java/org/terning/terningserver/repository/FilterRepository.java new file mode 100644 index 0000000..9f613e9 --- /dev/null +++ b/src/main/java/org/terning/terningserver/repository/FilterRepository.java @@ -0,0 +1,9 @@ +package org.terning.terningserver.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import org.terning.terningserver.domain.Filter; + +@Repository +public interface FilterRepository extends JpaRepository { +} From 20abc0c616f5961d91d0ce6a3645b4ffbd2e57d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:38:21 +0900 Subject: [PATCH 104/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20SignUpFilterResp?= =?UTF-8?q?onse=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 회원가입 시 필터 설정에 대한 응답을 담을 새로운 Java 레코드 `SignUpFilterResponse` 추가 - 이 레코드는 현재는 비어 있지만, 향후 필터 관련 데이터 전송 시 확장될 예정 --- .../domain/auth/response/SignUpFilterResponse.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/domain/auth/response/SignUpFilterResponse.java diff --git a/src/main/java/org/terning/terningserver/domain/auth/response/SignUpFilterResponse.java b/src/main/java/org/terning/terningserver/domain/auth/response/SignUpFilterResponse.java new file mode 100644 index 0000000..51f7965 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/auth/response/SignUpFilterResponse.java @@ -0,0 +1,4 @@ +package org.terning.terningserver.domain.auth.response; + +public record SignUpFilterResponse() { +} From c948cc636bf2c7ebc920fa8c865ea1362757e58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:40:36 +0900 Subject: [PATCH 105/205] =?UTF-8?q?[=E2=9C=A8feat:/#17]:=20SignUpFilterReq?= =?UTF-8?q?uest=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 회원가입 시 필터 정보 입력을 위한 `SignUpFilterRequest` 레코드 추가 - 필드로 grade, workingPeriod, startYear, startMonth를 포함하며, 모든 필드는 null을 허용하지 않음(@NonNull 사용) - 빌더 패턴 적용(@Builder)하여 객체의 불변성을 보장하고, 빌더 접근을 PRIVATE으로 제한하여 불필요한 외부 접근 차단 --- .../domain/auth/request/SignUpFilterRequest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/domain/auth/request/SignUpFilterRequest.java diff --git a/src/main/java/org/terning/terningserver/domain/auth/request/SignUpFilterRequest.java b/src/main/java/org/terning/terningserver/domain/auth/request/SignUpFilterRequest.java new file mode 100644 index 0000000..f53ffb4 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/auth/request/SignUpFilterRequest.java @@ -0,0 +1,16 @@ +package org.terning.terningserver.domain.auth.request; + +import lombok.Builder; +import lombok.NonNull; + +import static lombok.AccessLevel.PRIVATE; + +@Builder(access = PRIVATE) +public record SignUpFilterRequest( + @NonNull int grade, + @NonNull int workingPeriod, + @NonNull int startYear, + @NonNull int startMonth + +) { +} From 308ef24b296b38acd6f8f49e96cd99f5c346379d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:41:04 +0900 Subject: [PATCH 106/205] =?UTF-8?q?[=E2=9C=A8feat:/#17]:=20SignUpRequest?= =?UTF-8?q?=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20=EB=B9=8C=EB=8D=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 회원가입 요청 데이터를 담기 위한 `SignUpRequest` 레코드 추가 - 필수 필드로 `name`과 `profileImage`를 포함, 모든 필드는 null이 허용되지 않음(@NonNull) - 레코드에 빌더 패턴 적용(@Builder)으로 객체 생성 시 불변성 보장 - `of` 정적 메서드를 통해 외부에서 레코드의 인스턴스를 쉽게 생성할 수 있도록 구현 --- .../domain/auth/request/SignUpRequest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/domain/auth/request/SignUpRequest.java diff --git a/src/main/java/org/terning/terningserver/domain/auth/request/SignUpRequest.java b/src/main/java/org/terning/terningserver/domain/auth/request/SignUpRequest.java new file mode 100644 index 0000000..61e0c92 --- /dev/null +++ b/src/main/java/org/terning/terningserver/domain/auth/request/SignUpRequest.java @@ -0,0 +1,21 @@ +package org.terning.terningserver.domain.auth.request; + +import lombok.Builder; +import lombok.NonNull; + +import static lombok.AccessLevel.PRIVATE; + +@Builder(access = PRIVATE) +public record SignUpRequest( + @NonNull String name, + @NonNull int profileImage +) { + + public static SignUpRequest of(String name, int profileImage){ + return SignUpRequest.builder() + .name(name) + .profileImage(profileImage) + .build(); + } + +} From bc7302686e8f8890b1ec65c448b0f9644459d56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 13:42:07 +0900 Subject: [PATCH 107/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20AuthController?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B8=EC=A6=9D=20=EB=B0=8F=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EA=B4=80=EB=A6=AC=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용자 로그인, 로그아웃, 회원가입, 토큰 재발급, 회원 탈퇴 등의 API 엔드포인트 구현 - `/sign-in` 경로에서 사용자 인증 후 SignInResponse 반환 - `/token-reissue` 경로에서 refreshToken을 사용해 토큰 재발급 처리 - `/sign-up` 및 `/sign-up/filter` 경로에서 각각 사용자 정보 등록과 필터 설정 추가 - `/logout` 및 `/withdraw` 경로에서 사용자 로그아웃과 탈퇴 처리 - 각 API 요청에 대한 성공 응답으로 `SuccessResponse` 객체를 반환, 통일된 응답 구조 제공 - `AuthService`, `SignUpService`, `SignUpFilterService`를 활용하여 비즈니스 로직 처리 --- .../controller/AuthController.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/controller/AuthController.java diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java new file mode 100644 index 0000000..e782a81 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -0,0 +1,93 @@ +package org.terning.terningserver.controller; + +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.domain.auth.request.SignInRequest; +import org.terning.terningserver.domain.auth.request.SignUpFilterRequest; +import org.terning.terningserver.domain.auth.request.SignUpRequest; +import org.terning.terningserver.domain.auth.response.SignInResponse; +import org.terning.terningserver.domain.auth.response.SignUpFilterResponse; +import org.terning.terningserver.domain.auth.response.TokenGetResponse; +import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.service.AuthService; +import org.terning.terningserver.service.SignUpFilterService; +import org.terning.terningserver.service.SignUpService; + +import java.security.Principal; + +import static org.terning.terningserver.exception.enums.SuccessMessage.*; + +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_SIGN_IN; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/auth") +public class AuthController { + + private final AuthService authService; + + @PostMapping("/sign-in") + public ResponseEntity> signIn( + @RequestHeader("Authorization") String authAccessToken, + @RequestBody SignInRequest request + ) { + User user = authService.saveUser(authAccessToken, request); + val signInResponse = authService.signIn(user, request); + + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_IN, signInResponse)); + } + + private final SignUpService signUpService; + private final SignUpFilterService signUpFilterService; + + // TODO: 에러 메시지 위치 + @PostMapping("/token-reissue") + public ResponseEntity> reissueToken( + @RequestHeader("Authorization") String refreshToken + ) { + val response = authService.reissueToken(refreshToken); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_REISSUE_TOKEN, response)); + } + + @PostMapping("/sign-up") + public ResponseEntity> signUp( + @RequestHeader("User-Id") Long userId, + @RequestBody SignUpRequest request + ) { + signUpService.signUp(userId, request.name(), request.profileImage()); + + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_UP)); + } + + @PostMapping("/sign-up/fileter") + public ResponseEntity> filter( + @RequestHeader("User-Id") Long userId, + @RequestBody SignUpFilterRequest request + ) { + signUpFilterService.signUpFilter(userId, request); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_UP_FILTER)); + + } + + @PostMapping("/logout") + public ResponseEntity signOut(Principal principal) { +// val userId = Long.parseLong(principal.getName()); + val userId = 6; + authService.signOut(userId); + + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_OUT)); + } + + @DeleteMapping("/withdraw") + public ResponseEntity withdraw(Principal principal) { +// val userId = Long.parseLong(principal.getName()); + val userId = 7; + authService.withdraw(userId); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_WITHDRAW)); + + } + +} From a8a42a22d0b881e7c74b881b9029da652f73e2ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:12:48 +0900 Subject: [PATCH 108/205] =?UTF-8?q?[=E2=9C=A8feat/#31]:=20Swagger=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/controller/swagger/SearchSwagger.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java index f3b78b6..ac9a1a2 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java @@ -6,7 +6,9 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestParam; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; import org.terning.terningserver.dto.search.response.SearchResultResponse; import org.terning.terningserver.exception.dto.SuccessResponse; @@ -26,6 +28,7 @@ ResponseEntity> getMostScrapped @Operation(summary = "탐색 > 검색 결과 화면", description = "탐색 화면에서 인턴 공고를 검색하는 API") ResponseEntity> searchInternshipAnnouncement( - + @RequestParam(value = "keyword", required = false) String keyword, + @RequestParam("sortBy") String sortBy, Pageable pageable ); } From 9224c12cba911a30e01971b6f96d85b7207df3f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:22:13 +0900 Subject: [PATCH 109/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8F=C2=A0refactor/#31]:?= =?UTF-8?q?=20Swagger=20=EC=84=A4=EC=A0=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/dto/search/response/SearchResultResponse.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java index 96851ee..35c1d3b 100644 --- a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java +++ b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java @@ -33,7 +33,6 @@ public static SearchAnnouncementResponse from(InternshipAnnouncement announcemen .build(); } } - public static SearchResultResponse of(List announcements) { public static SearchResultResponse of(int totalPages, Boolean hasNext, List announcements) { return new SearchResultResponse(totalPages, hasNext, announcements); } From 86f06b19e93207722f34f748670f49d77257ed52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 17:33:21 +0900 Subject: [PATCH 110/205] =?UTF-8?q?[=E2=9C=85chore/#17]:=20ValueConfig=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=EC=97=90=20=ED=99=98=EA=B2=BD=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EB=B3=84=EC=B9=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/config/ValueConfig.java | 10 +++++----- src/main/resources/application-dev.yml | 9 ++++++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/terning/terningserver/config/ValueConfig.java b/src/main/java/org/terning/terningserver/config/ValueConfig.java index e2b4e80..2ebce42 100644 --- a/src/main/java/org/terning/terningserver/config/ValueConfig.java +++ b/src/main/java/org/terning/terningserver/config/ValueConfig.java @@ -12,19 +12,19 @@ @Getter public class ValueConfig { - @Value("${jwt.SECRET_KEY}") + @Value("${SECRET_KEY}") private String secretKey; - @Value("${jwt.KAKAO_URL}") + @Value("${KAKAO_URL}") private String kakaoUri; - @Value("${jwt.APPLE_URL}") + @Value("${APPLE_URL}") private String appleUri; - @Value("${jwt.ACCESS_TOKEN_EXPIRED}") + @Value("${ACCESS_TOKEN_EXPIRED}") private Long accessTokenExpired; - @Value("${jwt.REFRESH_TOKEN_EXPIRED}") + @Value("${REFRESH_TOKEN_EXPIRED}") private Long refreshTokenExpired; public static final String IOS_FORCE_UPDATE_VERSION = "0.0.9"; diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 7331780..d592417 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -37,6 +37,13 @@ spring: format_sql: true show_sql: true +jwt: + secret-key: ${SECRET_KEY} + apple-url: ${APPLE_URL} + kakao-url: ${KAKAO_URL} + access-token-expired: ${ACCESS_TOKEN_EXPIRED} + refresh-token-expired: ${REFRESH_TOKEN_EXPIRED} + logging: level: - com.zaxxer.hikari: INFO \ No newline at end of file + com.zaxxer.hikari: INFO From 970aa43a5a92bb1e2a5281171b1f7cb791ffe014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 18:19:18 +0900 Subject: [PATCH 111/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8F=C2=A0refactor/#31]:?= =?UTF-8?q?=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EC=9D=98=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?Stream.toList()=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/service/ScrapServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 71c14af..6ee3774 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -20,6 +20,6 @@ public List getTodayScrap(Long userId){ LocalDate today = LocalDate.now(); return scrapRepository.findByUserIdAndInternshipAnnouncement_Deadline(userId, today).stream() .map(TodayScrapResponseDto::of) - .collect(Collectors.toList()); + .toList(); } } From b00ce313fadbc5fc50cca465bb0fab93b8635f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 18:30:56 +0900 Subject: [PATCH 112/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20Swagger=20API=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=ED=99=94=EB=A5=BC=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AuthSwagger 인터페이스를 추가하여 소셜 로그인, 회원가입, 토큰 재발급, 사용자 필터링 정보 생성, 로그아웃, 계정 탈퇴에 대한 API 설명을 명시적으로 정의하였습니다. - 각 API 메서드에 `@Operation` 어노테이션을 사용하여 요약과 세부 설명을 제공함으로써, API 사용자가 각 엔드포인트의 용도와 기능을 쉽게 이해할 수 있도록 하였습니다. - `@Tag` 어노테이션을 사용하여 이 인터페이스가 소셜 로그인 및 회원가입과 관련된 API를 다루는 것임을 명확히 하였습니다. --- .../controller/swagger/AuthSwagger.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java diff --git a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java new file mode 100644 index 0000000..412b20e --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java @@ -0,0 +1,46 @@ +package org.terning.terningserver.controller.swagger; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.terning.terningserver.domain.auth.response.SignInResponse; +import org.terning.terningserver.domain.auth.response.SignUpFilterResponse; +import org.terning.terningserver.domain.auth.response.TokenGetResponse; +import org.terning.terningserver.domain.enums.AuthType; +import org.terning.terningserver.exception.dto.SuccessResponse; + +@Tag(name = "Auth", description = "소셜 로그인 및 회원가입 API") +public interface AuthSwagger { + + @Operation(summary = "소셜 로그인", description = "AuthType에 맞는 소셜 로그인 API") + ResponseEntity> signIn( + String accessToken, + String refreshToken, + Long userId, + AuthType authType + ); + + @Operation(summary = "토큰 재발급", description = "토큰 재발급 API") + ResponseEntity> reissueToken( + String accessToken + ); + + @Operation(summary = "사용자 필터링 정보 생성", description = "사용자 필터링 정보 생성 API") + ResponseEntity> filter( + + ); + + @Operation(summary = "회원가입", description = "회원가입 API") + ResponseEntity> signUp( + ); + + @Operation(summary = "로그아웃", description = "로그아웃 API") + ResponseEntity signOut( + ); + + @Operation(summary = "계정탈퇴", description = "계정탈퇴 API") + ResponseEntity withdraw( + ); + + +} From 5177a658fe1677c985aae2d02627f1066cf6f5e2 Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 15 Jul 2024 18:51:15 +0900 Subject: [PATCH 113/205] =?UTF-8?q?[=E2=9C=A8feat/#36]=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94=20>=20=EC=9B=94=EA=B0=84=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94(=EA=B8=B0=EB=B3=B8=20=EB=B7=B0)=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CalendarController.java | 37 +++++++++++++++++++ .../controller/swagger/CalendarSwagger.java | 21 +++++++++++ .../response/MonthlyDefaultResponseDto.java | 34 +++++++++++++++++ .../exception/enums/ErrorMessage.java | 1 - .../exception/enums/SuccessMessage.java | 5 ++- .../repository/scrap/ScrapRepository.java | 1 + .../terningserver/service/ScrapService.java | 2 + .../service/ScrapServiceImpl.java | 30 +++++++++++++++ 8 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/controller/CalendarController.java create mode 100644 src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java create mode 100644 src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyDefaultResponseDto.java diff --git a/src/main/java/org/terning/terningserver/controller/CalendarController.java b/src/main/java/org/terning/terningserver/controller/CalendarController.java new file mode 100644 index 0000000..c0b2186 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/CalendarController.java @@ -0,0 +1,37 @@ +package org.terning.terningserver.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.terning.terningserver.controller.swagger.CalendarSwagger; +import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; +import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.service.ScrapService; + +import java.util.List; + +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MONTHLY_SCRAPS; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class CalendarController implements CalendarSwagger { + + private final ScrapService scrapService; + + @GetMapping("/calendar/monthly-default") + public ResponseEntity>> getMonthlyScraps( + @RequestHeader("Authorization") String token, + @RequestParam("year") int year, + @RequestParam("month") int month + ){ + Long userId = getUserIdFromToken(token); + List monthlyScraps = scrapService.getMonthlyScraps(userId, year, month); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_MONTHLY_SCRAPS, monthlyScraps)); + } + + private Long getUserIdFromToken(String token){ + //실제 토큰에서 userId를 받아오는 로직 구현 + return 1L; //임시로 사용자 ID 1로 반환 + } +} diff --git a/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java new file mode 100644 index 0000000..474cc85 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java @@ -0,0 +1,21 @@ +package org.terning.terningserver.controller.swagger; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; +import org.terning.terningserver.exception.dto.SuccessResponse; + +import java.time.Month; +import java.util.List; + +@Tag(name = "Calendar", description = "캘린더 관련 API") +public interface CalendarSwagger { + + @Operation(summary = "캘린더 > 월간 스크랩 공고 조회", description = "월간 스크랩 공고를 조회하는 API") + ResponseEntity>> getMonthlyScraps( + String token, + int year, + int month + ); +} diff --git a/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyDefaultResponseDto.java b/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyDefaultResponseDto.java new file mode 100644 index 0000000..a85e228 --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyDefaultResponseDto.java @@ -0,0 +1,34 @@ +package org.terning.terningserver.dto.calendar.response; + + +import lombok.Builder; + +import java.util.List; + +@Builder +public record MonthlyDefaultResponseDto( + String deadline, + List scraps +) { + @Builder + public static record ScrapDetail( + Long scrapId, + String title, + String color + ){ + public static ScrapDetail of(Long scrapId, String title, String color){ + return ScrapDetail.builder() + .scrapId(scrapId) + .title(title) + .color(color) + .build(); + } + } + + public static MonthlyDefaultResponseDto of(String deadline, List scraps){ + return MonthlyDefaultResponseDto.builder() + .deadline(deadline) + .scraps(scraps) + .build(); + } +} diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index 88fbba2..3908038 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -10,7 +10,6 @@ public enum ErrorMessage { //404(NotFound) NOT_FOUND_INTERN_CATEGORY(404, "해당 인턴 공고는 존재하지 않습니다"), NOT_FOUND_INTERN_EXCEPTION(404, "해당 인턴 공고는 존재하지 않습니다"), - WRONG_PERIOD(404, "해당 단어가 존재하지 않습니다"), NOT_FOUND_USER_EXCEPTION(404, "해당 유저가 존재하지 않습니다"); private final int status; diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index ba592d7..48d50a3 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -15,7 +15,10 @@ public enum SuccessMessage { SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS(200, "탐색 > 스크랩 수 많은 공고를 조회하는데 성공했습니다"), // 인턴 공고 - SUCCESS_GET_INTERNSHIP_DETAIL(200, "공고 상세 정보 불러오기에 성공했습니다"); + SUCCESS_GET_INTERNSHIP_DETAIL(200, "공고 상세 정보 불러오기에 성공했습니다"), + + // Calendar (캘린더 화면) + SUCCESS_GET_MONTHLY_SCRAPS(200, "캘린더 > (월간) 스크랩 된 공고 정보 불러오기를 성공했습니다"); ; private final int status; diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java index f4648fd..2f34752 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java @@ -11,4 +11,5 @@ public interface ScrapRepository extends JpaRepository { Boolean existsByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); List findByUserIdAndInternshipAnnouncement_Deadline(Long userId, LocalDate deadline); + List findByUserIdAndInternshipAnnouncement_DeadlineBetween(Long userId, LocalDate start, LocalDate end); } diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java index d940a73..c9d1175 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapService.java +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -1,9 +1,11 @@ package org.terning.terningserver.service; +import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import java.util.List; public interface ScrapService { List getTodayScrap(Long userId); + List getMonthlyScraps(Long userId, int year, int month); } diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 71c14af..3695419 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -2,11 +2,14 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.terning.terningserver.domain.Scrap; +import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import org.terning.terningserver.repository.scrap.ScrapRepository; import java.time.LocalDate; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Service @@ -22,4 +25,31 @@ public List getTodayScrap(Long userId){ .map(TodayScrapResponseDto::of) .collect(Collectors.toList()); } + + @Override + public List getMonthlyScraps(Long userId, int year, int month){ + + //모든 월의 시작일은 1, 마지막일은 해당 다음월의 하루 + LocalDate start = LocalDate.of(year, month, 1); + LocalDate end = start.plusMonths(1).minusDays(1); + + List scraps = scrapRepository.findByUserIdAndInternshipAnnouncement_DeadlineBetween(userId, start, end); + + // deadline 별로 그룹화 + Map> scrapsByDeadline = scraps.stream() + .collect(Collectors.groupingBy(s -> s.getInternshipAnnouncement().getDeadline())); + + return scrapsByDeadline.entrySet().stream() + .map(entry -> MonthlyDefaultResponseDto.of( + entry.getKey().toString(), + entry.getValue().stream() + .map(s -> MonthlyDefaultResponseDto.ScrapDetail.of( + s.getId(), + s.getInternshipAnnouncement().getTitle(), + s.getColor().getColorValue() + )) + .toList() + )) + .toList(); + } } From 890fffed615aa3fd18be60b8d84ae8185f99f747 Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 15 Jul 2024 18:54:14 +0900 Subject: [PATCH 114/205] =?UTF-8?q?[=E2=9C=A8feat/#36]=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94=20>=20=EC=9B=94=EA=B0=84=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94(=EA=B8=B0=EB=B3=B8=20=EB=B7=B0)=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/service/ScrapServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 3695419..a8eb727 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -23,7 +23,7 @@ public List getTodayScrap(Long userId){ LocalDate today = LocalDate.now(); return scrapRepository.findByUserIdAndInternshipAnnouncement_Deadline(userId, today).stream() .map(TodayScrapResponseDto::of) - .collect(Collectors.toList()); + .toList(); } @Override From 55fcbf5fafc5d7cc1422abc289fdcad3b3df85ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:13:49 +0900 Subject: [PATCH 115/205] =?UTF-8?q?[=E2=9C=A8=20feat/#39]:=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=20Controller=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Terning | 1 + .../controller/ScrapController.java | 20 +++++++++++++++++++ .../service/ScrapServiceImpl.java | 9 +++++++++ 3 files changed, 30 insertions(+) create mode 160000 Terning create mode 100644 src/main/java/org/terning/terningserver/controller/ScrapController.java diff --git a/Terning b/Terning new file mode 160000 index 0000000..e53017f --- /dev/null +++ b/Terning @@ -0,0 +1 @@ +Subproject commit e53017fc3ff5bbab45222818feb966ca912c1917 diff --git a/src/main/java/org/terning/terningserver/controller/ScrapController.java b/src/main/java/org/terning/terningserver/controller/ScrapController.java new file mode 100644 index 0000000..0450fe5 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/ScrapController.java @@ -0,0 +1,20 @@ +package org.terning.terningserver.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.terning.terningserver.service.ScrapService; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class ScrapController { + private final ScrapService scrapService; + + @PostMapping("/scraps/{internshipAnnouncementId}") + public void createScrap(@PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequest request) { + scrapService. + } +} diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 71c14af..d9caf64 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -22,4 +22,13 @@ public List getTodayScrap(Long userId){ .map(TodayScrapResponseDto::of) .collect(Collectors.toList()); } + + @Override + public void createPost(CreateScrapRequest request) { + + } + + private void getInternshipAnnouncement() { + internshipRepository.findById() + } } From 9509c2b8b6dd66858689436e42e3e367a4664460 Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 15 Jul 2024 20:28:21 +0900 Subject: [PATCH 116/205] =?UTF-8?q?[=E2=9C=A8feat/#36]=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94=20>=20=EC=9B=94=EA=B0=84=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94(=EA=B8=B0=EB=B3=B8=20=EB=B7=B0)=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/service/ScrapServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index a8eb727..83c4345 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -29,7 +29,7 @@ public List getTodayScrap(Long userId){ @Override public List getMonthlyScraps(Long userId, int year, int month){ - //모든 월의 시작일은 1, 마지막일은 해당 다음월의 하루 + //모든 월의 시작일은 1, 마지막일은 해당 다음월의 하루 전 LocalDate start = LocalDate.of(year, month, 1); LocalDate end = start.plusMonths(1).minusDays(1); From 2a11720c2665e121c2fe17b3d60d1bf5c9ac4bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 20:30:51 +0900 Subject: [PATCH 117/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Res?= =?UTF-8?q?ponse=EC=99=80=20Request=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EC=9D=84=20ResponseDto=EC=99=80=20RequestDto?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모든 Response 클래스를 ResponseDto로 변경 - 모든 Request 클래스를 RequestDto로 변경 --- .../controller/AuthController.java | 26 +++++++++---------- .../controller/swagger/AuthSwagger.java | 14 +++++----- .../domain/auth/request/SignInRequest.java | 13 ---------- .../auth/response/SignUpFilterResponse.java | 4 --- .../auth/response/TokenGetResponse.java | 17 ------------ .../dto/auth/request/SignInRequestDto.java | 13 ++++++++++ .../auth/request/SignUpFilterRequestDto.java} | 4 +-- .../auth/request/SignUpRequestDto.java} | 8 +++--- .../auth/request/TokenGetRequestDto.java} | 8 +++--- .../auth/response/SignInResponseDto.java} | 8 +++--- .../response/SignUpFilterResponseDto.java | 4 +++ .../auth/response/TokenGetResponseDto.java | 17 ++++++++++++ .../terningserver/service/AuthService.java | 12 ++++----- .../service/AuthServiceImpl.java | 16 ++++++------ .../service/SignUpFilterService.java | 4 +-- 15 files changed, 84 insertions(+), 84 deletions(-) delete mode 100644 src/main/java/org/terning/terningserver/domain/auth/request/SignInRequest.java delete mode 100644 src/main/java/org/terning/terningserver/domain/auth/response/SignUpFilterResponse.java delete mode 100644 src/main/java/org/terning/terningserver/domain/auth/response/TokenGetResponse.java create mode 100644 src/main/java/org/terning/terningserver/dto/auth/request/SignInRequestDto.java rename src/main/java/org/terning/terningserver/{domain/auth/request/SignUpFilterRequest.java => dto/auth/request/SignUpFilterRequestDto.java} (73%) rename src/main/java/org/terning/terningserver/{domain/auth/request/SignUpRequest.java => dto/auth/request/SignUpRequestDto.java} (60%) rename src/main/java/org/terning/terningserver/{domain/auth/request/TokenGetRequest.java => dto/auth/request/TokenGetRequestDto.java} (54%) rename src/main/java/org/terning/terningserver/{domain/auth/response/SignInResponse.java => dto/auth/response/SignInResponseDto.java} (70%) create mode 100644 src/main/java/org/terning/terningserver/dto/auth/response/SignUpFilterResponseDto.java create mode 100644 src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index 88e865f..1f87c5b 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -5,12 +5,12 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.terning.terningserver.domain.User; -import org.terning.terningserver.domain.auth.request.SignInRequest; -import org.terning.terningserver.domain.auth.request.SignUpFilterRequest; -import org.terning.terningserver.domain.auth.request.SignUpRequest; -import org.terning.terningserver.domain.auth.response.SignInResponse; -import org.terning.terningserver.domain.auth.response.SignUpFilterResponse; -import org.terning.terningserver.domain.auth.response.TokenGetResponse; +import org.terning.terningserver.dto.auth.request.SignInRequestDto; +import org.terning.terningserver.dto.auth.request.SignUpFilterRequestDto; +import org.terning.terningserver.dto.auth.request.SignUpRequestDto; +import org.terning.terningserver.dto.auth.response.SignInResponseDto; +import org.terning.terningserver.dto.auth.response.SignUpFilterResponseDto; +import org.terning.terningserver.dto.auth.response.TokenGetResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.service.AuthService; import org.terning.terningserver.service.SignUpFilterService; @@ -29,9 +29,9 @@ public class AuthController { private final AuthService authService; @PostMapping("/sign-in") - public ResponseEntity> signIn( + public ResponseEntity> signIn( @RequestHeader("Authorization") String authAccessToken, - @RequestBody SignInRequest request + @RequestBody SignInRequestDto request ) { User user = authService.saveUser(authAccessToken, request); val signInResponse = authService.signIn(user, request); @@ -44,7 +44,7 @@ public ResponseEntity> signIn( // TODO: 에러 메시지 위치 @PostMapping("/token-reissue") - public ResponseEntity> reissueToken( + public ResponseEntity> reissueToken( @RequestHeader("Authorization") String refreshToken ) { val response = authService.reissueToken(refreshToken); @@ -52,9 +52,9 @@ public ResponseEntity> reissueToken( } @PostMapping("/sign-up") - public ResponseEntity> signUp( + public ResponseEntity> signUp( @RequestHeader("User-Id") Long userId, - @RequestBody SignUpRequest request + @RequestBody SignUpRequestDto request ) { signUpService.signUp(userId, request.name(), request.profileImage()); @@ -62,9 +62,9 @@ public ResponseEntity> signUp( } @PostMapping("/sign-up/fileter") - public ResponseEntity> filter( + public ResponseEntity> filter( @RequestHeader("User-Id") Long userId, - @RequestBody SignUpFilterRequest request + @RequestBody SignUpFilterRequestDto request ) { signUpFilterService.signUpFilter(userId, request); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_UP_FILTER)); diff --git a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java index 412b20e..1107fb1 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java @@ -3,9 +3,9 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; -import org.terning.terningserver.domain.auth.response.SignInResponse; -import org.terning.terningserver.domain.auth.response.SignUpFilterResponse; -import org.terning.terningserver.domain.auth.response.TokenGetResponse; +import org.terning.terningserver.dto.auth.response.SignInResponseDto; +import org.terning.terningserver.dto.auth.response.SignUpFilterResponseDto; +import org.terning.terningserver.dto.auth.response.TokenGetResponseDto; import org.terning.terningserver.domain.enums.AuthType; import org.terning.terningserver.exception.dto.SuccessResponse; @@ -13,7 +13,7 @@ public interface AuthSwagger { @Operation(summary = "소셜 로그인", description = "AuthType에 맞는 소셜 로그인 API") - ResponseEntity> signIn( + ResponseEntity> signIn( String accessToken, String refreshToken, Long userId, @@ -21,17 +21,17 @@ ResponseEntity> signIn( ); @Operation(summary = "토큰 재발급", description = "토큰 재발급 API") - ResponseEntity> reissueToken( + ResponseEntity> reissueToken( String accessToken ); @Operation(summary = "사용자 필터링 정보 생성", description = "사용자 필터링 정보 생성 API") - ResponseEntity> filter( + ResponseEntity> filter( ); @Operation(summary = "회원가입", description = "회원가입 API") - ResponseEntity> signUp( + ResponseEntity> signUp( ); @Operation(summary = "로그아웃", description = "로그아웃 API") diff --git a/src/main/java/org/terning/terningserver/domain/auth/request/SignInRequest.java b/src/main/java/org/terning/terningserver/domain/auth/request/SignInRequest.java deleted file mode 100644 index f0545c2..0000000 --- a/src/main/java/org/terning/terningserver/domain/auth/request/SignInRequest.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.terning.terningserver.domain.auth.request; - -import lombok.NonNull; -import org.terning.terningserver.domain.enums.AuthType; - -public record SignInRequest( - @NonNull AuthType authType - ) { - - public static SignInRequest of(AuthType authType){ - return new SignInRequest(authType); - } -} diff --git a/src/main/java/org/terning/terningserver/domain/auth/response/SignUpFilterResponse.java b/src/main/java/org/terning/terningserver/domain/auth/response/SignUpFilterResponse.java deleted file mode 100644 index 51f7965..0000000 --- a/src/main/java/org/terning/terningserver/domain/auth/response/SignUpFilterResponse.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.terning.terningserver.domain.auth.response; - -public record SignUpFilterResponse() { -} diff --git a/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetResponse.java b/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetResponse.java deleted file mode 100644 index e081a39..0000000 --- a/src/main/java/org/terning/terningserver/domain/auth/response/TokenGetResponse.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.terning.terningserver.domain.auth.response; - -import lombok.Builder; -import lombok.NonNull; - -import static lombok.AccessLevel.*; - -@Builder(access = PRIVATE) -public record TokenGetResponse(@NonNull String accessToken -) { - - public static TokenGetResponse of(String accessToken) { - return TokenGetResponse.builder() - .accessToken(accessToken) - .build(); - } -} diff --git a/src/main/java/org/terning/terningserver/dto/auth/request/SignInRequestDto.java b/src/main/java/org/terning/terningserver/dto/auth/request/SignInRequestDto.java new file mode 100644 index 0000000..b45265d --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/auth/request/SignInRequestDto.java @@ -0,0 +1,13 @@ +package org.terning.terningserver.dto.auth.request; + +import lombok.NonNull; +import org.terning.terningserver.domain.enums.AuthType; + +public record SignInRequestDto( + @NonNull AuthType authType + ) { + + public static SignInRequestDto of(AuthType authType){ + return new SignInRequestDto(authType); + } +} diff --git a/src/main/java/org/terning/terningserver/domain/auth/request/SignUpFilterRequest.java b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java similarity index 73% rename from src/main/java/org/terning/terningserver/domain/auth/request/SignUpFilterRequest.java rename to src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java index f53ffb4..64d04f5 100644 --- a/src/main/java/org/terning/terningserver/domain/auth/request/SignUpFilterRequest.java +++ b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.domain.auth.request; +package org.terning.terningserver.dto.auth.request; import lombok.Builder; import lombok.NonNull; @@ -6,7 +6,7 @@ import static lombok.AccessLevel.PRIVATE; @Builder(access = PRIVATE) -public record SignUpFilterRequest( +public record SignUpFilterRequestDto( @NonNull int grade, @NonNull int workingPeriod, @NonNull int startYear, diff --git a/src/main/java/org/terning/terningserver/domain/auth/request/SignUpRequest.java b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java similarity index 60% rename from src/main/java/org/terning/terningserver/domain/auth/request/SignUpRequest.java rename to src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java index 61e0c92..7309ecf 100644 --- a/src/main/java/org/terning/terningserver/domain/auth/request/SignUpRequest.java +++ b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.domain.auth.request; +package org.terning.terningserver.dto.auth.request; import lombok.Builder; import lombok.NonNull; @@ -6,13 +6,13 @@ import static lombok.AccessLevel.PRIVATE; @Builder(access = PRIVATE) -public record SignUpRequest( +public record SignUpRequestDto( @NonNull String name, @NonNull int profileImage ) { - public static SignUpRequest of(String name, int profileImage){ - return SignUpRequest.builder() + public static SignUpRequestDto of(String name, int profileImage){ + return SignUpRequestDto.builder() .name(name) .profileImage(profileImage) .build(); diff --git a/src/main/java/org/terning/terningserver/domain/auth/request/TokenGetRequest.java b/src/main/java/org/terning/terningserver/dto/auth/request/TokenGetRequestDto.java similarity index 54% rename from src/main/java/org/terning/terningserver/domain/auth/request/TokenGetRequest.java rename to src/main/java/org/terning/terningserver/dto/auth/request/TokenGetRequestDto.java index 1384e55..7bd4eef 100644 --- a/src/main/java/org/terning/terningserver/domain/auth/request/TokenGetRequest.java +++ b/src/main/java/org/terning/terningserver/dto/auth/request/TokenGetRequestDto.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.domain.auth.request; +package org.terning.terningserver.dto.auth.request; import lombok.Builder; import lombok.NonNull; @@ -6,12 +6,12 @@ import static lombok.AccessLevel.*; @Builder(access = PRIVATE) -public record TokenGetRequest( +public record TokenGetRequestDto( @NonNull String refreshToken ) { - public static TokenGetRequest of(String refreshToken) { - return TokenGetRequest.builder() + public static TokenGetRequestDto of(String refreshToken) { + return TokenGetRequestDto.builder() .refreshToken(refreshToken) .build(); } diff --git a/src/main/java/org/terning/terningserver/domain/auth/response/SignInResponse.java b/src/main/java/org/terning/terningserver/dto/auth/response/SignInResponseDto.java similarity index 70% rename from src/main/java/org/terning/terningserver/domain/auth/response/SignInResponse.java rename to src/main/java/org/terning/terningserver/dto/auth/response/SignInResponseDto.java index 7a35da1..7cfa536 100644 --- a/src/main/java/org/terning/terningserver/domain/auth/response/SignInResponse.java +++ b/src/main/java/org/terning/terningserver/dto/auth/response/SignInResponseDto.java @@ -1,4 +1,4 @@ -package org.terning.terningserver.domain.auth.response; +package org.terning.terningserver.dto.auth.response; import lombok.Builder; import org.terning.terningserver.domain.Token; @@ -7,14 +7,14 @@ import static lombok.AccessLevel.PRIVATE; @Builder(access = PRIVATE) -public record SignInResponse( +public record SignInResponseDto( String accessToken, String refreshToken, Long userId, AuthType authType ) { - public static SignInResponse of(Token token, Long userId, AuthType authType) { - return SignInResponse.builder() + public static SignInResponseDto of(Token token, Long userId, AuthType authType) { + return SignInResponseDto.builder() .accessToken(token.getAccessToken()) .refreshToken(token.getRefreshToken()) .userId(userId) diff --git a/src/main/java/org/terning/terningserver/dto/auth/response/SignUpFilterResponseDto.java b/src/main/java/org/terning/terningserver/dto/auth/response/SignUpFilterResponseDto.java new file mode 100644 index 0000000..761ddb5 --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/auth/response/SignUpFilterResponseDto.java @@ -0,0 +1,4 @@ +package org.terning.terningserver.dto.auth.response; + +public record SignUpFilterResponseDto() { +} diff --git a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java new file mode 100644 index 0000000..e7148df --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java @@ -0,0 +1,17 @@ +package org.terning.terningserver.dto.auth.response; + +import lombok.Builder; +import lombok.NonNull; + +import static lombok.AccessLevel.*; + +@Builder(access = PRIVATE) +public record TokenGetResponseDto(@NonNull String accessToken +) { + + public static TokenGetResponseDto of(String accessToken) { + return TokenGetResponseDto.builder() + .accessToken(accessToken) + .build(); + } +} diff --git a/src/main/java/org/terning/terningserver/service/AuthService.java b/src/main/java/org/terning/terningserver/service/AuthService.java index 444de1f..c527e90 100644 --- a/src/main/java/org/terning/terningserver/service/AuthService.java +++ b/src/main/java/org/terning/terningserver/service/AuthService.java @@ -1,19 +1,19 @@ package org.terning.terningserver.service; import org.terning.terningserver.domain.User; -import org.terning.terningserver.domain.auth.request.SignInRequest; -import org.terning.terningserver.domain.auth.response.SignInResponse; -import org.terning.terningserver.domain.auth.response.TokenGetResponse; +import org.terning.terningserver.dto.auth.request.SignInRequestDto; +import org.terning.terningserver.dto.auth.response.SignInResponseDto; +import org.terning.terningserver.dto.auth.response.TokenGetResponseDto; public interface AuthService { - SignInResponse signIn(User user, SignInRequest request); + SignInResponseDto signIn(User user, SignInRequestDto request); - User saveUser(String authAccessToken, SignInRequest request); + User saveUser(String authAccessToken, SignInRequestDto request); void signOut(long userId); void withdraw(long userId); - TokenGetResponse reissueToken(String refreshToken); + TokenGetResponseDto reissueToken(String refreshToken); } diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index a4fad8e..c0c5511 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -9,9 +9,9 @@ import org.terning.terningserver.config.ValueConfig; import org.terning.terningserver.domain.Token; import org.terning.terningserver.domain.User; -import org.terning.terningserver.domain.auth.request.SignInRequest; -import org.terning.terningserver.domain.auth.response.SignInResponse; -import org.terning.terningserver.domain.auth.response.TokenGetResponse; +import org.terning.terningserver.dto.auth.request.SignInRequestDto; +import org.terning.terningserver.dto.auth.response.SignInResponseDto; +import org.terning.terningserver.dto.auth.response.TokenGetResponseDto; import org.terning.terningserver.domain.enums.AuthType; import org.terning.terningserver.exception.CustomException; import org.terning.terningserver.jwt.JwtTokenProvider; @@ -37,14 +37,14 @@ public class AuthServiceImpl implements AuthService { @Override @Transactional - public SignInResponse signIn(User user, SignInRequest request) { + public SignInResponseDto signIn(User user, SignInRequestDto request) { User authenticatedUser = getUser(user.getAuthAccessToken(), request.authType()); val token = getToken(authenticatedUser); - return SignInResponse.of(token, authenticatedUser.getId(), authenticatedUser.getAuthType()); + return SignInResponseDto.of(token, authenticatedUser.getId(), authenticatedUser.getAuthType()); } @Transactional - public User saveUser(String authAccessToken, SignInRequest request) { + public User saveUser(String authAccessToken, SignInRequestDto request) { User user = User.builder() .authAccessToken(authAccessToken) .authType(request.authType()) @@ -67,11 +67,11 @@ public void withdraw(long userId) { } @Override - public TokenGetResponse reissueToken(String refreshToken) { + public TokenGetResponseDto reissueToken(String refreshToken) { val user = findUser(refreshToken); val token = Optional.ofNullable(generateAccessToken(user.getId())) .orElseThrow(() -> new CustomException(TOKEN_REISSUE_FAILED)); - return TokenGetResponse.of(token); + return TokenGetResponseDto.of(token); } private User getUser(String authAccessToken, AuthType authType) { diff --git a/src/main/java/org/terning/terningserver/service/SignUpFilterService.java b/src/main/java/org/terning/terningserver/service/SignUpFilterService.java index d5ac127..e25b51c 100644 --- a/src/main/java/org/terning/terningserver/service/SignUpFilterService.java +++ b/src/main/java/org/terning/terningserver/service/SignUpFilterService.java @@ -4,7 +4,7 @@ import org.springframework.stereotype.Service; import org.terning.terningserver.domain.Filter; import org.terning.terningserver.domain.User; -import org.terning.terningserver.domain.auth.request.SignUpFilterRequest; +import org.terning.terningserver.dto.auth.request.SignUpFilterRequestDto; import org.terning.terningserver.domain.enums.Grade; import org.terning.terningserver.domain.enums.WorkingPeriod; import org.terning.terningserver.exception.CustomException; @@ -20,7 +20,7 @@ public class SignUpFilterService { private final FilterRepository filterRepository; private final UserRepository userRepository; - public void signUpFilter(Long userId, SignUpFilterRequest request) { + public void signUpFilter(Long userId, SignUpFilterRequestDto request) { User user = userRepository.findById(userId).orElseThrow(() -> new CustomException(SIGN_UP_FILTER_FAILED)); int gradeKey = request.grade(); From 9d3b2a52422547f92a04af5c43243dd6f431aba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:39:11 +0900 Subject: [PATCH 118/205] =?UTF-8?q?[=E2=9C=A8feat/#39]:=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B4=20=EA=B3=B5=EA=B3=A0=20id=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B4=EA=B3=B5=EA=B3=A0=20=EC=B0=BE=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/InternshipDetailController.java | 4 ++-- .../controller/ScrapController.java | 10 ++++------ .../controller/SearchController.java | 10 +++------- .../swagger/InternshipDetailSwagger.java | 6 ++---- .../controller/swagger/SearchSwagger.java | 6 +++--- .../terning/terningserver/domain/Scrap.java | 1 + ...e.java => InternshipDetailResponseDto.java} | 6 +++--- .../scrap/request/CreateScrapRequestDto.java | 5 +++++ ...=> PopularAnnouncementListResponseDto.java} | 9 +++------ .../service/InternshipDetailService.java | 8 +++----- .../terningserver/service/ScrapService.java | 3 +++ .../service/ScrapServiceImpl.java | 18 ++++++++++++++---- .../terningserver/service/SearchService.java | 10 +++++----- 13 files changed, 51 insertions(+), 45 deletions(-) rename src/main/java/org/terning/terningserver/dto/internship_detail/{InternshipDetailResponse.java => InternshipDetailResponseDto.java} (87%) create mode 100644 src/main/java/org/terning/terningserver/dto/scrap/request/CreateScrapRequestDto.java rename src/main/java/org/terning/terningserver/dto/search/response/{PopularAnnouncementListResponse.java => PopularAnnouncementListResponseDto.java} (76%) diff --git a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java index f29bc33..a7aef3a 100644 --- a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java +++ b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java @@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.terning.terningserver.controller.swagger.InternshipDetailSwagger; -import org.terning.terningserver.dto.internship_detail.InternshipDetailResponse; +import org.terning.terningserver.dto.internship_detail.InternshipDetailResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.service.InternshipDetailService; @@ -22,7 +22,7 @@ public class InternshipDetailController implements InternshipDetailSwagger { private final InternshipDetailService internshipDetailService; @GetMapping("/announcements/{internshipAnnouncementId}") - public ResponseEntity> getInternshipDetail( + public ResponseEntity> getInternshipDetail( @PathVariable("internshipAnnouncementId") Long internshipAnnouncementId) { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_INTERNSHIP_DETAIL, diff --git a/src/main/java/org/terning/terningserver/controller/ScrapController.java b/src/main/java/org/terning/terningserver/controller/ScrapController.java index 0450fe5..371f8ea 100644 --- a/src/main/java/org/terning/terningserver/controller/ScrapController.java +++ b/src/main/java/org/terning/terningserver/controller/ScrapController.java @@ -1,10 +1,8 @@ package org.terning.terningserver.controller; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; import org.terning.terningserver.service.ScrapService; @RestController @@ -14,7 +12,7 @@ public class ScrapController { private final ScrapService scrapService; @PostMapping("/scraps/{internshipAnnouncementId}") - public void createScrap(@PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequest request) { - scrapService. + public void createScrap(@PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request) { + scrapService.createScrap(internshipAnnouncementId, request); } } diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index 1eaf9b3..7e5b564 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -7,13 +7,9 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.terning.terningserver.controller.swagger.SearchSwagger; -import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; +import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; -import org.terning.terningserver.exception.enums.SuccessMessage; import org.terning.terningserver.service.SearchService; -import org.terning.terningserver.util.DateUtil; - -import java.time.LocalDate; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS; @@ -27,7 +23,7 @@ public class SearchController implements SearchSwagger { private final SearchService searchService; @GetMapping("/search/views") - public ResponseEntity> getMostViewedAnnouncements() { + public ResponseEntity> getMostViewedAnnouncements() { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_MOST_VIEWED_ANNOUNCEMENTS, @@ -36,7 +32,7 @@ public ResponseEntity> getMostV } @GetMapping("/search/scraps") - public ResponseEntity> getMostScrappedAnnouncements() { + public ResponseEntity> getMostScrappedAnnouncements() { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS, searchService.getMostScrappedAnnouncements() diff --git a/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java index 5f37062..906bd1d 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java @@ -2,15 +2,13 @@ import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; -import org.terning.terningserver.dto.internship_detail.InternshipDetailResponse; +import org.terning.terningserver.dto.internship_detail.InternshipDetailResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; @Tag(name = "InternshipDetail", description = "공고 상세 페이지 관련 API") @@ -21,7 +19,7 @@ public interface InternshipDetailSwagger { @ApiResponse(responseCode = "200", description = "공고 상세 정보 불러오기에 성공했습니다", content = @Content(mediaType = "application/json")), @ApiResponse(responseCode = "404", description = "해당 id에 해당하는 인턴 공고가 존재하지 않습니다", content = @Content(mediaType = "application/json")) }) - ResponseEntity> getInternshipDetail( + ResponseEntity> getInternshipDetail( @PathVariable("internshipAnnouncementId") Long internshipAnnouncementId ); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java index 7298c49..b481d98 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java @@ -7,7 +7,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; -import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; +import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; @Tag(name = "Search", description = "탐색 관련 API") @@ -17,7 +17,7 @@ public interface SearchSwagger { @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "요청에 성공하였습니다.", content = @Content(mediaType = "application/json")) }) - ResponseEntity> getMostViewedAnnouncements( + ResponseEntity> getMostViewedAnnouncements( ); @@ -25,7 +25,7 @@ ResponseEntity> getMostViewedAn @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "요청에 성공하였습니다.", content = @Content(mediaType = "application/json")) }) - ResponseEntity> getMostScrappedAnnouncements( + ResponseEntity> getMostScrappedAnnouncements( ); } diff --git a/src/main/java/org/terning/terningserver/domain/Scrap.java b/src/main/java/org/terning/terningserver/domain/Scrap.java index 0c4b0a3..40a5c46 100644 --- a/src/main/java/org/terning/terningserver/domain/Scrap.java +++ b/src/main/java/org/terning/terningserver/domain/Scrap.java @@ -34,4 +34,5 @@ public class Scrap extends BaseTimeEntity { @Column(nullable = false) private Color color; // 스크랩 색상 (사용자가 지정) + } diff --git a/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java b/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java similarity index 87% rename from src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java rename to src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java index b08dbfe..41d065b 100644 --- a/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponse.java +++ b/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java @@ -6,7 +6,7 @@ import org.terning.terningserver.util.DateUtil; @Builder -public record InternshipDetailResponse( +public record InternshipDetailResponseDto( String dDay, String title, String deadline, @@ -23,8 +23,8 @@ public record InternshipDetailResponse( String url, boolean isScrapped ) { - public static InternshipDetailResponse of(InternshipAnnouncement announcement, Company company, boolean isScrapped) { - return InternshipDetailResponse.builder() + public static InternshipDetailResponseDto of(InternshipAnnouncement announcement, Company company, boolean isScrapped) { + return InternshipDetailResponseDto.builder() .dDay(DateUtil.convert(announcement.getDeadline())) .title(announcement.getTitle()) .deadline(DateUtil.convertDeadline(announcement.getDeadline())) diff --git a/src/main/java/org/terning/terningserver/dto/scrap/request/CreateScrapRequestDto.java b/src/main/java/org/terning/terningserver/dto/scrap/request/CreateScrapRequestDto.java new file mode 100644 index 0000000..60c6d13 --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/scrap/request/CreateScrapRequestDto.java @@ -0,0 +1,5 @@ +package org.terning.terningserver.dto.scrap.request; + +public class CreateScrapRequestDto { + +} diff --git a/src/main/java/org/terning/terningserver/dto/search/response/PopularAnnouncementListResponse.java b/src/main/java/org/terning/terningserver/dto/search/response/PopularAnnouncementListResponseDto.java similarity index 76% rename from src/main/java/org/terning/terningserver/dto/search/response/PopularAnnouncementListResponse.java rename to src/main/java/org/terning/terningserver/dto/search/response/PopularAnnouncementListResponseDto.java index 39c2e05..a1908c9 100644 --- a/src/main/java/org/terning/terningserver/dto/search/response/PopularAnnouncementListResponse.java +++ b/src/main/java/org/terning/terningserver/dto/search/response/PopularAnnouncementListResponseDto.java @@ -1,14 +1,11 @@ package org.terning.terningserver.dto.search.response; -import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Data; import org.terning.terningserver.domain.InternshipAnnouncement; import java.util.List; -import java.util.stream.Collectors; -public record PopularAnnouncementListResponse( +public record PopularAnnouncementListResponseDto( List announcements ) { @@ -27,8 +24,8 @@ public static MostViewedAndScrappedAnnouncement from(InternshipAnnouncement anno } } - public static PopularAnnouncementListResponse of(List announcements) { - return new PopularAnnouncementListResponse( + public static PopularAnnouncementListResponseDto of(List announcements) { + return new PopularAnnouncementListResponseDto( announcements.stream().map(MostViewedAndScrappedAnnouncement::from).toList() ); } diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java index fbc04c5..18e7ab3 100644 --- a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java @@ -5,14 +5,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.InternshipAnnouncement; -import org.terning.terningserver.dto.internship_detail.InternshipDetailResponse; +import org.terning.terningserver.dto.internship_detail.InternshipDetailResponseDto; import org.terning.terningserver.exception.CustomException; import org.terning.terningserver.exception.enums.ErrorMessage; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import org.terning.terningserver.repository.scrap.ScrapRepository; -import static org.terning.terningserver.exception.enums.ErrorMessage.NOT_FOUND_INTERN_EXCEPTION; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -21,12 +19,12 @@ public class InternshipDetailService { private final InternshipRepository internshipRepository; private final ScrapRepository scrapRepository; - public InternshipDetailResponse getInternshipDetail(Long internshipAnnouncementId) { + public InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId) { InternshipAnnouncement announcement = internshipRepository.findById(internshipAnnouncementId) .orElseThrow(() -> new CustomException(ErrorMessage.NOT_FOUND_INTERN_EXCEPTION)); - return InternshipDetailResponse.of( + return InternshipDetailResponseDto.of( announcement, announcement.getCompany(), scrapRepository.existsByInternshipAnnouncementIdAndUserId(announcement.getId(), 1L) ); diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java index d940a73..e22b07a 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapService.java +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -1,9 +1,12 @@ package org.terning.terningserver.service; +import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import java.util.List; public interface ScrapService { List getTodayScrap(Long userId); + + void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request); } diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index d9caf64..0722904 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -2,18 +2,26 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.Scrap; +import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; +import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import org.terning.terningserver.repository.scrap.ScrapRepository; import java.time.LocalDate; import java.util.List; import java.util.stream.Collectors; +import static org.terning.terningserver.exception.enums.ErrorMessage.NOT_FOUND_INTERN_EXCEPTION; + @Service @RequiredArgsConstructor public class ScrapServiceImpl implements ScrapService { private final ScrapRepository scrapRepository; + private final InternshipRepository internshipRepository; @Override public List getTodayScrap(Long userId){ @@ -24,11 +32,13 @@ public List getTodayScrap(Long userId){ } @Override - public void createPost(CreateScrapRequest request) { - + public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request) { + getInternshipAnnouncement(internshipAnnouncementId); + Scrap. } - private void getInternshipAnnouncement() { - internshipRepository.findById() + private InternshipAnnouncement getInternshipAnnouncement(Long internshipAnnouncementId) { + return internshipRepository.findById(internshipAnnouncementId) + .orElseThrow(() -> new CustomException(NOT_FOUND_INTERN_EXCEPTION)); } } diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index f6424b0..f14dfa4 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -5,7 +5,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.InternshipAnnouncement; -import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponse; +import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponseDto; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import java.util.List; @@ -16,14 +16,14 @@ public class SearchService { private final InternshipRepository internshipRepository; - public PopularAnnouncementListResponse getMostViewedAnnouncements() { + public PopularAnnouncementListResponseDto getMostViewedAnnouncements() { List mostViewedInternships = internshipRepository.getMostViewedInternship(); - return PopularAnnouncementListResponse.of(mostViewedInternships); + return PopularAnnouncementListResponseDto.of(mostViewedInternships); } - public PopularAnnouncementListResponse getMostScrappedAnnouncements() { + public PopularAnnouncementListResponseDto getMostScrappedAnnouncements() { List mostViewedInternships = internshipRepository.getMostScrappedInternship(); - return PopularAnnouncementListResponse.of(mostViewedInternships); + return PopularAnnouncementListResponseDto.of(mostViewedInternships); } } From c1a7fb4153b252c3450bb0bfe883f0a2e229174d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 21:02:14 +0900 Subject: [PATCH 119/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor:/#17]:=20Sw?= =?UTF-8?q?agger=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AuthController.java | 11 ++++---- .../controller/swagger/AuthSwagger.java | 27 +++++++++++-------- src/main/resources/application-dev.yml | 2 +- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index 1f87c5b..e8d62ac 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -4,6 +4,7 @@ import lombok.val; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.terning.terningserver.controller.swagger.AuthSwagger; import org.terning.terningserver.domain.User; import org.terning.terningserver.dto.auth.request.SignInRequestDto; import org.terning.terningserver.dto.auth.request.SignUpFilterRequestDto; @@ -24,9 +25,11 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/auth") -public class AuthController { +public class AuthController implements AuthSwagger { private final AuthService authService; + private final SignUpService signUpService; + private final SignUpFilterService signUpFilterService; @PostMapping("/sign-in") public ResponseEntity> signIn( @@ -39,8 +42,6 @@ public ResponseEntity> signIn( return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_IN, signInResponse)); } - private final SignUpService signUpService; - private final SignUpFilterService signUpFilterService; // TODO: 에러 메시지 위치 @PostMapping("/token-reissue") @@ -74,7 +75,7 @@ public ResponseEntity> filter( @PostMapping("/logout") public ResponseEntity signOut(Principal principal) { // val userId = Long.parseLong(principal.getName()); - val userId = 6; + val userId = 1; authService.signOut(userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_OUT)); @@ -83,7 +84,7 @@ public ResponseEntity signOut(Principal principal) { @DeleteMapping("/withdraw") public ResponseEntity withdraw(Principal principal) { // val userId = Long.parseLong(principal.getName()); - val userId = 7; + val userId = 2; authService.withdraw(userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_WITHDRAW)); diff --git a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java index 1107fb1..75dc59d 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java @@ -3,44 +3,49 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.terning.terningserver.dto.auth.request.SignInRequestDto; +import org.terning.terningserver.dto.auth.request.SignUpFilterRequestDto; +import org.terning.terningserver.dto.auth.request.SignUpRequestDto; import org.terning.terningserver.dto.auth.response.SignInResponseDto; import org.terning.terningserver.dto.auth.response.SignUpFilterResponseDto; import org.terning.terningserver.dto.auth.response.TokenGetResponseDto; -import org.terning.terningserver.domain.enums.AuthType; import org.terning.terningserver.exception.dto.SuccessResponse; +import java.security.Principal; + @Tag(name = "Auth", description = "소셜 로그인 및 회원가입 API") public interface AuthSwagger { @Operation(summary = "소셜 로그인", description = "AuthType에 맞는 소셜 로그인 API") ResponseEntity> signIn( - String accessToken, - String refreshToken, - Long userId, - AuthType authType + @RequestHeader("Authorization") String authAccessToken, + @RequestBody SignInRequestDto request ); @Operation(summary = "토큰 재발급", description = "토큰 재발급 API") ResponseEntity> reissueToken( - String accessToken + @RequestHeader("Authorization") String refreshToken ); @Operation(summary = "사용자 필터링 정보 생성", description = "사용자 필터링 정보 생성 API") ResponseEntity> filter( - + @RequestHeader("User-Id") Long userId, + @RequestBody SignUpFilterRequestDto request ); @Operation(summary = "회원가입", description = "회원가입 API") ResponseEntity> signUp( + @RequestHeader("User-Id") Long userId, + @RequestBody SignUpRequestDto request ); @Operation(summary = "로그아웃", description = "로그아웃 API") - ResponseEntity signOut( - ); + ResponseEntity signOut(Principal principal); @Operation(summary = "계정탈퇴", description = "계정탈퇴 API") - ResponseEntity withdraw( - ); + ResponseEntity withdraw(Principal principal); } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index d592417..df28152 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -1,7 +1,7 @@ spring: datasource: driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://localhost:5432/terning + url: jdbc:postgresql://localhost:5432/terning55 username: ${USER_ID} password: ${USER_PW} From c883a56bdc465164822d6803aed94b4dc05e5622 Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 15 Jul 2024 21:08:44 +0900 Subject: [PATCH 120/205] =?UTF-8?q?[=E2=9C=A8feat/#40]=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94=20>=20=EC=9B=94=EA=B0=84=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94(=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=B7=B0)=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CalendarController.java | 13 +++++ .../controller/swagger/CalendarSwagger.java | 8 ++++ .../response/MonthlyListResponseDto.java | 47 +++++++++++++++++++ .../exception/enums/SuccessMessage.java | 3 +- .../terningserver/service/ScrapService.java | 2 + .../service/ScrapServiceImpl.java | 37 ++++++++++++++- 6 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyListResponseDto.java diff --git a/src/main/java/org/terning/terningserver/controller/CalendarController.java b/src/main/java/org/terning/terningserver/controller/CalendarController.java index c0b2186..29f6320 100644 --- a/src/main/java/org/terning/terningserver/controller/CalendarController.java +++ b/src/main/java/org/terning/terningserver/controller/CalendarController.java @@ -5,12 +5,14 @@ import org.springframework.web.bind.annotation.*; import org.terning.terningserver.controller.swagger.CalendarSwagger; import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; +import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.service.ScrapService; import java.util.List; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MONTHLY_SCRAPS; +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST; @RestController @RequiredArgsConstructor @@ -30,6 +32,17 @@ public ResponseEntity>> getMonth return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_MONTHLY_SCRAPS, monthlyScraps)); } + @GetMapping("/calendar/monthly-list") + public ResponseEntity>> getMonthlyScrapsAsList( + @RequestHeader("Authorization") String token, + @RequestParam("year") int year, + @RequestParam("month") int month + ){ + Long userId = getUserIdFromToken(token); + List monthlyScraps = scrapService.getMonthlyScrapsAsList(userId, year, month); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST, monthlyScraps)); + } + private Long getUserIdFromToken(String token){ //실제 토큰에서 userId를 받아오는 로직 구현 return 1L; //임시로 사용자 ID 1로 반환 diff --git a/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java index 474cc85..4f48887 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; +import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; import java.time.Month; @@ -18,4 +19,11 @@ ResponseEntity>> getMonthlyScrap int year, int month ); + + @Operation(summary = "캘린더 > 월간 스크랩 공고 조회 (리스트)", description = "월간 스크랩 공고를 리스트로 조회하는 API") + ResponseEntity>> getMonthlyScrapsAsList( + String token, + int year, + int month + ); } diff --git a/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyListResponseDto.java b/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyListResponseDto.java new file mode 100644 index 0000000..f9ec19c --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyListResponseDto.java @@ -0,0 +1,47 @@ +package org.terning.terningserver.dto.calendar.response; + +import lombok.Builder; + +import java.util.List; + +@Builder +public record MonthlyListResponseDto( + String deadline, + List scraps +) { + @Builder + public static record ScrapDetail( + Long scrapId, + Long internshipAnnouncementId, + String title, + String dDay, + String workingPeriod, + String color, + String companyImage, + int startYear, + int startMonth + ){ + public static ScrapDetail of(Long scrapId, Long internshipAnnouncementId, String title, + String dDay, String workingPeriod, String color, + String companyImage, int startYear, int startMonth){ + return ScrapDetail.builder() + .scrapId(scrapId) + .internshipAnnouncementId(internshipAnnouncementId) + .title(title) + .dDay(dDay) + .workingPeriod(workingPeriod) + .color(color) + .companyImage(companyImage) + .startYear(startYear) + .startMonth(startMonth) + .build(); + } + } + + public static MonthlyListResponseDto of(String deadline, List scraps){ + return MonthlyListResponseDto.builder() + .deadline(deadline) + .scraps(scraps) + .build(); + } +} diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 48d50a3..7621100 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -18,7 +18,8 @@ public enum SuccessMessage { SUCCESS_GET_INTERNSHIP_DETAIL(200, "공고 상세 정보 불러오기에 성공했습니다"), // Calendar (캘린더 화면) - SUCCESS_GET_MONTHLY_SCRAPS(200, "캘린더 > (월간) 스크랩 된 공고 정보 불러오기를 성공했습니다"); + SUCCESS_GET_MONTHLY_SCRAPS(200, "캘린더 > (월간) 스크랩 된 공고 정보 불러오기를 성공했습니다"), + SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST(200, "캘린더 > (월간) 스크랩 된 공고 정보 (리스트) 불러오기를 성공했습니다"); ; private final int status; diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java index c9d1175..308401e 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapService.java +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -1,6 +1,7 @@ package org.terning.terningserver.service; import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; +import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import java.util.List; @@ -8,4 +9,5 @@ public interface ScrapService { List getTodayScrap(Long userId); List getMonthlyScraps(Long userId, int year, int month); + List getMonthlyScrapsAsList(Long userId, int year, int month); } diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 83c4345..8860a11 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -4,8 +4,10 @@ import org.springframework.stereotype.Service; import org.terning.terningserver.domain.Scrap; import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; +import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import org.terning.terningserver.repository.scrap.ScrapRepository; +import org.terning.terningserver.util.DateUtil; import java.time.LocalDate; import java.util.List; @@ -35,7 +37,7 @@ public List getMonthlyScraps(Long userId, int year, i List scraps = scrapRepository.findByUserIdAndInternshipAnnouncement_DeadlineBetween(userId, start, end); - // deadline 별로 그룹화 + //deadline 별로 그룹화 Map> scrapsByDeadline = scraps.stream() .collect(Collectors.groupingBy(s -> s.getInternshipAnnouncement().getDeadline())); @@ -52,4 +54,37 @@ public List getMonthlyScraps(Long userId, int year, i )) .toList(); } + + @Override + public List getMonthlyScrapsAsList(Long userId, int year, int month){ + + //모든 월의 시작일은 1, 마지막일은 해당 다음월의 하루 전 + LocalDate start = LocalDate.of(year, month, 1); + LocalDate end = start.plusMonths(1).minusDays(1); + + List scraps = scrapRepository.findByUserIdAndInternshipAnnouncement_DeadlineBetween(userId, start, end); + + //deadline 별로 그룹화 + Map> scrapsByDeadline = scraps.stream() + .collect(Collectors.groupingBy(s -> s.getInternshipAnnouncement().getDeadline())); + + return scrapsByDeadline.entrySet().stream() + .map(entry -> MonthlyListResponseDto.of( + entry.getKey().toString(), + entry.getValue().stream() + .map(s -> MonthlyListResponseDto.ScrapDetail.of( + s.getId(), + s.getInternshipAnnouncement().getId(), + s.getInternshipAnnouncement().getTitle(), + DateUtil.convert(s.getInternshipAnnouncement().getDeadline()), + s.getInternshipAnnouncement().getWorkingPeriod(), + s.getColor().getColorValue(), + s.getInternshipAnnouncement().getCompany().getCompanyImage(), + s.getInternshipAnnouncement().getStartYear(), + s.getInternshipAnnouncement().getStartMonth() + )) + .toList() + )) + .toList(); + } } From 7a448d10457bc989dd761fc85996ab036f5dafca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 21:13:54 +0900 Subject: [PATCH 121/205] =?UTF-8?q?[=E2=9C=A8feat/#39]:=20Swagger=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InternshipDetailController.java | 2 +- .../controller/ScrapController.java | 8 ++++++- .../swagger/InternshipDetailSwagger.java | 4 ---- .../controller/swagger/ScrapSwagger.java | 18 ++++++++++++++ .../controller/swagger/SearchSwagger.java | 6 ----- .../terning/terningserver/domain/Scrap.java | 15 ++++++++++++ .../terningserver/domain/enums/Color.java | 2 ++ .../scrap/request/CreateScrapRequestDto.java | 4 +++- .../exception/enums/SuccessMessage.java | 6 +++-- .../service/ScrapServiceImpl.java | 24 ++++++++++++++++++- 10 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java diff --git a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java index a7aef3a..3dd5455 100644 --- a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java +++ b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java @@ -23,7 +23,7 @@ public class InternshipDetailController implements InternshipDetailSwagger { @GetMapping("/announcements/{internshipAnnouncementId}") public ResponseEntity> getInternshipDetail( - @PathVariable("internshipAnnouncementId") Long internshipAnnouncementId) { + @PathVariable Long internshipAnnouncementId) { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_INTERNSHIP_DETAIL, internshipDetailService.getInternshipDetail(internshipAnnouncementId) diff --git a/src/main/java/org/terning/terningserver/controller/ScrapController.java b/src/main/java/org/terning/terningserver/controller/ScrapController.java index 371f8ea..d0f01d2 100644 --- a/src/main/java/org/terning/terningserver/controller/ScrapController.java +++ b/src/main/java/org/terning/terningserver/controller/ScrapController.java @@ -1,10 +1,15 @@ package org.terning.terningserver.controller; import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; +import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.exception.enums.SuccessMessage; import org.terning.terningserver.service.ScrapService; +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_CREATE_SCRAP; + @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") @@ -12,7 +17,8 @@ public class ScrapController { private final ScrapService scrapService; @PostMapping("/scraps/{internshipAnnouncementId}") - public void createScrap(@PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request) { + public ResponseEntity createScrap(@PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request) { scrapService.createScrap(internshipAnnouncementId, request); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_CREATE_SCRAP)); } } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java index 906bd1d..7df1e9e 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java @@ -15,10 +15,6 @@ public interface InternshipDetailSwagger { @Operation(summary = "공고 상세 페이지", description = "인턴 공고의 상세 정보를 불러오는 API") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "공고 상세 정보 불러오기에 성공했습니다", content = @Content(mediaType = "application/json")), - @ApiResponse(responseCode = "404", description = "해당 id에 해당하는 인턴 공고가 존재하지 않습니다", content = @Content(mediaType = "application/json")) - }) ResponseEntity> getInternshipDetail( @PathVariable("internshipAnnouncementId") Long internshipAnnouncementId ); diff --git a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java new file mode 100644 index 0000000..521796c --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java @@ -0,0 +1,18 @@ +package org.terning.terningserver.controller.swagger; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; +import org.terning.terningserver.exception.dto.SuccessResponse; + +@Tag(name="Scrap", description = "스크랩 관련 API") +public interface ScrapSwagger { + + @Operation(summary = "스크랩 추가", description = "사용자가 스크랩을 추가하는 API") + ResponseEntity createScrap( + @PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request + ); +} diff --git a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java index b481d98..58f39f0 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java @@ -14,17 +14,11 @@ public interface SearchSwagger { @Operation(summary = "탐색 > 지금 조회수 많은 공고", description = "탐색 화면에서 조회수 많은 공고를 불러오는 API") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "요청에 성공하였습니다.", content = @Content(mediaType = "application/json")) - }) ResponseEntity> getMostViewedAnnouncements( ); @Operation(summary = "탐색 > 지금 스크랩 수 많은 공고", description = "탐색 화면에서 스크랩 수 많은 공고를 불러오는 API") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "요청에 성공하였습니다.", content = @Content(mediaType = "application/json")) - }) ResponseEntity> getMostScrappedAnnouncements( ); diff --git a/src/main/java/org/terning/terningserver/domain/Scrap.java b/src/main/java/org/terning/terningserver/domain/Scrap.java index 40a5c46..89bef37 100644 --- a/src/main/java/org/terning/terningserver/domain/Scrap.java +++ b/src/main/java/org/terning/terningserver/domain/Scrap.java @@ -1,6 +1,7 @@ package org.terning.terningserver.domain; import jakarta.persistence.*; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.terning.terningserver.domain.common.BaseTimeEntity; @@ -34,5 +35,19 @@ public class Scrap extends BaseTimeEntity { @Column(nullable = false) private Color color; // 스크랩 색상 (사용자가 지정) + @Builder + private Scrap(User user, InternshipAnnouncement internshipAnnouncement, Color color) { + this.user = user; + this.internshipAnnouncement = internshipAnnouncement; + this.color = color; + } + + public static Scrap create(User user, InternshipAnnouncement internshipAnnouncement, Color color) { + return Scrap.builder() + .user(user) + .internshipAnnouncement(internshipAnnouncement) + .color(color) + .build(); + } } diff --git a/src/main/java/org/terning/terningserver/domain/enums/Color.java b/src/main/java/org/terning/terningserver/domain/enums/Color.java index c8a5beb..bd70d1b 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/Color.java +++ b/src/main/java/org/terning/terningserver/domain/enums/Color.java @@ -1,9 +1,11 @@ package org.terning.terningserver.domain.enums; +import lombok.Getter; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor +@Getter public enum Color { RED(0, "ED4E54"), diff --git a/src/main/java/org/terning/terningserver/dto/scrap/request/CreateScrapRequestDto.java b/src/main/java/org/terning/terningserver/dto/scrap/request/CreateScrapRequestDto.java index 60c6d13..37fb183 100644 --- a/src/main/java/org/terning/terningserver/dto/scrap/request/CreateScrapRequestDto.java +++ b/src/main/java/org/terning/terningserver/dto/scrap/request/CreateScrapRequestDto.java @@ -1,5 +1,7 @@ package org.terning.terningserver.dto.scrap.request; -public class CreateScrapRequestDto { +public record CreateScrapRequestDto( + int color +) { } diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index ba592d7..cff337e 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -15,8 +15,10 @@ public enum SuccessMessage { SUCCESS_GET_MOST_SCRAPPED_ANNOUNCEMENTS(200, "탐색 > 스크랩 수 많은 공고를 조회하는데 성공했습니다"), // 인턴 공고 - SUCCESS_GET_INTERNSHIP_DETAIL(200, "공고 상세 정보 불러오기에 성공했습니다"); - ; + SUCCESS_GET_INTERNSHIP_DETAIL(200, "공고 상세 정보 불러오기에 성공했습니다"), + + // 스크랩 + SUCCESS_CREATE_SCRAP(201, "스크랩 추가에 성공했습니다"); private final int status; private final String message; diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 0722904..c42fb62 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -4,17 +4,22 @@ import org.springframework.stereotype.Service; import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.domain.Scrap; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.domain.enums.Color; import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import org.terning.terningserver.exception.CustomException; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import org.terning.terningserver.repository.scrap.ScrapRepository; +import org.terning.terningserver.repository.user.UserRepository; import java.time.LocalDate; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import static org.terning.terningserver.exception.enums.ErrorMessage.NOT_FOUND_INTERN_EXCEPTION; +import static org.terning.terningserver.exception.enums.ErrorMessage.NOT_FOUND_USER_EXCEPTION; @Service @RequiredArgsConstructor @@ -22,6 +27,7 @@ public class ScrapServiceImpl implements ScrapService { private final ScrapRepository scrapRepository; private final InternshipRepository internshipRepository; + private final UserRepository userRepository; @Override public List getTodayScrap(Long userId){ @@ -34,11 +40,27 @@ public List getTodayScrap(Long userId){ @Override public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request) { getInternshipAnnouncement(internshipAnnouncementId); - Scrap. + + scrapRepository.save(Scrap.create( + findUser(1L), + getInternshipAnnouncement(internshipAnnouncementId), + findColor(request.color()) + )); + } + + private Color findColor(int color) { + return Arrays.stream(Color.values()) + .filter(c-> c.getKey() == color) + .findAny().get(); } private InternshipAnnouncement getInternshipAnnouncement(Long internshipAnnouncementId) { return internshipRepository.findById(internshipAnnouncementId) .orElseThrow(() -> new CustomException(NOT_FOUND_INTERN_EXCEPTION)); } + + private User findUser(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new CustomException(NOT_FOUND_USER_EXCEPTION)); + } } From 60dcc573bbd4250583dd44b66915234fabb0aaaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 21:19:53 +0900 Subject: [PATCH 122/205] =?UTF-8?q?[=E2=9C=A8feat/#39]:=20ScrapController?= =?UTF-8?q?=EA=B0=80=20ScrapSwagger=20=EC=83=81=EC=86=8D=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/controller/ScrapController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/controller/ScrapController.java b/src/main/java/org/terning/terningserver/controller/ScrapController.java index d0f01d2..db313de 100644 --- a/src/main/java/org/terning/terningserver/controller/ScrapController.java +++ b/src/main/java/org/terning/terningserver/controller/ScrapController.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.terning.terningserver.controller.swagger.ScrapSwagger; import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.exception.enums.SuccessMessage; @@ -13,7 +14,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") -public class ScrapController { +public class ScrapController implements ScrapSwagger { private final ScrapService scrapService; @PostMapping("/scraps/{internshipAnnouncementId}") From d90f9fd047a106e131bde900e35e30d76c48bdc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 15 Jul 2024 23:37:08 +0900 Subject: [PATCH 123/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Swa?= =?UTF-8?q?gger=20=EC=9E=AC=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/config/SecurityConfig.java | 18 +++++++++++++----- .../controller/AuthController.java | 11 +++++------ .../controller/swagger/AuthSwagger.java | 7 +++++-- .../terningserver/service/AuthServiceImpl.java | 4 ++++ 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/terning/terningserver/config/SecurityConfig.java b/src/main/java/org/terning/terningserver/config/SecurityConfig.java index 2f2c751..4a18275 100644 --- a/src/main/java/org/terning/terningserver/config/SecurityConfig.java +++ b/src/main/java/org/terning/terningserver/config/SecurityConfig.java @@ -7,6 +7,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @@ -20,6 +21,14 @@ public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; private final CustomJwtAuthenticationEntryPoint customJwtAuthenticationEntryPoint; + private static final String[] AUTH_WHITELIST = { + "/v3/api-docs/**", + "/swagger-ui.html", + "/swagger-ui/index.html#/**", + "/swagger-resources/**", + "/swagger-ui/**", + "/api/v1/auth/**" + }; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @@ -31,11 +40,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { ) .exceptionHandling(exceptionHandling -> exceptionHandling.authenticationEntryPoint(customJwtAuthenticationEntryPoint)) - .authorizeHttpRequests(authorizeHttpRequests -> - authorizeHttpRequests - .requestMatchers(new AntPathRequestMatcher("/api/v1/auth/**")).permitAll() - .requestMatchers(new AntPathRequestMatcher("/error")).permitAll() - .anyRequest().authenticated()) + .authorizeHttpRequests(auth -> { + auth.requestMatchers(AUTH_WHITELIST).permitAll(); + auth.anyRequest().authenticated(); + }) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .build(); } diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index e8d62ac..a167404 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -36,6 +36,7 @@ public ResponseEntity> signIn( @RequestHeader("Authorization") String authAccessToken, @RequestBody SignInRequestDto request ) { + System.out.println(authAccessToken + " " + request.authType()); User user = authService.saveUser(authAccessToken, request); val signInResponse = authService.signIn(user, request); @@ -62,7 +63,7 @@ public ResponseEntity> signUp( return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_UP)); } - @PostMapping("/sign-up/fileter") + @PostMapping("/sign-up/filter") public ResponseEntity> filter( @RequestHeader("User-Id") Long userId, @RequestBody SignUpFilterRequestDto request @@ -73,9 +74,8 @@ public ResponseEntity> filter( } @PostMapping("/logout") - public ResponseEntity signOut(Principal principal) { -// val userId = Long.parseLong(principal.getName()); - val userId = 1; + public ResponseEntity signOut(@RequestHeader("Authorization") String token, Principal principal) { + val userId = Long.parseLong(principal.getName()); authService.signOut(userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_OUT)); @@ -83,8 +83,7 @@ public ResponseEntity signOut(Principal principal) { @DeleteMapping("/withdraw") public ResponseEntity withdraw(Principal principal) { -// val userId = Long.parseLong(principal.getName()); - val userId = 2; + val userId = Long.parseLong(principal.getName()); authService.withdraw(userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_WITHDRAW)); diff --git a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java index 75dc59d..3e4d7b2 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java @@ -42,10 +42,13 @@ ResponseEntity> signUp( ); @Operation(summary = "로그아웃", description = "로그아웃 API") - ResponseEntity signOut(Principal principal); + ResponseEntity signOut( + @RequestHeader("Authorization") String token, + Principal principal); @Operation(summary = "계정탈퇴", description = "계정탈퇴 API") - ResponseEntity withdraw(Principal principal); + ResponseEntity withdraw( + Principal principal); } diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index c0c5511..8fe59bf 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -1,5 +1,6 @@ package org.terning.terningserver.service; +import lombok.Builder; import lombok.extern.slf4j.Slf4j; import lombok.val; import org.springframework.security.core.Authentication; @@ -39,6 +40,9 @@ public class AuthServiceImpl implements AuthService { @Transactional public SignInResponseDto signIn(User user, SignInRequestDto request) { User authenticatedUser = getUser(user.getAuthAccessToken(), request.authType()); +// System.out.println( +// "AccessToken : " + user.getAuthAccessToken() + "AuthType : " + request.authType() +// ); val token = getToken(authenticatedUser); return SignInResponseDto.of(token, authenticatedUser.getId(), authenticatedUser.getAuthType()); } From 962b75f53bf9474e0fecfa7327108b2a0fc870a7 Mon Sep 17 00:00:00 2001 From: Willy Date: Mon, 15 Jul 2024 23:43:45 +0900 Subject: [PATCH 124/205] =?UTF-8?q?[=E2=9C=A8feat/#42]=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94=20>=20=EC=9D=BC=EA=B0=84=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94(=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=B7=B0)=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CalendarController.java | 15 +++++++-- .../controller/swagger/CalendarSwagger.java | 9 +++++- .../response/DailyScrapResponseDto.java | 32 +++++++++++++++++++ .../response/MonthlyDefaultResponseDto.java | 2 +- .../response/MonthlyListResponseDto.java | 6 ++-- .../exception/enums/SuccessMessage.java | 3 +- .../terningserver/service/ScrapService.java | 3 ++ .../service/ScrapServiceImpl.java | 9 ++++++ 8 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/dto/calendar/response/DailyScrapResponseDto.java diff --git a/src/main/java/org/terning/terningserver/controller/CalendarController.java b/src/main/java/org/terning/terningserver/controller/CalendarController.java index 29f6320..4c7d961 100644 --- a/src/main/java/org/terning/terningserver/controller/CalendarController.java +++ b/src/main/java/org/terning/terningserver/controller/CalendarController.java @@ -4,15 +4,16 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.terning.terningserver.controller.swagger.CalendarSwagger; +import org.terning.terningserver.dto.calendar.response.DailyScrapResponseDto; import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.service.ScrapService; +import java.time.LocalDate; import java.util.List; -import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MONTHLY_SCRAPS; -import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST; +import static org.terning.terningserver.exception.enums.SuccessMessage.*; @RestController @RequiredArgsConstructor @@ -43,6 +44,16 @@ public ResponseEntity>> getMonthlyS return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST, monthlyScraps)); } + @GetMapping("/calendar/daily") + public ResponseEntity>> getDailyScraps( + @RequestHeader("Authorization") String token, + @RequestParam("date") String date + ){ + Long userId = getUserIdFromToken(token); + LocalDate localDate = LocalDate.parse(date); + List dailyScraps = scrapService.getDailyScraps(userId, localDate); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_DAILY_SCRAPS, dailyScraps)); + } private Long getUserIdFromToken(String token){ //실제 토큰에서 userId를 받아오는 로직 구현 return 1L; //임시로 사용자 ID 1로 반환 diff --git a/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java index 4f48887..4271afc 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java @@ -3,11 +3,12 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestParam; +import org.terning.terningserver.dto.calendar.response.DailyScrapResponseDto; import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; -import java.time.Month; import java.util.List; @Tag(name = "Calendar", description = "캘린더 관련 API") @@ -26,4 +27,10 @@ ResponseEntity>> getMonthlyScrapsAs int year, int month ); + + @Operation(summary = "캘린더 > 일간 스크랩 공고 조회 (리스트)", description = "일간 스크랩 공고를 리스트로 조회하는 API") + ResponseEntity>> getDailyScraps( + String token, + String date + ); } diff --git a/src/main/java/org/terning/terningserver/dto/calendar/response/DailyScrapResponseDto.java b/src/main/java/org/terning/terningserver/dto/calendar/response/DailyScrapResponseDto.java new file mode 100644 index 0000000..865617a --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/calendar/response/DailyScrapResponseDto.java @@ -0,0 +1,32 @@ +package org.terning.terningserver.dto.calendar.response; + +import lombok.Builder; +import org.terning.terningserver.domain.Scrap; +import org.terning.terningserver.util.DateUtil; + +@Builder +public record DailyScrapResponseDto( + Long scrapId, + Long internshipAnnouncementId, + String title, + String dDay, + String workingPeriod, + String color, + String companyImage, + int startYear, + int startMonth +) { + public static DailyScrapResponseDto of(final Scrap scrap){ + return DailyScrapResponseDto.builder() + .scrapId(scrap.getId()) + .internshipAnnouncementId(scrap.getInternshipAnnouncement().getId()) + .title(scrap.getInternshipAnnouncement().getTitle()) + .dDay(DateUtil.convert(scrap.getInternshipAnnouncement().getDeadline())) + .workingPeriod(scrap.getInternshipAnnouncement().getWorkingPeriod()) + .color(scrap.getColor().getColorValue()) + .companyImage(scrap.getInternshipAnnouncement().getCompany().getCompanyImage()) + .startYear(scrap.getInternshipAnnouncement().getStartYear()) + .startMonth(scrap.getInternshipAnnouncement().getStartMonth()) + .build(); + } +} diff --git a/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyDefaultResponseDto.java b/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyDefaultResponseDto.java index a85e228..aa26f6c 100644 --- a/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyDefaultResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyDefaultResponseDto.java @@ -16,7 +16,7 @@ public static record ScrapDetail( String title, String color ){ - public static ScrapDetail of(Long scrapId, String title, String color){ + public static ScrapDetail of(final Long scrapId, final String title, final String color){ return ScrapDetail.builder() .scrapId(scrapId) .title(title) diff --git a/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyListResponseDto.java b/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyListResponseDto.java index f9ec19c..6728160 100644 --- a/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyListResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/calendar/response/MonthlyListResponseDto.java @@ -21,9 +21,9 @@ public static record ScrapDetail( int startYear, int startMonth ){ - public static ScrapDetail of(Long scrapId, Long internshipAnnouncementId, String title, - String dDay, String workingPeriod, String color, - String companyImage, int startYear, int startMonth){ + public static ScrapDetail of(final Long scrapId, final Long internshipAnnouncementId, final String title, + final String dDay, final String workingPeriod, final String color, + final String companyImage, final int startYear, final int startMonth){ return ScrapDetail.builder() .scrapId(scrapId) .internshipAnnouncementId(internshipAnnouncementId) diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 7621100..d09a160 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -19,7 +19,8 @@ public enum SuccessMessage { // Calendar (캘린더 화면) SUCCESS_GET_MONTHLY_SCRAPS(200, "캘린더 > (월간) 스크랩 된 공고 정보 불러오기를 성공했습니다"), - SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST(200, "캘린더 > (월간) 스크랩 된 공고 정보 (리스트) 불러오기를 성공했습니다"); + SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST(200, "캘린더 > (월간) 스크랩 된 공고 정보 (리스트) 불러오기를 성공했습니다"), + SUCCESS_GET_DAILY_SCRAPS(200, "캘린더 > (일간) 스크랩 된 공고 정보 불러오기를 성공했습니다"), ; private final int status; diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java index 308401e..4d832e6 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapService.java +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -1,13 +1,16 @@ package org.terning.terningserver.service; +import org.terning.terningserver.dto.calendar.response.DailyScrapResponseDto; import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; +import java.time.LocalDate; import java.util.List; public interface ScrapService { List getTodayScrap(Long userId); List getMonthlyScraps(Long userId, int year, int month); List getMonthlyScrapsAsList(Long userId, int year, int month); + List getDailyScraps(Long userId, LocalDate date); } diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 8860a11..2363737 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.terning.terningserver.domain.Scrap; +import org.terning.terningserver.dto.calendar.response.DailyScrapResponseDto; import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; @@ -87,4 +88,12 @@ public List getMonthlyScrapsAsList(Long userId, int year )) .toList(); } + + @Override + public List getDailyScraps(Long userId, LocalDate date){ + return scrapRepository.findByUserIdAndInternshipAnnouncement_Deadline(userId, date).stream() + .map(DailyScrapResponseDto::of) + .toList(); + } } + From 801f4fcf5309d9de6e6a870ff305e357336ee890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Mon, 15 Jul 2024 23:47:09 +0900 Subject: [PATCH 125/205] =?UTF-8?q?[=E2=9C=A8feat/#39]:=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=20=EC=83=89=EC=83=81=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ScrapController.java | 14 ++++++++ .../controller/swagger/ScrapSwagger.java | 12 +++++++ .../terning/terningserver/domain/Scrap.java | 4 +++ .../scrap/request/UpdateScrapRequestDto.java | 6 ++++ .../exception/enums/ErrorMessage.java | 4 ++- .../exception/enums/SuccessMessage.java | 4 ++- .../repository/scrap/ScrapRepository.java | 2 +- .../terningserver/service/ScrapService.java | 5 +++ .../service/ScrapServiceImpl.java | 35 +++++++++++++++++-- 9 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/dto/scrap/request/UpdateScrapRequestDto.java diff --git a/src/main/java/org/terning/terningserver/controller/ScrapController.java b/src/main/java/org/terning/terningserver/controller/ScrapController.java index db313de..a663477 100644 --- a/src/main/java/org/terning/terningserver/controller/ScrapController.java +++ b/src/main/java/org/terning/terningserver/controller/ScrapController.java @@ -5,11 +5,13 @@ import org.springframework.web.bind.annotation.*; import org.terning.terningserver.controller.swagger.ScrapSwagger; import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; +import org.terning.terningserver.dto.scrap.request.UpdateScrapRequestDto; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.exception.enums.SuccessMessage; import org.terning.terningserver.service.ScrapService; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_CREATE_SCRAP; +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_UPDATE_SCRAP; @RestController @RequiredArgsConstructor @@ -22,4 +24,16 @@ public ResponseEntity createScrap(@PathVariable Long internship scrapService.createScrap(internshipAnnouncementId, request); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_CREATE_SCRAP)); } + + @DeleteMapping("/scraps/{scrapId}") + public ResponseEntity deleteScrap(@PathVariable Long scrapId) { + scrapService.deleteScrap(scrapId); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_CREATE_SCRAP)); + } + + @PatchMapping("/scraps/{scrapId}") + public ResponseEntity updateScrapColor(@PathVariable Long scrapId, @RequestBody UpdateScrapRequestDto request) { + scrapService.updateScrapColor(scrapId, request); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_SCRAP)); + } } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java index 521796c..66ef0c3 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java @@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; +import org.terning.terningserver.dto.scrap.request.UpdateScrapRequestDto; import org.terning.terningserver.exception.dto.SuccessResponse; @Tag(name="Scrap", description = "스크랩 관련 API") @@ -15,4 +16,15 @@ public interface ScrapSwagger { ResponseEntity createScrap( @PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request ); + + @Operation(summary = "스크랩 취소", description = "사용자가 스크랩을 취소하는 API") + ResponseEntity deleteScrap( + @PathVariable Long internshipAnnouncementId + ); + + @Operation(summary = "스크랩 수정", description = "사용자가 스크랩 색상을 수정하는 API") + public ResponseEntity updateScrapColor( + @PathVariable Long scrapId, @RequestBody UpdateScrapRequestDto request + ); + } diff --git a/src/main/java/org/terning/terningserver/domain/Scrap.java b/src/main/java/org/terning/terningserver/domain/Scrap.java index 89bef37..699350d 100644 --- a/src/main/java/org/terning/terningserver/domain/Scrap.java +++ b/src/main/java/org/terning/terningserver/domain/Scrap.java @@ -49,5 +49,9 @@ public static Scrap create(User user, InternshipAnnouncement internshipAnnouncem .color(color) .build(); } + + public void updateColor(Color color) { + this.color = color; + } } diff --git a/src/main/java/org/terning/terningserver/dto/scrap/request/UpdateScrapRequestDto.java b/src/main/java/org/terning/terningserver/dto/scrap/request/UpdateScrapRequestDto.java new file mode 100644 index 0000000..9843b8e --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/scrap/request/UpdateScrapRequestDto.java @@ -0,0 +1,6 @@ +package org.terning.terningserver.dto.scrap.request; + +public record UpdateScrapRequestDto( + int color +) { +} diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index 88fbba2..1465751 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -11,7 +11,9 @@ public enum ErrorMessage { NOT_FOUND_INTERN_CATEGORY(404, "해당 인턴 공고는 존재하지 않습니다"), NOT_FOUND_INTERN_EXCEPTION(404, "해당 인턴 공고는 존재하지 않습니다"), WRONG_PERIOD(404, "해당 단어가 존재하지 않습니다"), - NOT_FOUND_USER_EXCEPTION(404, "해당 유저가 존재하지 않습니다"); + NOT_FOUND_USER_EXCEPTION(404, "해당 유저가 존재하지 않습니다"), + NOT_FOUND_SCRAP(404, "해당 스크랩 id에 대한 스크랩 정보가 존재하지 않습니다"), + FORBIDDEN_DELETE_SCRAP(403, "해당 유저가 스크랩하지 않았으므로 스크랩 취소가 불가합니다"); private final int status; private final String message; diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index cff337e..cb27824 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -18,7 +18,9 @@ public enum SuccessMessage { SUCCESS_GET_INTERNSHIP_DETAIL(200, "공고 상세 정보 불러오기에 성공했습니다"), // 스크랩 - SUCCESS_CREATE_SCRAP(201, "스크랩 추가에 성공했습니다"); + SUCCESS_CREATE_SCRAP(201, "스크랩 추가에 성공했습니다"), + SUCCESS_DELETE_SCRAP(200, "스크랩 취소에 성공했습니다"), + SUCCESS_UPDATE_SCRAP(200, "스크랩 수정에 성공했습니다"); private final int status; private final String message; diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java index f4648fd..38f0e7c 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java @@ -5,10 +5,10 @@ import java.time.LocalDate; import java.util.List; -import java.util.Optional; public interface ScrapRepository extends JpaRepository { Boolean existsByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); + List findByUserIdAndInternshipAnnouncement_Deadline(Long userId, LocalDate deadline); } diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java index e22b07a..28ca095 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapService.java +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -1,6 +1,7 @@ package org.terning.terningserver.service; import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; +import org.terning.terningserver.dto.scrap.request.UpdateScrapRequestDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import java.util.List; @@ -9,4 +10,8 @@ public interface ScrapService { List getTodayScrap(Long userId); void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request); + + void deleteScrap(Long scrapId); + + void updateScrapColor(Long scrapId, UpdateScrapRequestDto request); } diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index c42fb62..660cf5f 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -2,11 +2,13 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.domain.Scrap; import org.terning.terningserver.domain.User; import org.terning.terningserver.domain.enums.Color; import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; +import org.terning.terningserver.dto.scrap.request.UpdateScrapRequestDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import org.terning.terningserver.exception.CustomException; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; @@ -18,11 +20,11 @@ import java.util.List; import java.util.stream.Collectors; -import static org.terning.terningserver.exception.enums.ErrorMessage.NOT_FOUND_INTERN_EXCEPTION; -import static org.terning.terningserver.exception.enums.ErrorMessage.NOT_FOUND_USER_EXCEPTION; +import static org.terning.terningserver.exception.enums.ErrorMessage.*; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class ScrapServiceImpl implements ScrapService { private final ScrapRepository scrapRepository; @@ -38,6 +40,7 @@ public List getTodayScrap(Long userId){ } @Override + @Transactional public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request) { getInternshipAnnouncement(internshipAnnouncementId); @@ -48,6 +51,29 @@ public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto req )); } + @Override + @Transactional + public void deleteScrap(Long scrapId) { + Scrap scrap = findScrap(scrapId); + verifyScrapOwner(scrap); + scrapRepository.deleteById(scrapId); + } + + @Override + @Transactional + public void updateScrapColor(Long scrapId, UpdateScrapRequestDto request) { + Scrap scrap = findScrap(scrapId); + verifyScrapOwner(scrap); + scrap.updateColor(findColor(request.color())); + } + + //토큰으로 찾은(요청한) User와 스크랩한 User가 일치한지 여부 검증하는 메서드 + private void verifyScrapOwner(Scrap scrap) { + if(!scrap.getUser().equals(findUser(1L))) { + throw new CustomException(FORBIDDEN_DELETE_SCRAP); + } + } + private Color findColor(int color) { return Arrays.stream(Color.values()) .filter(c-> c.getKey() == color) @@ -63,4 +89,9 @@ private User findUser(Long userId) { return userRepository.findById(userId) .orElseThrow(() -> new CustomException(NOT_FOUND_USER_EXCEPTION)); } + + private Scrap findScrap(Long scrapId) { + return scrapRepository.findById(scrapId) + .orElseThrow(() -> new CustomException(NOT_FOUND_SCRAP)); + } } From c4b26a1ef74c3e386e064420cf2e409624ac4552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Tue, 16 Jul 2024 00:09:30 +0900 Subject: [PATCH 126/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8F=C2=A0refactor/#31]?= =?UTF-8?q?=20=EA=B0=80=EB=8F=85=EC=84=B1=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=EB=9D=84=EC=96=B4=EC=93=B0=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../internship_announcement/InternshipRepositoryImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index 6d7fd8f..f3ba37f 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -78,7 +78,7 @@ public Page searchInternshipAnnouncement(String keyword, .limit(pageable.getPageSize()) .fetch(); - Long count =jpaQueryFactory + Long count = jpaQueryFactory .select(internshipAnnouncement.count()) .from(internshipAnnouncement) .leftJoin(internshipAnnouncement.scraps) From faf2b582cff5e38a48de15ab451ced62aaa5bf48 Mon Sep 17 00:00:00 2001 From: Willy Date: Tue, 16 Jul 2024 01:32:09 +0900 Subject: [PATCH 127/205] =?UTF-8?q?[=E2=9C=A8feat/#44]=20=EB=A7=88?= =?UTF-8?q?=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80=20>=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/UserProfileController.java | 36 +++++++++++++++++++ .../controller/swagger/CalendarSwagger.java | 1 - .../controller/swagger/UserSwagger.java | 16 +++++++++ .../dto/user/response/ProfileResponseDto.java | 17 +++++++++ .../exception/enums/SuccessMessage.java | 4 ++- .../terningserver/service/UserService.java | 7 ++++ .../service/UserServiceImpl.java | 24 +++++++++++++ src/main/resources/application-dev.yml | 2 +- 8 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/controller/UserProfileController.java create mode 100644 src/main/java/org/terning/terningserver/controller/swagger/UserSwagger.java create mode 100644 src/main/java/org/terning/terningserver/dto/user/response/ProfileResponseDto.java create mode 100644 src/main/java/org/terning/terningserver/service/UserService.java create mode 100644 src/main/java/org/terning/terningserver/service/UserServiceImpl.java diff --git a/src/main/java/org/terning/terningserver/controller/UserProfileController.java b/src/main/java/org/terning/terningserver/controller/UserProfileController.java new file mode 100644 index 0000000..e8072e9 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/UserProfileController.java @@ -0,0 +1,36 @@ +package org.terning.terningserver.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.terning.terningserver.controller.swagger.UserSwagger; +import org.terning.terningserver.dto.user.response.ProfileResponseDto; +import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.service.UserService; + +import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_PROFILE; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class UserProfileController implements UserSwagger { + + private final UserService userService; + + @GetMapping("/mypage/profile") + public ResponseEntity> getProfile( + @RequestHeader("Authorization") String token + ){ + Long userId = getUserIdFromToken(token); + ProfileResponseDto profile = userService.getProfile(userId); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_PROFILE, profile)); + } + + private Long getUserIdFromToken(String token){ + //실제 토큰에서 userId를 가져오는 로직 구현 + return 1L; //임시로 사용자 ID 1로 반환 + } +} diff --git a/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java index 4f48887..34e6bdc 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java @@ -7,7 +7,6 @@ import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; -import java.time.Month; import java.util.List; @Tag(name = "Calendar", description = "캘린더 관련 API") diff --git a/src/main/java/org/terning/terningserver/controller/swagger/UserSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/UserSwagger.java new file mode 100644 index 0000000..7ebb1a5 --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/swagger/UserSwagger.java @@ -0,0 +1,16 @@ +package org.terning.terningserver.controller.swagger; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.terning.terningserver.dto.user.response.ProfileResponseDto; +import org.terning.terningserver.exception.dto.SuccessResponse; + +@Tag(name = "Mypage", description = "마이페이지 관련 API") +public interface UserSwagger { + + @Operation(summary = "마이페이지 > 프로필 정보 불러오기", description = "마이페이지에서 프로필 정보를 불러오는 API") + ResponseEntity> getProfile( + String token + ); +} diff --git a/src/main/java/org/terning/terningserver/dto/user/response/ProfileResponseDto.java b/src/main/java/org/terning/terningserver/dto/user/response/ProfileResponseDto.java new file mode 100644 index 0000000..38de73c --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/user/response/ProfileResponseDto.java @@ -0,0 +1,17 @@ +package org.terning.terningserver.dto.user.response; + +import lombok.Builder; +import org.terning.terningserver.domain.User; + +@Builder +public record ProfileResponseDto( + String name, + String authType +) { + public static ProfileResponseDto of(final User user){ + return ProfileResponseDto.builder() + .name(user.getName()) + .authType(user.getAuthType().name().toUpperCase()) + .build(); + } +} diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index 897bbce..af66095 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -20,8 +20,10 @@ public enum SuccessMessage { // Calendar (캘린더 화면) SUCCESS_GET_MONTHLY_SCRAPS(200, "캘린더 > (월간) 스크랩 된 공고 정보 불러오기를 성공했습니다"), - SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST(200, "캘린더 > (월간) 스크랩 된 공고 정보 (리스트) 불러오기를 성공했습니다"); + SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST(200, "캘린더 > (월간) 스크랩 된 공고 정보 (리스트) 불러오기를 성공했습니다"), + // Mypage (마이페이지 화면) + SUCCESS_GET_PROFILE(200, "마이페이지 > 프로필 정보 불러오기를 성공했습니다"); private final int status; private final String message; diff --git a/src/main/java/org/terning/terningserver/service/UserService.java b/src/main/java/org/terning/terningserver/service/UserService.java new file mode 100644 index 0000000..d4842db --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/UserService.java @@ -0,0 +1,7 @@ +package org.terning.terningserver.service; + +import org.terning.terningserver.dto.user.response.ProfileResponseDto; + +public interface UserService { + ProfileResponseDto getProfile(Long userId); +} diff --git a/src/main/java/org/terning/terningserver/service/UserServiceImpl.java b/src/main/java/org/terning/terningserver/service/UserServiceImpl.java new file mode 100644 index 0000000..73ff387 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/UserServiceImpl.java @@ -0,0 +1,24 @@ +package org.terning.terningserver.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.dto.user.response.ProfileResponseDto; +import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.exception.enums.ErrorMessage; +import org.terning.terningserver.repository.user.UserRepository; + +@Service +@RequiredArgsConstructor +public class UserServiceImpl implements UserService{ + + private final UserRepository userRepository; + + @Override + public ProfileResponseDto getProfile(Long userId){ + User user = userRepository.findById(userId).orElseThrow( + () -> new CustomException(ErrorMessage.NOT_FOUND_USER_EXCEPTION) + ); + return ProfileResponseDto.of(user); + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 9f3a57c..7331780 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -31,7 +31,7 @@ spring: jpa: show-sql: true hibernate: - ddl-auto: create + ddl-auto: update properties: hibernate: format_sql: true From 41896f0543a84cd1bbbe15464200fa09e08e5da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 03:42:19 +0900 Subject: [PATCH 128/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=EC=99=80=20=ED=95=84=ED=84=B0=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=20=EB=A1=9C=EC=A7=81=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=84=B0=EB=A7=81=20=EB=B0=8F=20=ED=8A=B8=EB=9E=9C=EC=9E=AD?= =?UTF-8?q?=EC=85=98=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 서비스 로직의 책임 분리 --- .../controller/AuthController.java | 9 ++- .../terning/terningserver/domain/Filter.java | 15 ++--- .../terning/terningserver/domain/User.java | 10 +-- .../auth/request/SignUpFilterRequestDto.java | 8 +++ .../service/AuthServiceImpl.java | 3 - .../service/SignUpFilterService.java | 64 +++++++++++++++---- 6 files changed, 73 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index a167404..f5849b8 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -5,6 +5,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.terning.terningserver.controller.swagger.AuthSwagger; +import org.terning.terningserver.domain.Filter; import org.terning.terningserver.domain.User; import org.terning.terningserver.dto.auth.request.SignInRequestDto; import org.terning.terningserver.dto.auth.request.SignUpFilterRequestDto; @@ -68,9 +69,13 @@ public ResponseEntity> filter( @RequestHeader("User-Id") Long userId, @RequestBody SignUpFilterRequestDto request ) { - signUpFilterService.signUpFilter(userId, request); - return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_UP_FILTER)); + // 필터 생성 및 저장 + Filter newFilter = signUpFilterService.createAndSaveFilter(request); + + // 사용자에게 필터 연결 + signUpFilterService.connectFilterToUser(userId, newFilter.getId()); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_UP_FILTER)); } @PostMapping("/logout") diff --git a/src/main/java/org/terning/terningserver/domain/Filter.java b/src/main/java/org/terning/terningserver/domain/Filter.java index 25ac397..55fc0ff 100644 --- a/src/main/java/org/terning/terningserver/domain/Filter.java +++ b/src/main/java/org/terning/terningserver/domain/Filter.java @@ -1,17 +1,22 @@ package org.terning.terningserver.domain; import jakarta.persistence.*; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.terning.terningserver.domain.enums.Grade; import org.terning.terningserver.domain.enums.WorkingPeriod; +import org.terning.terningserver.dto.auth.request.SignUpFilterRequestDto; + import static lombok.AccessLevel.PROTECTED; import static jakarta.persistence.GenerationType.IDENTITY; @Entity @Getter @NoArgsConstructor(access = PROTECTED) +@AllArgsConstructor +@Builder public class Filter { @Id @@ -32,14 +37,4 @@ public class Filter { @Column(nullable = false) private int startMonth; - - @Builder - public Filter(Long id, Grade grade, WorkingPeriod workingPeriod, int startYear, int startMonth) { - this.id = id; - this.grade = grade; - this.workingPeriod = workingPeriod; - this.startYear = startYear; - this.startMonth = startMonth; - } - } diff --git a/src/main/java/org/terning/terningserver/domain/User.java b/src/main/java/org/terning/terningserver/domain/User.java index c5907be..2fa5bb9 100644 --- a/src/main/java/org/terning/terningserver/domain/User.java +++ b/src/main/java/org/terning/terningserver/domain/User.java @@ -80,13 +80,7 @@ public void updateProfile(String name, Integer profileImage) { } } - @Builder - public void updateFilter(Grade grade, WorkingPeriod workingPeriod, int startYear, int startMonth) { - this.filter = Filter.builder() - .grade(grade) - .workingPeriod(workingPeriod) - .startYear(startYear) - .startMonth(startMonth) - .build(); + public void assignFilter(Filter filter) { + this.filter = filter; } } diff --git a/src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java index 64d04f5..484869c 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java @@ -13,4 +13,12 @@ public record SignUpFilterRequestDto( @NonNull int startMonth ) { + public static SignUpFilterRequestDto of(int grade, int workingPeriod, int startYear, int startMonth) { + return SignUpFilterRequestDto.builder() + .grade(grade) + .workingPeriod(workingPeriod) + .startYear(startYear) + .startMonth(startMonth) + .build(); + } } diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index 8fe59bf..3ba6e3b 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -40,9 +40,6 @@ public class AuthServiceImpl implements AuthService { @Transactional public SignInResponseDto signIn(User user, SignInRequestDto request) { User authenticatedUser = getUser(user.getAuthAccessToken(), request.authType()); -// System.out.println( -// "AccessToken : " + user.getAuthAccessToken() + "AuthType : " + request.authType() -// ); val token = getToken(authenticatedUser); return SignInResponseDto.of(token, authenticatedUser.getId(), authenticatedUser.getAuthType()); } diff --git a/src/main/java/org/terning/terningserver/service/SignUpFilterService.java b/src/main/java/org/terning/terningserver/service/SignUpFilterService.java index e25b51c..53f51b8 100644 --- a/src/main/java/org/terning/terningserver/service/SignUpFilterService.java +++ b/src/main/java/org/terning/terningserver/service/SignUpFilterService.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.Filter; import org.terning.terningserver.domain.User; import org.terning.terningserver.dto.auth.request.SignUpFilterRequestDto; @@ -20,17 +21,48 @@ public class SignUpFilterService { private final FilterRepository filterRepository; private final UserRepository userRepository; - public void signUpFilter(Long userId, SignUpFilterRequestDto request) { - User user = userRepository.findById(userId).orElseThrow(() -> new CustomException(SIGN_UP_FILTER_FAILED)); +// @Transactional +// public void signUpFilter(Long userId, SignUpFilterRequestDto request) { +// +// User user = userRepository.findById(userId).orElseThrow(() -> new CustomException(SIGN_UP_FILTER_FAILED)); +// +// int gradeKey = request.grade(); +// int workingPeriodKey = request.workingPeriod(); +// int startYear = request.startYear(); +// int startMonth = request.startMonth(); +// +// Grade grade = Grade.fromKey(gradeKey); +// WorkingPeriod workingPeriod = WorkingPeriod.fromKey(workingPeriodKey); +// +// Filter filter = Filter.builder() +// .grade(grade) +// .workingPeriod(workingPeriod) +// .startYear(startYear) +// .startMonth(startMonth) +// .build(); +// +// try { +// filterRepository.save(filter); +// } catch (Exception e) { +// throw new CustomException(SIGN_UP_FILTER_FAILED); +// } +// +// +// user.updateFilter(grade, workingPeriod, startYear, startMonth); +// userRepository.save(user); +// } + - int gradeKey = request.grade(); - int workingPeriodKey = request.workingPeriod(); + @Transactional + public Filter createAndSaveFilter(SignUpFilterRequestDto request) { + + // 필터 데이터 생성 + Grade grade = Grade.fromKey(request.grade()); + WorkingPeriod workingPeriod = WorkingPeriod.fromKey(request.workingPeriod()); int startYear = request.startYear(); int startMonth = request.startMonth(); - Grade grade = Grade.fromKey(gradeKey); - WorkingPeriod workingPeriod = WorkingPeriod.fromKey(workingPeriodKey); - + // 필터 객체 생성 Filter filter = Filter.builder() .grade(grade) .workingPeriod(workingPeriod) @@ -38,14 +70,20 @@ public void signUpFilter(Long userId, SignUpFilterRequestDto request) { .startMonth(startMonth) .build(); - try { - filterRepository.save(filter); - } catch (Exception e) { - throw new CustomException(SIGN_UP_FILTER_FAILED); - } + // 필터 저장 + return filterRepository.save(filter); + } + + @Transactional + public void connectFilterToUser(Long userId, Long filterId) { + // 사용자 찾기 + User user = userRepository.findById(userId).orElseThrow(() -> new CustomException(SIGN_UP_FILTER_FAILED)); + Filter filter = filterRepository.findById(filterId).orElseThrow(() -> new CustomException(SIGN_UP_FILTER_FAILED)); + // 사용자 객체에 필터 할당 + user.assignFilter(filter); - user.updateFilter(grade, workingPeriod, startYear, startMonth); + // 사용자 정보 업데이트 userRepository.save(user); } From cfe5911d4b21aea6c0f67d1d3347e462c397d95b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 03:58:40 +0900 Subject: [PATCH 129/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20pri?= =?UTF-8?q?nt=20code=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/controller/AuthController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index f5849b8..b13af9e 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -37,7 +37,6 @@ public ResponseEntity> signIn( @RequestHeader("Authorization") String authAccessToken, @RequestBody SignInRequestDto request ) { - System.out.println(authAccessToken + " " + request.authType()); User user = authService.saveUser(authAccessToken, request); val signInResponse = authService.signIn(user, request); From ca74046e7e42156838e4751f9b8d3e43995b0035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Tue, 16 Jul 2024 04:42:18 +0900 Subject: [PATCH 130/205] =?UTF-8?q?[=F0=9F=93=82=C2=A0file/#39]:=20dto=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20=EB=81=9D?= =?UTF-8?q?=EC=97=90=20Dto=20=EB=B6=99=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/controller/SearchController.java | 4 ++-- .../controller/swagger/SearchSwagger.java | 4 ++-- ...esultResponse.java => SearchResultResponseDto.java} | 7 +++---- .../terning/terningserver/service/SearchService.java | 4 ++-- .../terningserver/service/SearchServiceImpl.java | 10 +++++----- 5 files changed, 14 insertions(+), 15 deletions(-) rename src/main/java/org/terning/terningserver/dto/search/response/{SearchResultResponse.java => SearchResultResponseDto.java} (81%) diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index 1a77505..bfbbca7 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.RestController; import org.terning.terningserver.controller.swagger.SearchSwagger; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponseDto; -import org.terning.terningserver.dto.search.response.SearchResultResponse; +import org.terning.terningserver.dto.search.response.SearchResultResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.service.SearchService; import static org.terning.terningserver.exception.enums.SuccessMessage.*; @@ -40,7 +40,7 @@ public ResponseEntity> getMo } @GetMapping("/search") - public ResponseEntity> searchInternshipAnnouncement( + public ResponseEntity> searchInternshipAnnouncement( @RequestParam(value = "keyword", required = false) String keyword, @RequestParam(value = "sortBy", required = false) String sortBy, Pageable pageable) { return ResponseEntity.ok(SuccessResponse.of( diff --git a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java index e640046..537bb65 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java @@ -7,7 +7,7 @@ import org.springframework.http.ResponseEntity; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponseDto; import org.springframework.web.bind.annotation.RequestParam; -import org.terning.terningserver.dto.search.response.SearchResultResponse; +import org.terning.terningserver.dto.search.response.SearchResultResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; @Tag(name = "Search", description = "탐색 관련 API") @@ -24,7 +24,7 @@ ResponseEntity> getMostScrap ); @Operation(summary = "탐색 > 검색 결과 화면", description = "탐색 화면에서 인턴 공고를 검색하는 API") - ResponseEntity> searchInternshipAnnouncement( + ResponseEntity> searchInternshipAnnouncement( @RequestParam(value = "keyword", required = false) String keyword, @RequestParam("sortBy") String sortBy, Pageable pageable ); diff --git a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponseDto.java similarity index 81% rename from src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java rename to src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponseDto.java index 35c1d3b..34d082d 100644 --- a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponse.java +++ b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponseDto.java @@ -5,9 +5,8 @@ import org.terning.terningserver.util.DateUtil; import java.util.List; -import java.util.stream.Collectors; -public record SearchResultResponse( +public record SearchResultResponseDto( int totalPages, Boolean hasNext, List announcements @@ -33,8 +32,8 @@ public static SearchAnnouncementResponse from(InternshipAnnouncement announcemen .build(); } } - public static SearchResultResponse of(int totalPages, Boolean hasNext, List announcements) { - return new SearchResultResponse(totalPages, hasNext, announcements); + public static SearchResultResponseDto of(int totalPages, Boolean hasNext, List announcements) { + return new SearchResultResponseDto(totalPages, hasNext, announcements); } } diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index 5f4c2e1..d54d8af 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -2,7 +2,7 @@ import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponseDto; import org.springframework.data.domain.Pageable; -import org.terning.terningserver.dto.search.response.SearchResultResponse; +import org.terning.terningserver.dto.search.response.SearchResultResponseDto; public interface SearchService { @@ -10,6 +10,6 @@ public interface SearchService { PopularAnnouncementListResponseDto getMostScrappedAnnouncements(); - SearchResultResponse searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable); + SearchResultResponseDto searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable); } \ No newline at end of file diff --git a/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java b/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java index 0c253a4..0e25be8 100644 --- a/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java @@ -8,7 +8,7 @@ import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.domain.Scrap; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponseDto; -import org.terning.terningserver.dto.search.response.SearchResultResponse; +import org.terning.terningserver.dto.search.response.SearchResultResponseDto; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import org.terning.terningserver.repository.scrap.ScrapRepository; @@ -38,12 +38,12 @@ public PopularAnnouncementListResponseDto getMostScrappedAnnouncements() { } @Override - public SearchResultResponse searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { + public SearchResultResponseDto searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { Page pageAnnouncements = internshipRepository.searchInternshipAnnouncement(keyword, sortBy, pageable); List announcements = pageAnnouncements.getContent(); - List searchAnnouncementResponses = new ArrayList<>(); + List searchAnnouncementResponses = new ArrayList<>(); List scraps = scrapRepository.findAllByInternshipAndUserId(announcements, 1L); @@ -54,9 +54,9 @@ public SearchResultResponse searchInternshipAnnouncement(String keyword, String Scrap::getId )); - return new SearchResultResponse( + return new SearchResultResponseDto( pageAnnouncements.getTotalPages(), pageAnnouncements.hasNext(), announcements.stream() - .map(a -> SearchResultResponse.SearchAnnouncementResponse.from(a, scrapMap.get(a.getId()))) + .map(a -> SearchResultResponseDto.SearchAnnouncementResponse.from(a, scrapMap.get(a.getId()))) .toList()); } } \ No newline at end of file From e46f219a3545b6943c4fa38acd8d79158517805e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 04:45:48 +0900 Subject: [PATCH 131/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=95=84=EC=9B=83=20API=EC=9D=98=20=ED=8C=8C?= =?UTF-8?q?=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AuthController의 로그아웃 API에서 불필요한 Authorization 헤더 파라미터를 제거하고, Principal 객체만을 사용하여 사용자 ID를 얻도록 수정하였습니다. --- .../org/terning/terningserver/controller/AuthController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index b13af9e..9d568ca 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -78,7 +78,7 @@ public ResponseEntity> filter( } @PostMapping("/logout") - public ResponseEntity signOut(@RequestHeader("Authorization") String token, Principal principal) { + public ResponseEntity signOut(Principal principal) { val userId = Long.parseLong(principal.getName()); authService.signOut(userId); From d678a0f1a9976e0ae11f7f5426b0ea18c3223263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 04:53:11 +0900 Subject: [PATCH 132/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=95=84=EC=9B=83=20API=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20ID=20=EC=B2=98=EB=A6=AC=20=EB=B0=A9=EC=8B=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20Swagger=20=EB=AC=B8=EC=84=9C?= =?UTF-8?q?=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AuthController의 로그아웃 API에서 Principal 객체에서 사용자 ID를 동적으로 파싱하는 방식에서 고정된 사용자 ID(15)로 변경하였습니다. 이는 테스트 목적이나 특정 시나리오에서 요구될 수 있는 사항으로 반영하였습니다. - 또한, Swagger API 문서에서 로그아웃 함수의 불필요한 Authorization 헤더 파라미터를 제거하여 API 문서의 정확성을 높였습니다. --- .../org/terning/terningserver/controller/AuthController.java | 4 +++- .../terning/terningserver/controller/swagger/AuthSwagger.java | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index 9d568ca..4185319 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -79,9 +79,11 @@ public ResponseEntity> filter( @PostMapping("/logout") public ResponseEntity signOut(Principal principal) { - val userId = Long.parseLong(principal.getName()); +// val userId = Long.parseLong(principal.getName()); + val userId = 15; authService.signOut(userId); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_OUT)); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java index 3e4d7b2..f3611ac 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java @@ -43,7 +43,6 @@ ResponseEntity> signUp( @Operation(summary = "로그아웃", description = "로그아웃 API") ResponseEntity signOut( - @RequestHeader("Authorization") String token, Principal principal); @Operation(summary = "계정탈퇴", description = "계정탈퇴 API") From dc48650a1e73a781b7c413ee33b3de596f49f20a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 05:11:43 +0900 Subject: [PATCH 133/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20?= =?UTF-8?q?=EC=A4=84=20=EB=B0=94=EA=BF=88=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/controller/AuthController.java | 12 ++++++------ .../terningserver/controller/HomeController.java | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index 4185319..4c115f7 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -38,6 +38,7 @@ public ResponseEntity> signIn( @RequestBody SignInRequestDto request ) { User user = authService.saveUser(authAccessToken, request); + val signInResponse = authService.signIn(user, request); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_IN, signInResponse)); @@ -50,6 +51,7 @@ public ResponseEntity> reissueToken( @RequestHeader("Authorization") String refreshToken ) { val response = authService.reissueToken(refreshToken); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_REISSUE_TOKEN, response)); } @@ -79,20 +81,18 @@ public ResponseEntity> filter( @PostMapping("/logout") public ResponseEntity signOut(Principal principal) { -// val userId = Long.parseLong(principal.getName()); - val userId = 15; - authService.signOut(userId); + val userId = Long.parseLong(principal.getName()); + authService.signOut(userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_OUT)); } - @DeleteMapping("/withdraw") public ResponseEntity withdraw(Principal principal) { val userId = Long.parseLong(principal.getName()); + authService.withdraw(userId); - return ResponseEntity.ok(SuccessResponse.of(SUCCESS_WITHDRAW)); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_WITHDRAW)); } - } diff --git a/src/main/java/org/terning/terningserver/controller/HomeController.java b/src/main/java/org/terning/terningserver/controller/HomeController.java index b213155..c088aea 100644 --- a/src/main/java/org/terning/terningserver/controller/HomeController.java +++ b/src/main/java/org/terning/terningserver/controller/HomeController.java @@ -34,6 +34,7 @@ public ResponseEntity>> getAnnouncements( @RequestParam("startMonth") int startMonth ){ List announcements = homeService.getAnnouncements(token, sortBy, startYear, startMonth); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_ANNOUNCEMENTS, announcements)); } @@ -42,7 +43,9 @@ public ResponseEntity>> getTodayScra @RequestHeader("Authorization") String token ){ Long userId = getUserIdFromToken(token); + List scrapList = scrapService.getTodayScrap(userId); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_TODAY_ANNOUNCEMENTS, scrapList)); } From 22dffc41b2b8f68dcc71e26743617f2f610c45e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 05:24:05 +0900 Subject: [PATCH 134/205] =?UTF-8?q?[=E2=9C=85chore/#17]:=20PostgreSQL=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=B2=A0=EC=9D=B4=EC=8A=A4=20URL=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=A4=91=EB=B3=B5=EB=90=9C=20?= =?UTF-8?q?URL=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index df28152..d592417 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -1,7 +1,7 @@ spring: datasource: driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://localhost:5432/terning55 + url: jdbc:postgresql://localhost:5432/terning username: ${USER_ID} password: ${USER_PW} From 35ac32e18d30ad9b06caccad3b89be7d52da9113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Tue, 16 Jul 2024 14:20:38 +0900 Subject: [PATCH 135/205] =?UTF-8?q?[=F0=9F=93=82=C2=A0file/#47]:=20Interns?= =?UTF-8?q?hipDetailService=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - InternshipDetailService와 InternshipDetailServiceImpl로 분리 --- .../service/InternshipDetailService.java | 18 ++--------- .../service/InternshipDetailServiceImpl.java | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java index 18e7ab3..6382b79 100644 --- a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java @@ -11,22 +11,8 @@ import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import org.terning.terningserver.repository.scrap.ScrapRepository; -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class InternshipDetailService { - private final InternshipRepository internshipRepository; - private final ScrapRepository scrapRepository; +public interface InternshipDetailService { - public InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId) { - InternshipAnnouncement announcement = internshipRepository.findById(internshipAnnouncementId) - .orElseThrow(() -> new CustomException(ErrorMessage.NOT_FOUND_INTERN_EXCEPTION)); - - - return InternshipDetailResponseDto.of( - announcement, announcement.getCompany(), - scrapRepository.existsByInternshipAnnouncementIdAndUserId(announcement.getId(), 1L) - ); - } + InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId); } diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java b/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java new file mode 100644 index 0000000..cd862a5 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java @@ -0,0 +1,32 @@ +package org.terning.terningserver.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.dto.internship_detail.InternshipDetailResponseDto; +import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.exception.enums.ErrorMessage; +import org.terning.terningserver.repository.internship_announcement.InternshipRepository; +import org.terning.terningserver.repository.scrap.ScrapRepository; + + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class InternshipDetailServiceImpl implements InternshipDetailService { + private final InternshipRepository internshipRepository; + private final ScrapRepository scrapRepository; + + @Override + public InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId) { + InternshipAnnouncement announcement = internshipRepository.findById(internshipAnnouncementId) + .orElseThrow(() -> new CustomException(ErrorMessage.NOT_FOUND_INTERN_EXCEPTION)); + + + return InternshipDetailResponseDto.of( + announcement, announcement.getCompany(), + scrapRepository.existsByInternshipAnnouncementIdAndUserId(announcement.getId(), 1L) + ); + } +} From 12e75739686718990056bdcfb49215d0d042b7c8 Mon Sep 17 00:00:00 2001 From: Willy Date: Tue, 16 Jul 2024 15:41:26 +0900 Subject: [PATCH 136/205] =?UTF-8?q?[=F0=9F=94=A8=20fix/#51]=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InternshipRepositoryImpl.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index 4469aeb..8eaff06 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -149,14 +149,22 @@ private OrderSpecifier getSortOrder(String sortBy) { } // String 타입의 workingPeriod를 숫자로 변환하기 위한 메서드(ex. "2개월" => 2) - private NumberTemplate getWorkingPeriodAsNumber(){ + private NumberTemplate getWorkingPeriodAsNumber() { return Expressions.numberTemplate( Integer.class, - "CAST(SUBSTRING({0}, 1, LENGTH({0}) - 2) AS INTEGER)", + "CAST(NULLIF(regexp_replace({0}, '\\D', '', 'g'), '') AS INTEGER)", internshipAnnouncement.workingPeriod ); } +// private NumberTemplate getWorkingPeriodAsNumber(){ +// return Expressions.numberTemplate( +// Integer.class, +// "CAST(SUBSTRING({0}, 1, LENGTH({0}) - 2) AS INTEGER)", +// internshipAnnouncement.workingPeriod +// ); +// } + // 지원 마감일이 지나지 않은 공고 private BooleanExpression internDeadlineGoe() { return internshipAnnouncement.deadline.goe(LocalDate.now()); From 843fdc2ec27201a08ff2a45eb2c9baf912aea0ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Tue, 16 Jul 2024 15:54:03 +0900 Subject: [PATCH 137/205] =?UTF-8?q?[=E2=9C=A8feat/#47]:=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=EB=A7=81=20=EC=A0=95=EB=B3=B4=20=EB=B0=8F=20=EC=9E=AC?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FilterController.java | 34 +++++++++++++ .../terning/terningserver/domain/Filter.java | 7 +++ .../filter/request/UserFilterRequestDto.java | 9 ++++ .../response/UserFilterResponseDto.java | 21 ++++++++ .../exception/enums/SuccessMessage.java | 6 ++- .../terningserver/service/FilterService.java | 11 +++++ .../service/FilterServiceImpl.java | 48 +++++++++++++++++++ 7 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/terning/terningserver/controller/FilterController.java create mode 100644 src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java create mode 100644 src/main/java/org/terning/terningserver/dto/filter/response/UserFilterResponseDto.java create mode 100644 src/main/java/org/terning/terningserver/service/FilterService.java create mode 100644 src/main/java/org/terning/terningserver/service/FilterServiceImpl.java diff --git a/src/main/java/org/terning/terningserver/controller/FilterController.java b/src/main/java/org/terning/terningserver/controller/FilterController.java new file mode 100644 index 0000000..d827eef --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/FilterController.java @@ -0,0 +1,34 @@ +package org.terning.terningserver.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.terning.terningserver.dto.filter.request.UserFilterRequestDto; +import org.terning.terningserver.dto.filter.response.UserFilterResponseDto; +import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.service.FilterService; + +import static org.terning.terningserver.exception.enums.SuccessMessage.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class FilterController { + + private final FilterService filterService; + + @GetMapping("/filters") + public ResponseEntity> getUserFilter(@RequestHeader("Authorization") String token) { + return ResponseEntity.ok(SuccessResponse.of( + SUCCESS_GET_USER_FILTER, + filterService.getUserFilter() + )); + } + + @PutMapping("/filters") + public ResponseEntity updateUserFilter(@RequestBody UserFilterRequestDto requestDto) { + filterService.updateUserFilter(requestDto); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_SCRAP)); + } + +} diff --git a/src/main/java/org/terning/terningserver/domain/Filter.java b/src/main/java/org/terning/terningserver/domain/Filter.java index ac8431a..84cf785 100644 --- a/src/main/java/org/terning/terningserver/domain/Filter.java +++ b/src/main/java/org/terning/terningserver/domain/Filter.java @@ -29,4 +29,11 @@ public class Filter { private int startYear; // 근무 시작 연도 private int startMonth; // 근무 시작 월 + + public void updateFilter(Grade grade, WorkingPeriod workingPeriod, int startYear, int startMonth) { + this.grade = grade; + this.workingPeriod = workingPeriod; + this.startYear = startYear; + this.startMonth = startMonth; + } } diff --git a/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java b/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java new file mode 100644 index 0000000..510766e --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java @@ -0,0 +1,9 @@ +package org.terning.terningserver.dto.filter.request; + +public record UserFilterRequestDto( + int grade, + int workingPeriod, + int startYear, + int startMonth +) { +} diff --git a/src/main/java/org/terning/terningserver/dto/filter/response/UserFilterResponseDto.java b/src/main/java/org/terning/terningserver/dto/filter/response/UserFilterResponseDto.java new file mode 100644 index 0000000..67c833c --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/filter/response/UserFilterResponseDto.java @@ -0,0 +1,21 @@ +package org.terning.terningserver.dto.filter.response; + +import lombok.Builder; +import org.terning.terningserver.domain.Filter; + +@Builder +public record UserFilterResponseDto( + int grade, + int workingPeriod, + int startYear, + int startMonth +) { + public static UserFilterResponseDto of(Filter userFilter) { + return UserFilterResponseDto.builder() + .grade(userFilter.getGrade().getKey()) + .workingPeriod(userFilter.getWorkingPeriod().getKey()) + .startYear(userFilter.getStartYear()) + .startMonth(userFilter.getStartMonth()) + .build(); + } +} diff --git a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java index de1cc2f..01198c8 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/SuccessMessage.java @@ -25,7 +25,11 @@ public enum SuccessMessage { // Calendar (캘린더 화면) SUCCESS_GET_MONTHLY_SCRAPS(200, "캘린더 > (월간) 스크랩 된 공고 정보 불러오기를 성공했습니다"), - SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST(200, "캘린더 > (월간) 스크랩 된 공고 정보 (리스트) 불러오기를 성공했습니다"); + SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST(200, "캘린더 > (월간) 스크랩 된 공고 정보 (리스트) 불러오기를 성공했습니다"), + + // Filter(필터링) + SUCCESS_GET_USER_FILTER(200, "사용자의 필터링 정보를 불러오는데 성공했습니다"), + SUCCESS_UPDATE_USER_FILTER(200, "필터링 재설정에 성공했습니다"); private final int status; diff --git a/src/main/java/org/terning/terningserver/service/FilterService.java b/src/main/java/org/terning/terningserver/service/FilterService.java new file mode 100644 index 0000000..6b2b929 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/FilterService.java @@ -0,0 +1,11 @@ +package org.terning.terningserver.service; + +import org.terning.terningserver.dto.filter.request.UserFilterRequestDto; +import org.terning.terningserver.dto.filter.response.UserFilterResponseDto; + +public interface FilterService { + + UserFilterResponseDto getUserFilter(); + + void updateUserFilter(UserFilterRequestDto responseDto); +} diff --git a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java new file mode 100644 index 0000000..5307c17 --- /dev/null +++ b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java @@ -0,0 +1,48 @@ +package org.terning.terningserver.service; + + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.terning.terningserver.domain.Filter; +import org.terning.terningserver.domain.User; +import org.terning.terningserver.domain.enums.Grade; +import org.terning.terningserver.domain.enums.WorkingPeriod; +import org.terning.terningserver.dto.filter.request.UserFilterRequestDto; +import org.terning.terningserver.dto.filter.response.UserFilterResponseDto; +import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.repository.user.UserRepository; + +import static org.terning.terningserver.exception.enums.ErrorMessage.NOT_FOUND_USER_EXCEPTION; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class FilterServiceImpl implements FilterService { + + private final UserRepository userRepository; + + @Override + public UserFilterResponseDto getUserFilter() { + return UserFilterResponseDto.of(findUser(1L).getFilter()); + } + + @Override + @Transactional + public void updateUserFilter(UserFilterRequestDto responseDto) { + User user = findUser(1L); + Filter filter = user.getFilter(); + + filter.updateFilter( + Grade.fromKey(responseDto.grade()), + WorkingPeriod.fromKey(responseDto.workingPeriod()), + responseDto.startYear(), + responseDto.startMonth() + ); + } + + private User findUser(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new CustomException(NOT_FOUND_USER_EXCEPTION)); + } +} From feecce2449b6efd740bbcd2323cfb580ebf0eadb Mon Sep 17 00:00:00 2001 From: Willy Date: Tue, 16 Jul 2024 16:07:47 +0900 Subject: [PATCH 138/205] =?UTF-8?q?[=F0=9F=94=A8=20fix/#51]=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/service/ScrapServiceImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index b83122e..38fe279 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -105,11 +105,12 @@ public List getMonthlyScrapsAsList(Long userId, int year } @Override - public List getDailyScraps(Long userId, LocalDate date){ + public List getDailyScraps(Long userId, LocalDate date) { return scrapRepository.findByUserIdAndInternshipAnnouncement_Deadline(userId, date).stream() .map(DailyScrapResponseDto::of) .toList(); - + } + @Override @Transactional public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request) { From 6cd3f05254f86a385c7161b7e575b1d8fae409db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 16:09:46 +0900 Subject: [PATCH 139/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor:/17]:=20Aut?= =?UTF-8?q?hServiceImpl=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20=EB=B0=8F?= =?UTF-8?q?=20=ED=95=A8=EC=88=98=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - getUser 메서드의 포맷팅 변경 - signUp 메서드에 user 파라미터 추가 및 로직 수정 - getToken 메서드에서 accessToken 갱신 로직 추가 --- .../terningserver/service/AuthServiceImpl.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index 3ba6e3b..d62fee9 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -75,11 +75,12 @@ public TokenGetResponseDto reissueToken(String refreshToken) { return TokenGetResponseDto.of(token); } - private User getUser(String authAccessToken, AuthType authType) { + private User + getUser(String authAccessToken, AuthType authType) { User user = userRepository.findByAuthTypeAndAuthAccessToken(authType, authAccessToken) .orElseThrow(() -> new CustomException(INVALID_USER)); - val authId = getAuthId(user.getAuthType(), authAccessToken); - return signUp(authType, authId); + String authId = getAuthId(user.getAuthType(), authAccessToken); + return signUp(authType, authId, user); } private String getAuthId(AuthType authType, String authAccessToken) { @@ -89,9 +90,9 @@ private String getAuthId(AuthType authType, String authAccessToken) { }; } - private User signUp(AuthType authType, String authId) { - return userRepository.findByAuthTypeAndAuthAccessToken(authType, authId) - .orElseGet(() -> saveUser(authType, authId)); + private User signUp(AuthType authType, String authId, User user) { + user.updateUser(authType, authId, user); + return userRepository.save(user); } private User saveUser(AuthType authType, String authId) { @@ -105,7 +106,7 @@ private User saveUser(AuthType authType, String authId) { private Token getToken(User user) { val token = generateToken(new UserAuthentication(user.getId(), null, null)); - user.updateRefreshToken(token.getRefreshToken()); + user.updateRefreshToken(token.getRefreshToken(), token.getAccessToken()); return token; } From d53f17c492230d0e6fe553359f4c9911b87dfb12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 16:10:23 +0900 Subject: [PATCH 140/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Sig?= =?UTF-8?q?nUpFilterService=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - signUpFilter 메서드의 주석 처리된 불필요한 코드 제거 - createAndSaveFilter 메서드 추가 --- .../service/SignUpFilterService.java | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/SignUpFilterService.java b/src/main/java/org/terning/terningserver/service/SignUpFilterService.java index 53f51b8..5bf75fc 100644 --- a/src/main/java/org/terning/terningserver/service/SignUpFilterService.java +++ b/src/main/java/org/terning/terningserver/service/SignUpFilterService.java @@ -21,38 +21,6 @@ public class SignUpFilterService { private final FilterRepository filterRepository; private final UserRepository userRepository; -// @Transactional -// public void signUpFilter(Long userId, SignUpFilterRequestDto request) { -// -// User user = userRepository.findById(userId).orElseThrow(() -> new CustomException(SIGN_UP_FILTER_FAILED)); -// -// int gradeKey = request.grade(); -// int workingPeriodKey = request.workingPeriod(); -// int startYear = request.startYear(); -// int startMonth = request.startMonth(); -// -// Grade grade = Grade.fromKey(gradeKey); -// WorkingPeriod workingPeriod = WorkingPeriod.fromKey(workingPeriodKey); -// -// Filter filter = Filter.builder() -// .grade(grade) -// .workingPeriod(workingPeriod) -// .startYear(startYear) -// .startMonth(startMonth) -// .build(); -// -// try { -// filterRepository.save(filter); -// } catch (Exception e) { -// throw new CustomException(SIGN_UP_FILTER_FAILED); -// } -// -// -// user.updateFilter(grade, workingPeriod, startYear, startMonth); -// userRepository.save(user); -// } - - @Transactional public Filter createAndSaveFilter(SignUpFilterRequestDto request) { From 857c912bff5f9d57c5793d1eeda0203a9e50a662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 16:11:38 +0900 Subject: [PATCH 141/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Fil?= =?UTF-8?q?ter=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=EC=96=B4=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Grade와 WorkingPeriod 필드에 @Enumerated(EnumType.STRING) 어노테이션 추가 - 각 필드에 @Column(nullable = false) 어노테이션 추가 --- src/main/java/org/terning/terningserver/domain/Filter.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/terning/terningserver/domain/Filter.java b/src/main/java/org/terning/terningserver/domain/Filter.java index 55fc0ff..200fbe2 100644 --- a/src/main/java/org/terning/terningserver/domain/Filter.java +++ b/src/main/java/org/terning/terningserver/domain/Filter.java @@ -24,17 +24,13 @@ public class Filter { private Long id; @Enumerated(EnumType.STRING) - @Column(nullable = false) private Grade grade; @Enumerated(EnumType.STRING) - @Column(nullable = false) private WorkingPeriod workingPeriod; - @Column(nullable = false) private int startYear; - @Column(nullable = false) private int startMonth; } From b636beb89c85a1646ad6b1aa2e409b32145f7ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 16:12:16 +0900 Subject: [PATCH 142/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Aut?= =?UTF-8?q?hController=20=ED=86=A0=ED=81=B0=20=EC=9E=AC=EB=B0=9C=EA=B8=89?= =?UTF-8?q?=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /token-reissue 엔드포인트 추가 - TODO 주석 추가: 에러 메시지 위치 --- .../org/terning/terningserver/controller/AuthController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index 4c115f7..5736c4c 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -45,6 +45,7 @@ public ResponseEntity> signIn( } + // TODO: 에러 메시지 위치 @PostMapping("/token-reissue") public ResponseEntity> reissueToken( From 45681bed8f2c4be9f992d4b2d82993d9543ece49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 16:13:29 +0900 Subject: [PATCH 143/205] =?UTF-8?q?[=E2=9C=A8feat/#17]:=20nimbus-jose-jwt?= =?UTF-8?q?=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 96885bc..2ce40e6 100644 --- a/build.gradle +++ b/build.gradle @@ -53,6 +53,7 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-api:0.11.5' implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' + implementation 'com.nimbusds:nimbus-jose-jwt:3.10' // security implementation 'org.springframework.boot:spring-boot-starter-security' From 254367187661484b2eb9fe39bbd88361b055a67c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 16:14:03 +0900 Subject: [PATCH 144/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Use?= =?UTF-8?q?r=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - profileImage 필드 타입을 int에서 Integer로 변경 - updateRefreshToken 메서드에 authAccessToken 파라미터 추가 - updateUser 메서드 추가: 사용자 인증 정보 업데이트 --- .../java/org/terning/terningserver/domain/User.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/domain/User.java b/src/main/java/org/terning/terningserver/domain/User.java index 2fa5bb9..8a41012 100644 --- a/src/main/java/org/terning/terningserver/domain/User.java +++ b/src/main/java/org/terning/terningserver/domain/User.java @@ -40,7 +40,7 @@ public class User extends BaseTimeEntity { @Column(length = 12) private String name; // 사용자 이름 - private int profileImage; //유저 아이콘 + private Integer profileImage; //유저 아이콘 @Enumerated(STRING) private AuthType authType; // 인증 유형 (예: 카카오, 애플) @@ -59,8 +59,9 @@ public class User extends BaseTimeEntity { private State state; // 사용자 상태 (예: 활성, 비활성, 정지) - public void updateRefreshToken(String refreshToken) { + public void updateRefreshToken(String authAccessToken, String refreshToken) { this.refreshToken = refreshToken; + this.authAccessToken = authAccessToken; } public void resetRefreshToken() { @@ -83,4 +84,11 @@ public void updateProfile(String name, Integer profileImage) { public void assignFilter(Filter filter) { this.filter = filter; } + + public void updateUser(AuthType authType, String authId, User user) { + this.authType = authType; + this.authId = authId; + this.authAccessToken = user.getAuthAccessToken(); + this.refreshToken = user.getRefreshToken(); + } } From 1d2a5ecd5b2b0f0e958047851a5b346cf1841e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:20:26 +0900 Subject: [PATCH 145/205] =?UTF-8?q?[=E2=9C=A8feat/#47]:=20Swagger=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FilterController.java | 7 +++-- .../controller/swagger/FilterSwagger.java | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java diff --git a/src/main/java/org/terning/terningserver/controller/FilterController.java b/src/main/java/org/terning/terningserver/controller/FilterController.java index d827eef..69bb319 100644 --- a/src/main/java/org/terning/terningserver/controller/FilterController.java +++ b/src/main/java/org/terning/terningserver/controller/FilterController.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.terning.terningserver.controller.swagger.FilterSwagger; import org.terning.terningserver.dto.filter.request.UserFilterRequestDto; import org.terning.terningserver.dto.filter.response.UserFilterResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; @@ -13,7 +14,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") -public class FilterController { +public class FilterController implements FilterSwagger { private final FilterService filterService; @@ -26,7 +27,9 @@ public ResponseEntity> getUserFilter(@Req } @PutMapping("/filters") - public ResponseEntity updateUserFilter(@RequestBody UserFilterRequestDto requestDto) { + public ResponseEntity updateUserFilter( + @RequestHeader("Authorization") String token, + @RequestBody UserFilterRequestDto requestDto) { filterService.updateUserFilter(requestDto); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_SCRAP)); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java new file mode 100644 index 0000000..1030a6e --- /dev/null +++ b/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java @@ -0,0 +1,26 @@ +package org.terning.terningserver.controller.swagger; + + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.terning.terningserver.dto.filter.request.UserFilterRequestDto; +import org.terning.terningserver.dto.filter.response.UserFilterResponseDto; +import org.terning.terningserver.exception.dto.SuccessResponse; + +@Tag(name = "Filter", description = "사용자 필터링 관련 API") +public interface FilterSwagger { + + @Operation(summary = "사용자 필터링 정보 조회 API", description = "사용자가 설정한 필터링 정보를 조회하는 API") + ResponseEntity> getUserFilter( + @RequestHeader("Authorization") String token + ); + + @Operation(summary = "사용자 필터링 정보 수정 API", description = "사용자 필터링을 수정하는 API") + ResponseEntity updateUserFilter( + @RequestHeader("Authorization") String token, + @RequestBody UserFilterRequestDto requestDto + ); +} From aec75c5343c1693faab5b6a5278a44dc49a5368f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 16:43:36 +0900 Subject: [PATCH 146/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#17]:=20Err?= =?UTF-8?q?orMessage=20=EC=97=B4=EA=B1=B0=ED=98=95=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 중복된 에러 메시지 및 코드 정리 - SOCIAL_LOGIN_FAILED, TOKEN_REISSUE_FAILED, SIGN_UP_FAILED, USER_ALREADY_EXISTS 등 중복된 메시지 제거 --- .../exception/enums/ErrorMessage.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index cd06216..1d7fdf8 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -10,23 +10,23 @@ public enum ErrorMessage { // 소셜 로그인 INVALID_TOKEN(401, "유효하지 않은 토큰입니다."), INVALID_KEY(401, "유효하지 않은 키입니다."), - SOCIAL_LOGIN_FAILED(404, "소셜 로그인애 실패하였습니다"), + FAILED_SOCIAL_LOGIN(404, "소셜 로그인애 실패하였습니다"), INVALID_USER(404, "유효하지 않은 유저입니다."), - TOKEN_REISSUE_FAILED(404, "토큰 재발급에 실패하였습니다."), + FAILED_TOKEN_REISSUE(404, "토큰 재발급에 실패하였습니다."), // 회원가입 - SIGN_UP_FAILED(401, "회원가입에 실패하였습니다"), - USER_ALREADY_EXISTS(401, "이미 존재하는 유저입니다"), + FAILED_SIGN_UP(401, "회원가입에 실패하였습니다"), + EXISTS_USER_ALREADY(401, "이미 존재하는 유저입니다"), // 사용자 필터링 정보 생성 - SIGN_UP_FILTER_FAILED(404, "회원가입 필터링 정보 생성에 실패하였습니다"), + FAILED_SIGN_UP_FILTER(404, "회원가입 필터링 정보 생성에 실패하였습니다"), // 로그 아웃 - SIGN_OUT_FAILED(404, "로그아웃에 실패하였습니다"), - REFRESH_TOKEN_RESET_FAILED(400, "리프레쉬 토큰 초기화에 실패하였습니다"), + FAILED_SIGN_OUT(404, "로그아웃에 실패하였습니다"), + FAILED_REFRESH_TOKEN_RESET(400, "리프레쉬 토큰 초기화에 실패하였습니다"), // 계정 탈퇴 - WITHDRAW_FAILED(404, "계정 탈퇴에 실패하였습니다"), + FAILED_WITHDRAW(404, "계정 탈퇴에 실패하였습니다"), //404(NotFound) NOT_FOUND_INTERN_CATEGORY(404, "해당 인턴 공고는 존재하지 않습니다"), From e6f7f0cdd59c83277df5f3abe7177b4a935d1ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Tue, 16 Jul 2024 17:40:21 +0900 Subject: [PATCH 147/205] =?UTF-8?q?[=F0=9F=93=81file]:=20=EC=84=9C?= =?UTF-8?q?=EB=B8=8C=EB=AA=A8=EB=93=88=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/terning/terningserver/service/ScrapService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java index 72fce3d..de1796a 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapService.java +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -22,5 +22,6 @@ public interface ScrapService { List getMonthlyScraps(Long userId, int year, int month); List getMonthlyScrapsAsList(Long userId, int year, int month); + List getDailyScraps(Long userId, LocalDate date); } From 40caf461b76238f71e7e5102e7d7eae7dd76d22b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 17:42:28 +0900 Subject: [PATCH 148/205] =?UTF-8?q?[=E2=9C=A8feat/#55]:=20PrincipalHandler?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PrincipalHandler 클래스를 생성하여 JWT 기반의 사용자 ID 추출 기능 구현 - SecurityContextHolder를 사용하여 인증된 사용자 정보 가져오기 - 익명 사용자일 경우 CustomException을 발생시키는 로직 추가 --- .../terningserver/jwt/PrincipalHandler.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java diff --git a/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java b/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java new file mode 100644 index 0000000..eac7d62 --- /dev/null +++ b/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java @@ -0,0 +1,26 @@ +package org.terning.terningserver.jwt; + +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.terning.terningserver.exception.CustomException; + +import static org.terning.terningserver.exception.enums.ErrorMessage.UNAUTHORIZED_JWT_EXCEPTION; + +@Component +public class PrincipalHandler { + private static final String ANONYMOUS_USER = "anonymousUser"; + + public Long getUserIdFromPrincipal() { + Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + isPrincipalNull(principal); + return Long.valueOf(principal.toString()); + } + + public void isPrincipalNull( + final Object principal + ) { + if (principal.toString().equals(ANONYMOUS_USER)) { + throw new CustomException(UNAUTHORIZED_JWT_EXCEPTION); + } + } +} \ No newline at end of file From 155ae11abe08cb357f130534bfae2d8839bca710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 17:43:02 +0900 Subject: [PATCH 149/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#55]:=20Err?= =?UTF-8?q?orMessage=20=EC=A4=91=EB=B3=B5=20=EB=B0=8F=20=EB=88=84=EB=9D=BD?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/exception/enums/ErrorMessage.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index 419a693..d659e7b 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -8,11 +8,12 @@ public enum ErrorMessage { // 소셜 로그인 - INVALID_TOKEN(401, "유효하지 않은 토큰입니다."), - INVALID_KEY(401, "유효하지 않은 키입니다."), + INVALID_TOKEN(401, "유효하지 않은 토큰입니다"), + INVALID_KEY(401, "유효하지 않은 키입니다"), FAILED_SOCIAL_LOGIN(404, "소셜 로그인애 실패하였습니다"), - INVALID_USER(404, "유효하지 않은 유저입니다."), - FAILED_TOKEN_REISSUE(404, "토큰 재발급에 실패하였습니다."), + INVALID_USER(404, "유효하지 않은 유저입니다"), + FAILED_TOKEN_REISSUE(404, "토큰 재발급에 실패하였습니다"), + UNAUTHORIZED_JWT_EXCEPTION(401, "유효하지 않은 토큰입니다"), // 회원가입 FAILED_SIGN_UP(401, "회원가입에 실패하였습니다"), From d9cf5f9d1ae13c4d0f85aba9891cf411637b0d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Tue, 16 Jul 2024 17:48:28 +0900 Subject: [PATCH 150/205] =?UTF-8?q?[=F0=9F=93=81file]:=20=EC=84=9C?= =?UTF-8?q?=EB=B8=8C=EB=AA=A8=EB=93=88=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/terning/terningserver/util/DateUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/terning/terningserver/util/DateUtil.java b/src/main/java/org/terning/terningserver/util/DateUtil.java index 2e7af41..f08c300 100644 --- a/src/main/java/org/terning/terningserver/util/DateUtil.java +++ b/src/main/java/org/terning/terningserver/util/DateUtil.java @@ -25,4 +25,5 @@ public static String convertDeadline(LocalDate deadline) { + deadline.getMonthValue() + "월 " + deadline.getDayOfMonth() + "일"; } + } From a2f7402c2aa412be26aebc730492b46ff726b413 Mon Sep 17 00:00:00 2001 From: Willy Date: Tue, 16 Jul 2024 18:49:32 +0900 Subject: [PATCH 151/205] =?UTF-8?q?[=F0=9F=94=80merge/#55]=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EC=83=88=20=EB=B8=8C?= =?UTF-8?q?=EB=9E=9C=EC=B9=98=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/jwt/PrincipalHandler.java | 4 ++-- .../repository/user/UserRepository.java | 2 +- .../terningserver/service/AuthServiceImpl.java | 16 +++------------- .../terningserver/service/ScrapServiceImpl.java | 3 ++- 4 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java b/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java index eac7d62..78c3879 100644 --- a/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java +++ b/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java @@ -10,13 +10,13 @@ public class PrincipalHandler { private static final String ANONYMOUS_USER = "anonymousUser"; - public Long getUserIdFromPrincipal() { + public static Long getUserIdFromPrincipal() { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); isPrincipalNull(principal); return Long.valueOf(principal.toString()); } - public void isPrincipalNull( + public static void isPrincipalNull( final Object principal ) { if (principal.toString().equals(ANONYMOUS_USER)) { diff --git a/src/main/java/org/terning/terningserver/repository/user/UserRepository.java b/src/main/java/org/terning/terningserver/repository/user/UserRepository.java index d8e58d1..100485e 100644 --- a/src/main/java/org/terning/terningserver/repository/user/UserRepository.java +++ b/src/main/java/org/terning/terningserver/repository/user/UserRepository.java @@ -8,7 +8,7 @@ public interface UserRepository extends JpaRepository { - Optional findByAuthTypeAndAuthAccessToken(AuthType authType, String authId); + Optional findByAuthTypeAndRefreshToken(AuthType authType, String refreshToken); Optional findByRefreshToken(String refreshToken); diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index 0d4418b..9f27c87 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -75,11 +75,10 @@ public TokenGetResponseDto reissueToken(String refreshToken) { return TokenGetResponseDto.of(token); } - private User - getUser(String authAccessToken, AuthType authType) { - User user = userRepository.findByAuthTypeAndAuthAccessToken(authType, authAccessToken) + private User getUser(String refreshToken, AuthType authType) { + User user = userRepository.findByAuthTypeAndRefreshToken(authType, refreshToken) .orElseThrow(() -> new CustomException(INVALID_USER)); - String authId = getAuthId(user.getAuthType(), authAccessToken); + String authId = getAuthId(user.getAuthType(), refreshToken); return signUp(authType, authId, user); } @@ -95,15 +94,6 @@ private User signUp(AuthType authType, String authId, User user) { return userRepository.save(user); } - private User saveUser(AuthType authType, String authId) { - User user = User.builder() - .authType(authType) - .authId(authId) - .build(); - - return userRepository.save(user); - } - private Token getToken(User user) { val token = generateToken(new UserAuthentication(user.getId(), null, null)); user.updateRefreshToken(token.getRefreshToken(), token.getAccessToken()); diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 38fe279..ee55876 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -14,6 +14,7 @@ import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.jwt.PrincipalHandler; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import org.terning.terningserver.repository.scrap.ScrapRepository; import org.terning.terningserver.repository.user.UserRepository; @@ -117,7 +118,7 @@ public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto req getInternshipAnnouncement(internshipAnnouncementId); scrapRepository.save(Scrap.create( - findUser(1L), + findUser(PrincipalHandler.getUserIdFromPrincipal()), getInternshipAnnouncement(internshipAnnouncementId), findColor(request.color()) )); From 65db3774128a6e663c75cc3aac4b9be71a0b752e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 23:06:26 +0900 Subject: [PATCH 152/205] . --- .../controller/AuthController.java | 15 +++--- .../controller/swagger/AuthSwagger.java | 5 +- .../terning/terningserver/domain/User.java | 8 +--- .../dto/auth/request/SignUpRequestDto.java | 7 ++- .../dto/auth/response/SignInResponseDto.java | 8 ++-- .../dto/auth/response/SignUpResponseDto.java | 14 ++++++ .../repository/user/UserRepository.java | 4 ++ .../service/AppleServiceImpl.java | 15 ++++-- .../terningserver/service/AuthService.java | 4 +- .../service/AuthServiceImpl.java | 47 ++++++++++++++----- .../terningserver/service/SignUpService.java | 20 ++++++-- src/main/resources/application-dev.yml | 2 +- 12 files changed, 103 insertions(+), 46 deletions(-) create mode 100644 src/main/java/org/terning/terningserver/dto/auth/response/SignUpResponseDto.java diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index 5736c4c..cae481b 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -12,6 +12,7 @@ import org.terning.terningserver.dto.auth.request.SignUpRequestDto; import org.terning.terningserver.dto.auth.response.SignInResponseDto; import org.terning.terningserver.dto.auth.response.SignUpFilterResponseDto; +import org.terning.terningserver.dto.auth.response.SignUpResponseDto; import org.terning.terningserver.dto.auth.response.TokenGetResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; import org.terning.terningserver.service.AuthService; @@ -37,15 +38,13 @@ public ResponseEntity> signIn( @RequestHeader("Authorization") String authAccessToken, @RequestBody SignInRequestDto request ) { - User user = authService.saveUser(authAccessToken, request); +// User user = authService.saveUser(authAccessToken, request); - val signInResponse = authService.signIn(user, request); + val signInResponse = authService.signIn(authAccessToken, request); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_IN, signInResponse)); } - - // TODO: 에러 메시지 위치 @PostMapping("/token-reissue") public ResponseEntity> reissueToken( @@ -57,13 +56,13 @@ public ResponseEntity> reissueToken( } @PostMapping("/sign-up") - public ResponseEntity> signUp( - @RequestHeader("User-Id") Long userId, + public ResponseEntity> signUp( + @RequestHeader("authId") String authId, @RequestBody SignUpRequestDto request ) { - signUpService.signUp(userId, request.name(), request.profileImage()); + SignUpResponseDto signUpResponseDto = signUpService.signUp(authId, request.name(), request.profileImage(), request.authType()); - return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_UP)); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_UP, signUpResponseDto)); } @PostMapping("/sign-up/filter") diff --git a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java index f3611ac..543d545 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java @@ -10,6 +10,7 @@ import org.terning.terningserver.dto.auth.request.SignUpRequestDto; import org.terning.terningserver.dto.auth.response.SignInResponseDto; import org.terning.terningserver.dto.auth.response.SignUpFilterResponseDto; +import org.terning.terningserver.dto.auth.response.SignUpResponseDto; import org.terning.terningserver.dto.auth.response.TokenGetResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; @@ -36,8 +37,8 @@ ResponseEntity> filter( ); @Operation(summary = "회원가입", description = "회원가입 API") - ResponseEntity> signUp( - @RequestHeader("User-Id") Long userId, + ResponseEntity> signUp( + @RequestHeader("authId") String authId, @RequestBody SignUpRequestDto request ); diff --git a/src/main/java/org/terning/terningserver/domain/User.java b/src/main/java/org/terning/terningserver/domain/User.java index 953c2a2..773bc73 100644 --- a/src/main/java/org/terning/terningserver/domain/User.java +++ b/src/main/java/org/terning/terningserver/domain/User.java @@ -46,9 +46,6 @@ public class User extends BaseTimeEntity { @Column(length = 256) private String authId; // 인증 서비스에서 제공하는 고유 ID - @Column(length = 256) - private String authAccessToken; // 엑세스 토큰 - @Column(length = 256) private String refreshToken; // 리프레시 토큰 @@ -56,10 +53,8 @@ public class User extends BaseTimeEntity { @Enumerated(STRING) private State state; // 사용자 상태 (예: 활성, 비활성, 정지) - - public void updateRefreshToken(String authAccessToken, String refreshToken) { + public void updateRefreshToken(String refreshToken) { this.refreshToken = refreshToken; - this.authAccessToken = authAccessToken; } public void resetRefreshToken() { @@ -86,7 +81,6 @@ public void assignFilter(Filter filter) { public void updateUser(AuthType authType, String authId, User user) { this.authType = authType; this.authId = authId; - this.authAccessToken = user.getAuthAccessToken(); this.refreshToken = user.getRefreshToken(); } } diff --git a/src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java index 7309ecf..5e69811 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java @@ -2,19 +2,22 @@ import lombok.Builder; import lombok.NonNull; +import org.terning.terningserver.domain.enums.AuthType; import static lombok.AccessLevel.PRIVATE; @Builder(access = PRIVATE) public record SignUpRequestDto( @NonNull String name, - @NonNull int profileImage + @NonNull int profileImage, + @NonNull AuthType authType ) { - public static SignUpRequestDto of(String name, int profileImage){ + public static SignUpRequestDto of(String name, int profileImage, AuthType authType){ return SignUpRequestDto.builder() .name(name) .profileImage(profileImage) + .authType(authType) .build(); } diff --git a/src/main/java/org/terning/terningserver/dto/auth/response/SignInResponseDto.java b/src/main/java/org/terning/terningserver/dto/auth/response/SignInResponseDto.java index 7cfa536..e583f22 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/response/SignInResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/response/SignInResponseDto.java @@ -11,12 +11,14 @@ public record SignInResponseDto( String accessToken, String refreshToken, Long userId, + String authId, AuthType authType ) { - public static SignInResponseDto of(Token token, Long userId, AuthType authType) { + public static SignInResponseDto of(Token token, String authId, AuthType authType, Long userId) { return SignInResponseDto.builder() - .accessToken(token.getAccessToken()) - .refreshToken(token.getRefreshToken()) + .accessToken(token == null ? null : token.getAccessToken()) + .refreshToken(token == null ? null : token.getRefreshToken()) + .authId(authId) .userId(userId) .authType(authType) .build(); diff --git a/src/main/java/org/terning/terningserver/dto/auth/response/SignUpResponseDto.java b/src/main/java/org/terning/terningserver/dto/auth/response/SignUpResponseDto.java new file mode 100644 index 0000000..202b0b4 --- /dev/null +++ b/src/main/java/org/terning/terningserver/dto/auth/response/SignUpResponseDto.java @@ -0,0 +1,14 @@ +package org.terning.terningserver.dto.auth.response; + +import org.terning.terningserver.domain.enums.AuthType; + +public record SignUpResponseDto( + String accessToken, + String refreshToken, + Long userId, + AuthType authType +) { + public static SignUpResponseDto of(String accessToken, String refreshToken, Long userId, AuthType authType) { + return new SignUpResponseDto(accessToken, refreshToken, userId, authType); + } +} diff --git a/src/main/java/org/terning/terningserver/repository/user/UserRepository.java b/src/main/java/org/terning/terningserver/repository/user/UserRepository.java index 100485e..4be8d57 100644 --- a/src/main/java/org/terning/terningserver/repository/user/UserRepository.java +++ b/src/main/java/org/terning/terningserver/repository/user/UserRepository.java @@ -12,4 +12,8 @@ public interface UserRepository extends JpaRepository { Optional findByRefreshToken(String refreshToken); + Optional findByAuthId(String authId); + + Optional findByAuthIdAndAuthType(String authId, AuthType authType); + } diff --git a/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java b/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java index 47be476..53ac5fb 100644 --- a/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java @@ -1,9 +1,7 @@ package org.terning.terningserver.service; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.google.gson.*; +import io.jsonwebtoken.Jwts; import lombok.RequiredArgsConstructor; import lombok.val; import org.springframework.http.HttpMethod; @@ -40,7 +38,14 @@ public String getAppleData(String authAccessToken) { val publicKeyList = getApplePublicKeys(); val publicKey = makePublicKey(authAccessToken, publicKeyList); - return ""; + val userInfo = Jwts.parserBuilder() + .setSigningKey(publicKey) + .build() + .parseClaimsJws(getTokenFromBearerString(authAccessToken)) + .getBody(); + + val userInfoObject = (JsonObject)JsonParser.parseString(new Gson().toJson(userInfo)); + return userInfoObject.get(ValueConfig.ID).getAsString(); } private JsonArray getApplePublicKeys() { diff --git a/src/main/java/org/terning/terningserver/service/AuthService.java b/src/main/java/org/terning/terningserver/service/AuthService.java index c527e90..ff4c517 100644 --- a/src/main/java/org/terning/terningserver/service/AuthService.java +++ b/src/main/java/org/terning/terningserver/service/AuthService.java @@ -7,9 +7,9 @@ public interface AuthService { - SignInResponseDto signIn(User user, SignInRequestDto request); + SignInResponseDto signIn(String authAccessToken, SignInRequestDto request); - User saveUser(String authAccessToken, SignInRequestDto request); + User saveUser(SignInRequestDto request); void signOut(long userId); diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index 9f27c87..bf38643 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -38,16 +38,29 @@ public class AuthServiceImpl implements AuthService { @Override @Transactional - public SignInResponseDto signIn(User user, SignInRequestDto request) { - User authenticatedUser = getUser(user.getAuthAccessToken(), request.authType()); - val token = getToken(authenticatedUser); - return SignInResponseDto.of(token, authenticatedUser.getId(), authenticatedUser.getAuthType()); + public SignInResponseDto signIn(String authAccessToken, SignInRequestDto request) { + String authId = getAuthId(request.authType(), authAccessToken); + + Optional userOptional = userRepository.findByAuthIdAndAuthType(authId, request.authType()); + + if (userOptional.isPresent()) { + User user = userOptional.get(); + return SignInResponseDto.of( + getToken(user), + authId, + request.authType(), + user.getId() + ); + } + else { + return SignInResponseDto.of(null, authId, request.authType(), null); + } } + @Transactional - public User saveUser(String authAccessToken, SignInRequestDto request) { + public User saveUser(SignInRequestDto request) { User user = User.builder() - .authAccessToken(authAccessToken) .authType(request.authType()) .build(); return userRepository.save(user); @@ -70,11 +83,10 @@ public void withdraw(long userId) { @Override public TokenGetResponseDto reissueToken(String refreshToken) { val user = findUser(refreshToken); - val token = Optional.ofNullable(generateAccessToken(user.getId())) + val token = Optional.ofNullable(generateRefreshToken(user.getId())) .orElseThrow(() -> new CustomException(FAILED_TOKEN_REISSUE)); return TokenGetResponseDto.of(token); } - private User getUser(String refreshToken, AuthType authType) { User user = userRepository.findByAuthTypeAndRefreshToken(authType, refreshToken) .orElseThrow(() -> new CustomException(INVALID_USER)); @@ -82,6 +94,13 @@ private User getUser(String refreshToken, AuthType authType) { return signUp(authType, authId, user); } +// private User getUser(String authAccessToken, AuthType authType) { +//// User user = userRepository.findByAuthTypeAndAuthAccessToken(authType, authAccessToken) +//// .orElseThrow(() -> new CustomException(INVALID_USER)); +// String authId = getAuthId(authType, authAccessToken); +// return signUp(authType, authId); +// } + private String getAuthId(AuthType authType, String authAccessToken) { return switch (authType) { case APPLE -> appleService.getAppleData(authAccessToken); @@ -96,7 +115,13 @@ private User signUp(AuthType authType, String authId, User user) { private Token getToken(User user) { val token = generateToken(new UserAuthentication(user.getId(), null, null)); - user.updateRefreshToken(token.getRefreshToken(), token.getAccessToken()); + user.updateRefreshToken(token.getRefreshToken()); + return token; + } + + public Token getTokenByAuthId(String AuthId) { + long id = Long.parseLong(AuthId); + val token = generateToken(new UserAuthentication(id, null, null)); return token; } @@ -120,9 +145,9 @@ private String getTokenFromBearerString(String token) { return token.replaceFirst(ValueConfig.BEARER_HEADER, ValueConfig.BLANK); } - private String generateAccessToken(long userId) { + private String generateRefreshToken(long userId) { val authentication = new UserAuthentication(userId, null, null); - return jwtTokenProvider.generateToken(authentication, valueConfig.getAccessTokenExpired()); + return jwtTokenProvider.generateToken(authentication, valueConfig.getRefreshTokenExpired()); } private void deleteUser(User user) { diff --git a/src/main/java/org/terning/terningserver/service/SignUpService.java b/src/main/java/org/terning/terningserver/service/SignUpService.java index ef4f02d..ecb77bb 100644 --- a/src/main/java/org/terning/terningserver/service/SignUpService.java +++ b/src/main/java/org/terning/terningserver/service/SignUpService.java @@ -2,7 +2,10 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.terning.terningserver.domain.Token; import org.terning.terningserver.domain.User; +import org.terning.terningserver.domain.enums.AuthType; +import org.terning.terningserver.dto.auth.response.SignUpResponseDto; import org.terning.terningserver.exception.CustomException; import org.terning.terningserver.repository.user.UserRepository; @@ -14,11 +17,18 @@ public class SignUpService { private final UserRepository userRepository; + private final AuthServiceImpl authService; - public User signUp(Long userId, String name, Integer profileImage) { - return userRepository.findById(userId).map(user -> { - user.updateProfile(name, profileImage); - return userRepository.save(user); - }).orElseThrow(() -> new CustomException(FAILED_SIGN_UP)); + public SignUpResponseDto signUp(String authId, String name, Integer profileImage, AuthType authType) { + Token token = authService.getTokenByAuthId(authId); + User user = userRepository.save(User.builder() + .authId(authId) + .name(name) + .authType(authType) + .refreshToken(token.getRefreshToken()) + .profileImage(profileImage) + .build()); + + return SignUpResponseDto.of(token.getAccessToken(), token.getRefreshToken(), user.getId(), authType); } } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index d592417..df28152 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -1,7 +1,7 @@ spring: datasource: driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://localhost:5432/terning + url: jdbc:postgresql://localhost:5432/terning55 username: ${USER_ID} password: ${USER_PW} From 1daffaca226eda2ddf936d7e53984d14017f7148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Tue, 16 Jul 2024 17:40:21 +0900 Subject: [PATCH 153/205] =?UTF-8?q?[=F0=9F=93=81file]:=20=EC=84=9C?= =?UTF-8?q?=EB=B8=8C=EB=AA=A8=EB=93=88=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/terning/terningserver/service/ScrapService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java index 72fce3d..de1796a 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapService.java +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -22,5 +22,6 @@ public interface ScrapService { List getMonthlyScraps(Long userId, int year, int month); List getMonthlyScrapsAsList(Long userId, int year, int month); + List getDailyScraps(Long userId, LocalDate date); } From 8cb6874c523a4e5395711c59db3cd34f4e05d6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Tue, 16 Jul 2024 17:48:28 +0900 Subject: [PATCH 154/205] =?UTF-8?q?[=F0=9F=93=81file]:=20=EC=84=9C?= =?UTF-8?q?=EB=B8=8C=EB=AA=A8=EB=93=88=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/terning/terningserver/util/DateUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/terning/terningserver/util/DateUtil.java b/src/main/java/org/terning/terningserver/util/DateUtil.java index 2e7af41..f08c300 100644 --- a/src/main/java/org/terning/terningserver/util/DateUtil.java +++ b/src/main/java/org/terning/terningserver/util/DateUtil.java @@ -25,4 +25,5 @@ public static String convertDeadline(LocalDate deadline) { + deadline.getMonthValue() + "월 " + deadline.getDayOfMonth() + "일"; } + } From 67dea1488e09b33286308943c623c527e47565de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 16 Jul 2024 23:08:47 +0900 Subject: [PATCH 155/205] . --- .../java/org/terning/terningserver/config/SecurityConfig.java | 4 ++-- .../org/terning/terningserver/controller/ScrapController.java | 3 ++- .../java/org/terning/terningserver/service/ScrapService.java | 2 +- .../org/terning/terningserver/service/ScrapServiceImpl.java | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/terning/terningserver/config/SecurityConfig.java b/src/main/java/org/terning/terningserver/config/SecurityConfig.java index 2a719ae..6f3107c 100644 --- a/src/main/java/org/terning/terningserver/config/SecurityConfig.java +++ b/src/main/java/org/terning/terningserver/config/SecurityConfig.java @@ -24,10 +24,10 @@ public class SecurityConfig { private static final String[] AUTH_WHITELIST = { "/v3/api-docs/**", "/swagger-ui.html", - "/swagger-ui/index.html#/**", + "/api/v1/swagger-ui/index.html#/**", "/swagger-resources/**", "/swagger-ui/**", - "/api/v1/**" + "/api/v1/auth/**" }; @Bean diff --git a/src/main/java/org/terning/terningserver/controller/ScrapController.java b/src/main/java/org/terning/terningserver/controller/ScrapController.java index e6a318a..c362062 100644 --- a/src/main/java/org/terning/terningserver/controller/ScrapController.java +++ b/src/main/java/org/terning/terningserver/controller/ScrapController.java @@ -7,6 +7,7 @@ import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; import org.terning.terningserver.dto.scrap.request.UpdateScrapRequestDto; import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.jwt.PrincipalHandler; import org.terning.terningserver.service.ScrapService; import static org.terning.terningserver.exception.enums.SuccessMessage.*; @@ -19,7 +20,7 @@ public class ScrapController implements ScrapSwagger { @PostMapping("/scraps/{internshipAnnouncementId}") public ResponseEntity createScrap(@PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request) { - scrapService.createScrap(internshipAnnouncementId, request); + scrapService.createScrap(internshipAnnouncementId, request, PrincipalHandler.getUserIdFromPrincipal()); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_CREATE_SCRAP)); } diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java index de1796a..7102daf 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapService.java +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -13,7 +13,7 @@ public interface ScrapService { List getTodayScrap(Long userId); - void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request); + void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request, Long userId); void deleteScrap(Long scrapId); diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index ee55876..d07970b 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -114,7 +114,7 @@ public List getDailyScraps(Long userId, LocalDate date) { @Override @Transactional - public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request) { + public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request, Long userId) { getInternshipAnnouncement(internshipAnnouncementId); scrapRepository.save(Scrap.create( From 81bf914844080d1eb930d24e4ec64ba336fac15f Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 03:00:51 +0900 Subject: [PATCH 156/205] =?UTF-8?q?[=F0=9F=94=80merge/#55]=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EC=83=88=20=EB=B8=8C?= =?UTF-8?q?=EB=9E=9C=EC=B9=98=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/controller/AuthController.java | 7 +++---- .../controller/CalendarController.java | 14 ++++---------- .../terningserver/controller/FilterController.java | 7 +++++-- .../terningserver/controller/HomeController.java | 13 ++++--------- .../terningserver/controller/ScrapController.java | 8 ++++++-- .../controller/UserProfileController.java | 9 ++------- .../controller/swagger/AuthSwagger.java | 5 +++-- .../controller/swagger/CalendarSwagger.java | 7 ++++--- .../controller/swagger/FilterSwagger.java | 4 ++-- .../controller/swagger/HomeSwagger.java | 11 ++++++----- .../controller/swagger/ScrapSwagger.java | 3 ++- .../controller/swagger/UserSwagger.java | 2 +- .../dto/filter/request/UserFilterRequestDto.java | 2 ++ .../terningserver/service/FilterServiceImpl.java | 4 ++-- .../terning/terningserver/service/HomeService.java | 2 +- .../terningserver/service/HomeServiceImpl.java | 8 +------- .../terningserver/service/ScrapServiceImpl.java | 2 +- src/main/resources/application-dev.yml | 2 +- 18 files changed, 50 insertions(+), 60 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index cae481b..1d54404 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.val; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import org.terning.terningserver.controller.swagger.AuthSwagger; import org.terning.terningserver.domain.Filter; @@ -80,16 +81,14 @@ public ResponseEntity> filter( } @PostMapping("/logout") - public ResponseEntity signOut(Principal principal) { - val userId = Long.parseLong(principal.getName()); + public ResponseEntity signOut(@AuthenticationPrincipal Long userId) { authService.signOut(userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_OUT)); } @DeleteMapping("/withdraw") - public ResponseEntity withdraw(Principal principal) { - val userId = Long.parseLong(principal.getName()); + public ResponseEntity withdraw(@AuthenticationPrincipal Long userId) { authService.withdraw(userId); diff --git a/src/main/java/org/terning/terningserver/controller/CalendarController.java b/src/main/java/org/terning/terningserver/controller/CalendarController.java index 4c7d961..6649df8 100644 --- a/src/main/java/org/terning/terningserver/controller/CalendarController.java +++ b/src/main/java/org/terning/terningserver/controller/CalendarController.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import org.terning.terningserver.controller.swagger.CalendarSwagger; import org.terning.terningserver.dto.calendar.response.DailyScrapResponseDto; @@ -24,38 +25,31 @@ public class CalendarController implements CalendarSwagger { @GetMapping("/calendar/monthly-default") public ResponseEntity>> getMonthlyScraps( - @RequestHeader("Authorization") String token, + @AuthenticationPrincipal Long userId, @RequestParam("year") int year, @RequestParam("month") int month ){ - Long userId = getUserIdFromToken(token); List monthlyScraps = scrapService.getMonthlyScraps(userId, year, month); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_MONTHLY_SCRAPS, monthlyScraps)); } @GetMapping("/calendar/monthly-list") public ResponseEntity>> getMonthlyScrapsAsList( - @RequestHeader("Authorization") String token, + @AuthenticationPrincipal Long userId, @RequestParam("year") int year, @RequestParam("month") int month ){ - Long userId = getUserIdFromToken(token); List monthlyScraps = scrapService.getMonthlyScrapsAsList(userId, year, month); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_MONTHLY_SCRAPS_AS_LIST, monthlyScraps)); } @GetMapping("/calendar/daily") public ResponseEntity>> getDailyScraps( - @RequestHeader("Authorization") String token, + @AuthenticationPrincipal Long userId, @RequestParam("date") String date ){ - Long userId = getUserIdFromToken(token); LocalDate localDate = LocalDate.parse(date); List dailyScraps = scrapService.getDailyScraps(userId, localDate); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_DAILY_SCRAPS, dailyScraps)); } - private Long getUserIdFromToken(String token){ - //실제 토큰에서 userId를 받아오는 로직 구현 - return 1L; //임시로 사용자 ID 1로 반환 - } } diff --git a/src/main/java/org/terning/terningserver/controller/FilterController.java b/src/main/java/org/terning/terningserver/controller/FilterController.java index 69bb319..739fe64 100644 --- a/src/main/java/org/terning/terningserver/controller/FilterController.java +++ b/src/main/java/org/terning/terningserver/controller/FilterController.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import org.terning.terningserver.controller.swagger.FilterSwagger; import org.terning.terningserver.dto.filter.request.UserFilterRequestDto; @@ -19,7 +20,9 @@ public class FilterController implements FilterSwagger { private final FilterService filterService; @GetMapping("/filters") - public ResponseEntity> getUserFilter(@RequestHeader("Authorization") String token) { + public ResponseEntity> getUserFilter( + @AuthenticationPrincipal Long userId + ) { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_USER_FILTER, filterService.getUserFilter() @@ -28,7 +31,7 @@ public ResponseEntity> getUserFilter(@Req @PutMapping("/filters") public ResponseEntity updateUserFilter( - @RequestHeader("Authorization") String token, + @AuthenticationPrincipal Long userId, @RequestBody UserFilterRequestDto requestDto) { filterService.updateUserFilter(requestDto); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_SCRAP)); diff --git a/src/main/java/org/terning/terningserver/controller/HomeController.java b/src/main/java/org/terning/terningserver/controller/HomeController.java index c088aea..be5b600 100644 --- a/src/main/java/org/terning/terningserver/controller/HomeController.java +++ b/src/main/java/org/terning/terningserver/controller/HomeController.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import org.terning.terningserver.controller.swagger.HomeSwagger; import org.terning.terningserver.dto.user.response.HomeResponseDto; @@ -28,29 +29,23 @@ public class HomeController implements HomeSwagger { @GetMapping("/home") public ResponseEntity>> getAnnouncements( - @RequestHeader("Authorization") String token, + @AuthenticationPrincipal Long userId, @RequestParam(value = "sortBy", required = false, defaultValue = "deadlineSoon") String sortBy, @RequestParam("startYear") int startYear, @RequestParam("startMonth") int startMonth ){ - List announcements = homeService.getAnnouncements(token, sortBy, startYear, startMonth); + List announcements = homeService.getAnnouncements(userId, sortBy, startYear, startMonth); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_ANNOUNCEMENTS, announcements)); } @GetMapping("/home/today") public ResponseEntity>> getTodayScraps( - @RequestHeader("Authorization") String token + @AuthenticationPrincipal Long userId ){ - Long userId = getUserIdFromToken(token); List scrapList = scrapService.getTodayScrap(userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_TODAY_ANNOUNCEMENTS, scrapList)); } - - private Long getUserIdFromToken(String token){ - //실제 토큰에서 userId를 가져오는 로직 구현 - return 1L; //임시로 사용자 ID 1로 반환 - } } diff --git a/src/main/java/org/terning/terningserver/controller/ScrapController.java b/src/main/java/org/terning/terningserver/controller/ScrapController.java index c362062..9ef27c9 100644 --- a/src/main/java/org/terning/terningserver/controller/ScrapController.java +++ b/src/main/java/org/terning/terningserver/controller/ScrapController.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import org.terning.terningserver.controller.swagger.ScrapSwagger; import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; @@ -19,8 +20,11 @@ public class ScrapController implements ScrapSwagger { private final ScrapService scrapService; @PostMapping("/scraps/{internshipAnnouncementId}") - public ResponseEntity createScrap(@PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request) { - scrapService.createScrap(internshipAnnouncementId, request, PrincipalHandler.getUserIdFromPrincipal()); + public ResponseEntity createScrap( + @AuthenticationPrincipal Long userId, + @PathVariable Long internshipAnnouncementId, + @RequestBody CreateScrapRequestDto request) { + scrapService.createScrap(internshipAnnouncementId, request, userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_CREATE_SCRAP)); } diff --git a/src/main/java/org/terning/terningserver/controller/UserProfileController.java b/src/main/java/org/terning/terningserver/controller/UserProfileController.java index e8072e9..e6b032a 100644 --- a/src/main/java/org/terning/terningserver/controller/UserProfileController.java +++ b/src/main/java/org/terning/terningserver/controller/UserProfileController.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; @@ -22,15 +23,9 @@ public class UserProfileController implements UserSwagger { @GetMapping("/mypage/profile") public ResponseEntity> getProfile( - @RequestHeader("Authorization") String token + @AuthenticationPrincipal Long userId ){ - Long userId = getUserIdFromToken(token); ProfileResponseDto profile = userService.getProfile(userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_GET_PROFILE, profile)); } - - private Long getUserIdFromToken(String token){ - //실제 토큰에서 userId를 가져오는 로직 구현 - return 1L; //임시로 사용자 ID 1로 반환 - } } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java index 543d545..c1709d3 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/AuthSwagger.java @@ -3,6 +3,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.terning.terningserver.dto.auth.request.SignInRequestDto; @@ -44,11 +45,11 @@ ResponseEntity> signUp( @Operation(summary = "로그아웃", description = "로그아웃 API") ResponseEntity signOut( - Principal principal); + @AuthenticationPrincipal Long userId); @Operation(summary = "계정탈퇴", description = "계정탈퇴 API") ResponseEntity withdraw( - Principal principal); + @AuthenticationPrincipal Long userId); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java index 4271afc..2d382fa 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/CalendarSwagger.java @@ -3,6 +3,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.RequestParam; import org.terning.terningserver.dto.calendar.response.DailyScrapResponseDto; import org.terning.terningserver.dto.calendar.response.MonthlyDefaultResponseDto; @@ -16,21 +17,21 @@ public interface CalendarSwagger { @Operation(summary = "캘린더 > 월간 스크랩 공고 조회", description = "월간 스크랩 공고를 조회하는 API") ResponseEntity>> getMonthlyScraps( - String token, + Long userId, int year, int month ); @Operation(summary = "캘린더 > 월간 스크랩 공고 조회 (리스트)", description = "월간 스크랩 공고를 리스트로 조회하는 API") ResponseEntity>> getMonthlyScrapsAsList( - String token, + Long userId, int year, int month ); @Operation(summary = "캘린더 > 일간 스크랩 공고 조회 (리스트)", description = "일간 스크랩 공고를 리스트로 조회하는 API") ResponseEntity>> getDailyScraps( - String token, + Long userId, String date ); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java index 1030a6e..6e37c43 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java @@ -15,12 +15,12 @@ public interface FilterSwagger { @Operation(summary = "사용자 필터링 정보 조회 API", description = "사용자가 설정한 필터링 정보를 조회하는 API") ResponseEntity> getUserFilter( - @RequestHeader("Authorization") String token + Long userId ); @Operation(summary = "사용자 필터링 정보 수정 API", description = "사용자 필터링을 수정하는 API") ResponseEntity updateUserFilter( - @RequestHeader("Authorization") String token, + Long userId, @RequestBody UserFilterRequestDto requestDto ); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java index 7a30afd..82ba92c 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/HomeSwagger.java @@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.terning.terningserver.dto.user.response.HomeResponseDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; @@ -17,14 +18,14 @@ public interface HomeSwagger { @Operation(summary = "홈화면 > 나에게 딱맞는 인턴 공고 조회", description = "특정 사용자에 필터링 조건에 맞는 인턴 공고 정보를 조회하는 API") ResponseEntity>> getAnnouncements( - String token, - String sortBy, - int startYear, - int startMonth + Long userId, + String sortBy, + int startYear, + int startMonth ); @Operation(summary = "홈화면 > 오늘 마감인 스크랩 공고 조회", description = "오늘 마감인 스크랩 공고를 조회하는 API") ResponseEntity>> getTodayScraps( - String token + Long userId ); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java index 66ef0c3..180f99e 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java @@ -3,6 +3,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.terning.terningserver.dto.scrap.request.CreateScrapRequestDto; @@ -14,7 +15,7 @@ public interface ScrapSwagger { @Operation(summary = "스크랩 추가", description = "사용자가 스크랩을 추가하는 API") ResponseEntity createScrap( - @PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request + @AuthenticationPrincipal Long userId, @PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request ); @Operation(summary = "스크랩 취소", description = "사용자가 스크랩을 취소하는 API") diff --git a/src/main/java/org/terning/terningserver/controller/swagger/UserSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/UserSwagger.java index 7ebb1a5..5575e80 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/UserSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/UserSwagger.java @@ -11,6 +11,6 @@ public interface UserSwagger { @Operation(summary = "마이페이지 > 프로필 정보 불러오기", description = "마이페이지에서 프로필 정보를 불러오는 API") ResponseEntity> getProfile( - String token + Long userId ); } diff --git a/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java b/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java index 510766e..e5bb972 100644 --- a/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java +++ b/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java @@ -1,6 +1,8 @@ package org.terning.terningserver.dto.filter.request; public record UserFilterRequestDto( + + Long userId, int grade, int workingPeriod, int startYear, diff --git a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java index 5307c17..a5bd831 100644 --- a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java @@ -24,13 +24,13 @@ public class FilterServiceImpl implements FilterService { @Override public UserFilterResponseDto getUserFilter() { - return UserFilterResponseDto.of(findUser(1L).getFilter()); + return UserFilterResponseDto.of(findUser(6L).getFilter()); } @Override @Transactional public void updateUserFilter(UserFilterRequestDto responseDto) { - User user = findUser(1L); + User user = findUser(6L); Filter filter = user.getFilter(); filter.updateFilter( diff --git a/src/main/java/org/terning/terningserver/service/HomeService.java b/src/main/java/org/terning/terningserver/service/HomeService.java index 216c754..0c79ea5 100644 --- a/src/main/java/org/terning/terningserver/service/HomeService.java +++ b/src/main/java/org/terning/terningserver/service/HomeService.java @@ -6,5 +6,5 @@ public interface HomeService { - List getAnnouncements(String token, String sortBy, int startYear, int startMonth); + List getAnnouncements(Long userId, String sortBy, int startYear, int startMonth); } diff --git a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java index 664c725..9fab987 100644 --- a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java @@ -23,8 +23,7 @@ public class HomeServiceImpl implements HomeService{ private final ScrapRepository scrapRepository; @Override - public List getAnnouncements(String token, String sortBy, int startYear, int startMonth){ - Long userId = getUserIdFromToken(token); + public List getAnnouncements(Long userId, String sortBy, int startYear, int startMonth){ User user = userRepository.findById(userId).orElseThrow( () -> new CustomException(ErrorMessage.NOT_FOUND_USER_EXCEPTION) ); @@ -37,9 +36,4 @@ public List getAnnouncements(String token, String sortBy, int s }) .collect(Collectors.toList()); } - - private Long getUserIdFromToken(String token){ - //실제 토큰에서 userId를 가져오는 로직 구현 - return 1L; //임시로 사용자 ID 1로 반환 - } } diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index d07970b..12255e2 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -118,7 +118,7 @@ public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto req getInternshipAnnouncement(internshipAnnouncementId); scrapRepository.save(Scrap.create( - findUser(PrincipalHandler.getUserIdFromPrincipal()), + findUser(userId), getInternshipAnnouncement(internshipAnnouncementId), findColor(request.color()) )); diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index df28152..d592417 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -1,7 +1,7 @@ spring: datasource: driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://localhost:5432/terning55 + url: jdbc:postgresql://localhost:5432/terning username: ${USER_ID} password: ${USER_PW} From f32ba87fa46e43c151ec11a3dedd67b904318710 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 04:32:11 +0900 Subject: [PATCH 157/205] =?UTF-8?q?[=F0=9F=94=80merge/#55]=20.gitignore=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 713c174..29e7043 100644 --- a/.gitignore +++ b/.gitignore @@ -189,7 +189,7 @@ Temporary Items # application.yml #src/main/resources/application.yml -src/main/resources/application-dev.yml +#src/main/resources/application-dev.yml # Q-Class src/main/generated \ No newline at end of file From 3f7e0ce0711dfa0f006ebd108e6fa92ae8f6a4de Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 11:13:48 +0900 Subject: [PATCH 158/205] =?UTF-8?q?[=F0=9F=94=80merge/#55]=20valueConfig?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/config/ValueConfig.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/terning/terningserver/config/ValueConfig.java b/src/main/java/org/terning/terningserver/config/ValueConfig.java index 2ebce42..fa138b0 100644 --- a/src/main/java/org/terning/terningserver/config/ValueConfig.java +++ b/src/main/java/org/terning/terningserver/config/ValueConfig.java @@ -12,19 +12,19 @@ @Getter public class ValueConfig { - @Value("${SECRET_KEY}") + @Value("${jwt.secret-key}") private String secretKey; - @Value("${KAKAO_URL}") + @Value("${jwt.kakao-url}") private String kakaoUri; - @Value("${APPLE_URL}") + @Value("${jwt.apple-url}") private String appleUri; - @Value("${ACCESS_TOKEN_EXPIRED}") + @Value("${jwt.access-token-expired}") private Long accessTokenExpired; - @Value("${REFRESH_TOKEN_EXPIRED}") + @Value("${jwt.refresh-token-expired}") private Long refreshTokenExpired; public static final String IOS_FORCE_UPDATE_VERSION = "0.0.9"; From 63f02fd256e94ac9aa599960a223a53f9a9090a0 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 12:19:34 +0900 Subject: [PATCH 159/205] =?UTF-8?q?[=F0=9F=94=80fix/#62]=20application.yml?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +-- src/main/resources/application-dev.yml | 49 -------------------------- src/main/resources/application.yml | 4 --- 3 files changed, 2 insertions(+), 55 deletions(-) delete mode 100644 src/main/resources/application-dev.yml delete mode 100644 src/main/resources/application.yml diff --git a/.gitignore b/.gitignore index 99bdb2d..4f5aa4a 100644 --- a/.gitignore +++ b/.gitignore @@ -188,8 +188,8 @@ Temporary Items .apdisk # application.yml -#src/main/resources/application.yml -#src/main/resources/application-dev.yml +src/main/resources/application.yml +src/main/resources/application-dev.yml # Q-Class src/main/generated diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml deleted file mode 100644 index d592417..0000000 --- a/src/main/resources/application-dev.yml +++ /dev/null @@ -1,49 +0,0 @@ -spring: - datasource: - driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://localhost:5432/terning - username: ${USER_ID} - password: ${USER_PW} - - hikari: - maximum-pool-size: 10 - minimum-idle: 10 - connection-timeout: 5000 # 5 seconds - validation-timeout: 2000 # 2 seconds - idle-timeout: 600000 # 10 minutes - max-lifetime: 1800000 # 30 minutes - - # 로그 관련 설정 - data-source-properties: - dataSource.logWriter: # 로그 작성 구현체 지정 - dataSource.logUnclosedConnections: false # 사용하지 않은 커넥션의 로깅 여부 지정 - - # 모니터링 관련 설정 - metrics: - enabled: true # HikariCP 메트릭스 활성화 - export: - reporter: - - prometheus # 사용할 메트릭스 리포터 설정 - prometheus: - enabled: true # Prometheus 메트릭스 리포터 활성화 여부 - step: 60s # 측정 간격 - - jpa: - show-sql: true - hibernate: - ddl-auto: update - properties: - hibernate: - format_sql: true - show_sql: true - -jwt: - secret-key: ${SECRET_KEY} - apple-url: ${APPLE_URL} - kakao-url: ${KAKAO_URL} - access-token-expired: ${ACCESS_TOKEN_EXPIRED} - refresh-token-expired: ${REFRESH_TOKEN_EXPIRED} - -logging: - level: - com.zaxxer.hikari: INFO diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml deleted file mode 100644 index 41ba440..0000000 --- a/src/main/resources/application.yml +++ /dev/null @@ -1,4 +0,0 @@ -spring: - profiles: - active: - - dev \ No newline at end of file From bc7f424e4d0bdf5b2ae79f42988df2d2f4b04223 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 13:47:35 +0900 Subject: [PATCH 160/205] Update SecurityConfig.java --- .../java/org/terning/terningserver/config/SecurityConfig.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/config/SecurityConfig.java b/src/main/java/org/terning/terningserver/config/SecurityConfig.java index 6f3107c..7806050 100644 --- a/src/main/java/org/terning/terningserver/config/SecurityConfig.java +++ b/src/main/java/org/terning/terningserver/config/SecurityConfig.java @@ -27,7 +27,8 @@ public class SecurityConfig { "/api/v1/swagger-ui/index.html#/**", "/swagger-resources/**", "/swagger-ui/**", - "/api/v1/auth/**" + "/api/v1/auth/**", + "/actuator/health" }; @Bean From cc4e507104f304fce04b6f0bbe3f90535e2d68ca Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 15:08:50 +0900 Subject: [PATCH 161/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terning/terningserver/config/WebConfig.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/org/terning/terningserver/config/WebConfig.java diff --git a/src/main/java/org/terning/terningserver/config/WebConfig.java b/src/main/java/org/terning/terningserver/config/WebConfig.java new file mode 100644 index 0000000..7760cb5 --- /dev/null +++ b/src/main/java/org/terning/terningserver/config/WebConfig.java @@ -0,0 +1,17 @@ +package org.terning.terningserver.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry){ + registry.addMapping("/**") + .allowedOrigins("http://www.terning-official.p-e.kr") + .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD") + .allowCredentials(true); + } +} From 781fb180782b5c4d509cb02e9aa226d03c0b8f76 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 15:15:27 +0900 Subject: [PATCH 162/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/terning/terningserver/config/WebConfig.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/config/WebConfig.java b/src/main/java/org/terning/terningserver/config/WebConfig.java index 7760cb5..43a844a 100644 --- a/src/main/java/org/terning/terningserver/config/WebConfig.java +++ b/src/main/java/org/terning/terningserver/config/WebConfig.java @@ -10,8 +10,9 @@ public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry){ registry.addMapping("/**") - .allowedOrigins("http://www.terning-official.p-e.kr") + .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD") - .allowCredentials(true); + .allowedHeaders("*") + .allowCredentials(false); } } From 502f744576fe96b226650589056cdd4e3719c68d Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 15:23:24 +0900 Subject: [PATCH 163/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/terning/terningserver/config/SecurityConfig.java | 1 + src/main/java/org/terning/terningserver/config/WebConfig.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/config/SecurityConfig.java b/src/main/java/org/terning/terningserver/config/SecurityConfig.java index 7806050..265a0c7 100644 --- a/src/main/java/org/terning/terningserver/config/SecurityConfig.java +++ b/src/main/java/org/terning/terningserver/config/SecurityConfig.java @@ -22,6 +22,7 @@ public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; private final CustomJwtAuthenticationEntryPoint customJwtAuthenticationEntryPoint; private static final String[] AUTH_WHITELIST = { + "/**", "/v3/api-docs/**", "/swagger-ui.html", "/api/v1/swagger-ui/index.html#/**", diff --git a/src/main/java/org/terning/terningserver/config/WebConfig.java b/src/main/java/org/terning/terningserver/config/WebConfig.java index 43a844a..de85275 100644 --- a/src/main/java/org/terning/terningserver/config/WebConfig.java +++ b/src/main/java/org/terning/terningserver/config/WebConfig.java @@ -13,6 +13,6 @@ public void addCorsMappings(CorsRegistry registry){ .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD") .allowedHeaders("*") - .allowCredentials(false); + .allowCredentials(true); } } From cc627ba1bc789253de6a6ee8f84d83107df45f6f Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 15:26:41 +0900 Subject: [PATCH 164/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/terning/terningserver/config/WebConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/config/WebConfig.java b/src/main/java/org/terning/terningserver/config/WebConfig.java index de85275..43a844a 100644 --- a/src/main/java/org/terning/terningserver/config/WebConfig.java +++ b/src/main/java/org/terning/terningserver/config/WebConfig.java @@ -13,6 +13,6 @@ public void addCorsMappings(CorsRegistry registry){ .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD") .allowedHeaders("*") - .allowCredentials(true); + .allowCredentials(false); } } From 0ed381d8d025dffde22ae594bdf87a140d9bc287 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 15:37:37 +0900 Subject: [PATCH 165/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/config/SecurityConfig.java | 5 ++-- .../terningserver/config/WebConfig.java | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/terning/terningserver/config/SecurityConfig.java b/src/main/java/org/terning/terningserver/config/SecurityConfig.java index 265a0c7..3f02bbb 100644 --- a/src/main/java/org/terning/terningserver/config/SecurityConfig.java +++ b/src/main/java/org/terning/terningserver/config/SecurityConfig.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; @@ -22,7 +23,6 @@ public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; private final CustomJwtAuthenticationEntryPoint customJwtAuthenticationEntryPoint; private static final String[] AUTH_WHITELIST = { - "/**", "/v3/api-docs/**", "/swagger-ui.html", "/api/v1/swagger-ui/index.html#/**", @@ -35,6 +35,7 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http + .cors(Customizer.withDefaults()) .csrf(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable) .sessionManagement(sessionManagement -> @@ -49,6 +50,4 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .build(); } - - } diff --git a/src/main/java/org/terning/terningserver/config/WebConfig.java b/src/main/java/org/terning/terningserver/config/WebConfig.java index 43a844a..95ffcf8 100644 --- a/src/main/java/org/terning/terningserver/config/WebConfig.java +++ b/src/main/java/org/terning/terningserver/config/WebConfig.java @@ -1,18 +1,26 @@ package org.terning.terningserver.config; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration -public class WebConfig implements WebMvcConfigurer { +public class WebConfig { - @Override - public void addCorsMappings(CorsRegistry registry){ - registry.addMapping("/**") - .allowedOrigins("*") - .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD") - .allowedHeaders("*") - .allowCredentials(false); + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.addAllowedOriginPattern("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + config.setAllowCredentials(false); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); } } +//Spring Security 6.1 이상에서는 CORS 설정을 HttpSecurity에 직접 추가하지 않고, 별도의 CorsConfigurationSource Bean을 등록하여 설정 \ No newline at end of file From c1b57dfa462521d2ce55fd61ef1490cc4a72fe21 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 15:48:31 +0900 Subject: [PATCH 166/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/config/SecurityConfig.java | 1 - .../terningserver/config/WebConfig.java | 26 ------------------- .../terningserver/config/WebMvcConfig.java | 18 +++++++++++++ 3 files changed, 18 insertions(+), 27 deletions(-) delete mode 100644 src/main/java/org/terning/terningserver/config/WebConfig.java create mode 100644 src/main/java/org/terning/terningserver/config/WebMvcConfig.java diff --git a/src/main/java/org/terning/terningserver/config/SecurityConfig.java b/src/main/java/org/terning/terningserver/config/SecurityConfig.java index 3f02bbb..95c0635 100644 --- a/src/main/java/org/terning/terningserver/config/SecurityConfig.java +++ b/src/main/java/org/terning/terningserver/config/SecurityConfig.java @@ -35,7 +35,6 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http - .cors(Customizer.withDefaults()) .csrf(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable) .sessionManagement(sessionManagement -> diff --git a/src/main/java/org/terning/terningserver/config/WebConfig.java b/src/main/java/org/terning/terningserver/config/WebConfig.java deleted file mode 100644 index 95ffcf8..0000000 --- a/src/main/java/org/terning/terningserver/config/WebConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.terning.terningserver.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -public class WebConfig { - - @Bean - public CorsFilter corsFilter() { - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - CorsConfiguration config = new CorsConfiguration(); - config.addAllowedOriginPattern("*"); - config.addAllowedHeader("*"); - config.addAllowedMethod("*"); - config.setAllowCredentials(false); - source.registerCorsConfiguration("/**", config); - return new CorsFilter(source); - } -} -//Spring Security 6.1 이상에서는 CORS 설정을 HttpSecurity에 직접 추가하지 않고, 별도의 CorsConfigurationSource Bean을 등록하여 설정 \ No newline at end of file diff --git a/src/main/java/org/terning/terningserver/config/WebMvcConfig.java b/src/main/java/org/terning/terningserver/config/WebMvcConfig.java new file mode 100644 index 0000000..0aeec2b --- /dev/null +++ b/src/main/java/org/terning/terningserver/config/WebMvcConfig.java @@ -0,0 +1,18 @@ +package org.terning.terningserver.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@EnableWebMvc +public class WebMvcConfig implements WebMvcConfigurer { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOriginPatterns("*") // 허용할 출처 : 특정 도메인만 받을 수 있음 + .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH") // 허용할 HTTP method + .allowCredentials(true); // 쿠키 인증 요청 허용 + } +} \ No newline at end of file From 93b7372a8c3b3534c2761619aec3ace86cb0756a Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 16:04:50 +0900 Subject: [PATCH 167/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/terning/terningserver/config/WebMvcConfig.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/terning/terningserver/config/WebMvcConfig.java b/src/main/java/org/terning/terningserver/config/WebMvcConfig.java index 0aeec2b..80d6e5f 100644 --- a/src/main/java/org/terning/terningserver/config/WebMvcConfig.java +++ b/src/main/java/org/terning/terningserver/config/WebMvcConfig.java @@ -2,16 +2,14 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration -@EnableWebMvc public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") - .allowedOriginPatterns("*") // 허용할 출처 : 특정 도메인만 받을 수 있음 + .allowedOrigins("http://localhost:8080", "http://localhost:3000", "http://terning-official.p-e.kr") // 허용할 출처 : 특정 도메인만 받을 수 있음 .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH") // 허용할 HTTP method .allowCredentials(true); // 쿠키 인증 요청 허용 } From 66afccfd26baf63d412747c81319f68570e15a99 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 16:10:41 +0900 Subject: [PATCH 168/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/controller/AuthController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index 1d54404..6c2b3f6 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -28,6 +28,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/auth") +@CrossOrigin(origins = "http://terning-official.p-e.kr") public class AuthController implements AuthSwagger { private final AuthService authService; From d217dec973882747946da9035b0ab96f8b49fdce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 17 Jul 2024 17:28:23 +0900 Subject: [PATCH 169/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#develop]=20CORS?= =?UTF-8?q?=20=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Terning | 1 - .../org/terning/terningserver/config/SwaggerConfig.java | 7 +++++++ .../org/terning/terningserver/config/WebMvcConfig.java | 6 ++++-- 3 files changed, 11 insertions(+), 3 deletions(-) delete mode 160000 Terning diff --git a/Terning b/Terning deleted file mode 160000 index e53017f..0000000 --- a/Terning +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e53017fc3ff5bbab45222818feb966ca912c1917 diff --git a/src/main/java/org/terning/terningserver/config/SwaggerConfig.java b/src/main/java/org/terning/terningserver/config/SwaggerConfig.java index 9ec4e6a..043f701 100644 --- a/src/main/java/org/terning/terningserver/config/SwaggerConfig.java +++ b/src/main/java/org/terning/terningserver/config/SwaggerConfig.java @@ -1,5 +1,7 @@ package org.terning.terningserver.config; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.servers.Server; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; @@ -9,6 +11,11 @@ import org.springframework.context.annotation.Configuration; @Configuration +@OpenAPIDefinition( + servers = { + @Server(url = "/", description = "Default Server url") + } +) public class SwaggerConfig { @Bean public OpenAPI openAPI() { diff --git a/src/main/java/org/terning/terningserver/config/WebMvcConfig.java b/src/main/java/org/terning/terningserver/config/WebMvcConfig.java index 80d6e5f..0ed35f2 100644 --- a/src/main/java/org/terning/terningserver/config/WebMvcConfig.java +++ b/src/main/java/org/terning/terningserver/config/WebMvcConfig.java @@ -5,12 +5,14 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration + public class WebMvcConfig implements WebMvcConfigurer { + @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") - .allowedOrigins("http://localhost:8080", "http://localhost:3000", "http://terning-official.p-e.kr") // 허용할 출처 : 특정 도메인만 받을 수 있음 + .allowedOrigins("http://localhost:8080", "http://localhost:3000", "http://terning-official.p-e.kr","http://localhost:5173") // 허용할 출처 : 특정 도메인만 받을 수 있음 .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH") // 허용할 HTTP method .allowCredentials(true); // 쿠키 인증 요청 허용 } -} \ No newline at end of file +} From a511656c5e9b260384b48b78c450ed854b8cbfe5 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 23:26:02 +0900 Subject: [PATCH 170/205] Update AuthController.java --- .../org/terning/terningserver/controller/AuthController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index 6c2b3f6..1d54404 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -28,7 +28,6 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/auth") -@CrossOrigin(origins = "http://terning-official.p-e.kr") public class AuthController implements AuthSwagger { private final AuthService authService; From 9ca05e786bab9c292302760a3f142c3daafb2d60 Mon Sep 17 00:00:00 2001 From: Willy Date: Wed, 17 Jul 2024 23:59:22 +0900 Subject: [PATCH 171/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/terning/terningserver/domain/enums/AuthType.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/terning/terningserver/domain/enums/AuthType.java b/src/main/java/org/terning/terningserver/domain/enums/AuthType.java index d565eb6..51fe075 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/AuthType.java +++ b/src/main/java/org/terning/terningserver/domain/enums/AuthType.java @@ -2,4 +2,5 @@ public enum AuthType { KAKAO, APPLE + } From 56a1582ffbcfa241a3bdbcc29e3e7c3222acd58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 01:25:26 +0900 Subject: [PATCH 172/205] =?UTF-8?q?[=E2=9C=A8feat/#68]:=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=20&=20=ED=95=84=ED=84=B0=EB=A7=81=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=20=EC=A0=95=EB=B3=B4=20=EA=B0=80=EC=A0=B8?= =?UTF-8?q?=EC=98=A4=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FilterController.java | 6 ++++-- .../controller/ScrapController.java | 9 +++++---- .../controller/swagger/ScrapSwagger.java | 2 +- .../filter/response/UserFilterResponseDto.java | 16 ++++++++-------- .../terningserver/jwt/PrincipalHandler.java | 17 ++++++++++++----- .../terningserver/service/FilterService.java | 4 ++-- .../service/FilterServiceImpl.java | 8 ++++---- .../terningserver/service/ScrapService.java | 4 ++-- .../terningserver/service/ScrapServiceImpl.java | 13 +++++++------ 9 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/FilterController.java b/src/main/java/org/terning/terningserver/controller/FilterController.java index 739fe64..02ea027 100644 --- a/src/main/java/org/terning/terningserver/controller/FilterController.java +++ b/src/main/java/org/terning/terningserver/controller/FilterController.java @@ -8,6 +8,7 @@ import org.terning.terningserver.dto.filter.request.UserFilterRequestDto; import org.terning.terningserver.dto.filter.response.UserFilterResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.jwt.PrincipalHandler; import org.terning.terningserver.service.FilterService; import static org.terning.terningserver.exception.enums.SuccessMessage.*; @@ -18,6 +19,7 @@ public class FilterController implements FilterSwagger { private final FilterService filterService; + private final PrincipalHandler principalHandler; @GetMapping("/filters") public ResponseEntity> getUserFilter( @@ -25,7 +27,7 @@ public ResponseEntity> getUserFilter( ) { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_USER_FILTER, - filterService.getUserFilter() + filterService.getUserFilter(principalHandler.getUserFromPrincipal()) )); } @@ -33,7 +35,7 @@ public ResponseEntity> getUserFilter( public ResponseEntity updateUserFilter( @AuthenticationPrincipal Long userId, @RequestBody UserFilterRequestDto requestDto) { - filterService.updateUserFilter(requestDto); + filterService.updateUserFilter(requestDto, principalHandler.getUserFromPrincipal()); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_SCRAP)); } diff --git a/src/main/java/org/terning/terningserver/controller/ScrapController.java b/src/main/java/org/terning/terningserver/controller/ScrapController.java index 9ef27c9..878eb99 100644 --- a/src/main/java/org/terning/terningserver/controller/ScrapController.java +++ b/src/main/java/org/terning/terningserver/controller/ScrapController.java @@ -17,26 +17,27 @@ @RequiredArgsConstructor @RequestMapping("/api/v1") public class ScrapController implements ScrapSwagger { + private final ScrapService scrapService; + private final PrincipalHandler principalHandler; @PostMapping("/scraps/{internshipAnnouncementId}") public ResponseEntity createScrap( - @AuthenticationPrincipal Long userId, @PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request) { - scrapService.createScrap(internshipAnnouncementId, request, userId); + scrapService.createScrap(internshipAnnouncementId, request, principalHandler.getUserFromPrincipal()); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_CREATE_SCRAP)); } @DeleteMapping("/scraps/{scrapId}") public ResponseEntity deleteScrap(@PathVariable Long scrapId) { - scrapService.deleteScrap(scrapId); + scrapService.deleteScrap(scrapId, principalHandler.getUserFromPrincipal()); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_DELETE_SCRAP)); } @PatchMapping("/scraps/{scrapId}") public ResponseEntity updateScrapColor(@PathVariable Long scrapId, @RequestBody UpdateScrapRequestDto request) { - scrapService.updateScrapColor(scrapId, request); + scrapService.updateScrapColor(scrapId, request, principalHandler.getUserFromPrincipal()); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_SCRAP)); } } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java index 180f99e..5ddab57 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java @@ -15,7 +15,7 @@ public interface ScrapSwagger { @Operation(summary = "스크랩 추가", description = "사용자가 스크랩을 추가하는 API") ResponseEntity createScrap( - @AuthenticationPrincipal Long userId, @PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request + @PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request ); @Operation(summary = "스크랩 취소", description = "사용자가 스크랩을 취소하는 API") diff --git a/src/main/java/org/terning/terningserver/dto/filter/response/UserFilterResponseDto.java b/src/main/java/org/terning/terningserver/dto/filter/response/UserFilterResponseDto.java index 67c833c..cf28909 100644 --- a/src/main/java/org/terning/terningserver/dto/filter/response/UserFilterResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/filter/response/UserFilterResponseDto.java @@ -5,17 +5,17 @@ @Builder public record UserFilterResponseDto( - int grade, - int workingPeriod, - int startYear, - int startMonth + Integer grade, + Integer workingPeriod, + Integer startYear, + Integer startMonth ) { public static UserFilterResponseDto of(Filter userFilter) { return UserFilterResponseDto.builder() - .grade(userFilter.getGrade().getKey()) - .workingPeriod(userFilter.getWorkingPeriod().getKey()) - .startYear(userFilter.getStartYear()) - .startMonth(userFilter.getStartMonth()) + .grade(userFilter == null ? null : userFilter.getGrade().getKey()) + .workingPeriod(userFilter == null ? null : userFilter.getWorkingPeriod().getKey()) + .startYear(userFilter == null ? null : userFilter.getStartYear()) + .startMonth(userFilter == null ? null : userFilter.getStartMonth()) .build(); } } diff --git a/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java b/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java index 78c3879..6bdc593 100644 --- a/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java +++ b/src/main/java/org/terning/terningserver/jwt/PrincipalHandler.java @@ -1,22 +1,29 @@ package org.terning.terningserver.jwt; +import lombok.RequiredArgsConstructor; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.exception.enums.ErrorMessage; +import org.terning.terningserver.repository.user.UserRepository; +import static org.terning.terningserver.exception.enums.ErrorMessage.INVALID_USER; import static org.terning.terningserver.exception.enums.ErrorMessage.UNAUTHORIZED_JWT_EXCEPTION; @Component +@RequiredArgsConstructor public class PrincipalHandler { - private static final String ANONYMOUS_USER = "anonymousUser"; - public static Long getUserIdFromPrincipal() { + private final UserRepository userRepository; + private final String ANONYMOUS_USER = "anonymousUser"; + + public Long getUserFromPrincipal() { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - isPrincipalNull(principal); - return Long.valueOf(principal.toString()); + return userRepository.findByAuthId(principal.toString()) + .orElseThrow(() -> new CustomException(INVALID_USER)).getId(); } - public static void isPrincipalNull( + public void isPrincipalNull( final Object principal ) { if (principal.toString().equals(ANONYMOUS_USER)) { diff --git a/src/main/java/org/terning/terningserver/service/FilterService.java b/src/main/java/org/terning/terningserver/service/FilterService.java index 6b2b929..f05c4b2 100644 --- a/src/main/java/org/terning/terningserver/service/FilterService.java +++ b/src/main/java/org/terning/terningserver/service/FilterService.java @@ -5,7 +5,7 @@ public interface FilterService { - UserFilterResponseDto getUserFilter(); + UserFilterResponseDto getUserFilter(Long userId); - void updateUserFilter(UserFilterRequestDto responseDto); + void updateUserFilter(UserFilterRequestDto responseDto, Long userId); } diff --git a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java index a5bd831..9c1d025 100644 --- a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java @@ -23,14 +23,14 @@ public class FilterServiceImpl implements FilterService { private final UserRepository userRepository; @Override - public UserFilterResponseDto getUserFilter() { - return UserFilterResponseDto.of(findUser(6L).getFilter()); + public UserFilterResponseDto getUserFilter(Long userId) { + return UserFilterResponseDto.of(findUser(userId).getFilter()); } @Override @Transactional - public void updateUserFilter(UserFilterRequestDto responseDto) { - User user = findUser(6L); + public void updateUserFilter(UserFilterRequestDto responseDto, Long userId) { + User user = findUser(userId); Filter filter = user.getFilter(); filter.updateFilter( diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java index 7102daf..5d94bb5 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapService.java +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -15,9 +15,9 @@ public interface ScrapService { void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request, Long userId); - void deleteScrap(Long scrapId); + void deleteScrap(Long scrapId, Long userId); - void updateScrapColor(Long scrapId, UpdateScrapRequestDto request); + void updateScrapColor(Long scrapId, UpdateScrapRequestDto request, Long userId); List getMonthlyScraps(Long userId, int year, int month); diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 12255e2..69118d0 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -115,6 +115,7 @@ public List getDailyScraps(Long userId, LocalDate date) { @Override @Transactional public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request, Long userId) { + getInternshipAnnouncement(internshipAnnouncementId); scrapRepository.save(Scrap.create( @@ -126,23 +127,23 @@ public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto req @Override @Transactional - public void deleteScrap(Long scrapId) { + public void deleteScrap(Long scrapId, Long userId) { Scrap scrap = findScrap(scrapId); - verifyScrapOwner(scrap); + verifyScrapOwner(scrap, userId); scrapRepository.deleteById(scrapId); } @Override @Transactional - public void updateScrapColor(Long scrapId, UpdateScrapRequestDto request) { + public void updateScrapColor(Long scrapId, UpdateScrapRequestDto request, Long userId) { Scrap scrap = findScrap(scrapId); - verifyScrapOwner(scrap); + verifyScrapOwner(scrap, userId); scrap.updateColor(findColor(request.color())); } //토큰으로 찾은(요청한) User와 스크랩한 User가 일치한지 여부 검증하는 메서드 - private void verifyScrapOwner(Scrap scrap) { - if(!scrap.getUser().equals(findUser(1L))) { + private void verifyScrapOwner(Scrap scrap, Long userId) { + if(!scrap.getUser().equals(findUser(userId))) { throw new CustomException(FORBIDDEN_DELETE_SCRAP); } } From 5810e512073d6c35584d74200c7ebce3f898b00e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 01:30:38 +0900 Subject: [PATCH 173/205] =?UTF-8?q?[=F0=9F=94=A8fix/#68]:=20=ED=83=90?= =?UTF-8?q?=EC=83=89=20=EB=B0=8F=20=EA=B3=B5=EA=B3=A0=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 탐색 > 조회수 및 스크랩 수 많은 공고 5개만 보내주도록 수정 - 공고 상세페이지 요청시 조회수 +1 되도록 로직 수정 --- .../terning/terningserver/domain/InternshipAnnouncement.java | 4 ++++ .../internship_announcement/InternshipRepositoryImpl.java | 2 ++ .../terningserver/service/InternshipDetailServiceImpl.java | 1 + 3 files changed, 7 insertions(+) diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java index 204657e..d853b25 100644 --- a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -68,4 +68,8 @@ public class InternshipAnnouncement extends BaseTimeEntity { @OneToMany(mappedBy = "internshipAnnouncement", cascade = CascadeType.ALL) private List scrapList = new ArrayList<>(); //스크랩 리스트 + + public void updateViewCount() { + this.viewCount += 1; + } } diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index 1c62f12..c486547 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -37,6 +37,7 @@ public List getMostViewedInternship() { internCreatedAtAfter() ) //지원 마감된 공고 및 30일 보다 오래된 공고 제외 .orderBy(internshipAnnouncement.viewCount.desc(), internshipAnnouncement.createdAt.desc()) + .limit(5) .fetch(); } @@ -49,6 +50,7 @@ public List getMostScrappedInternship() { internCreatedAtAfter() ) //지원 마감된 공고 및 30일 보다 오래된 공고 제외 .orderBy(internshipAnnouncement.scrapCount.desc(), internshipAnnouncement.createdAt.desc()) + .limit(5) .fetch(); } diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java b/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java index cd862a5..84f2549 100644 --- a/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java @@ -23,6 +23,7 @@ public InternshipDetailResponseDto getInternshipDetail(Long internshipAnnounceme InternshipAnnouncement announcement = internshipRepository.findById(internshipAnnouncementId) .orElseThrow(() -> new CustomException(ErrorMessage.NOT_FOUND_INTERN_EXCEPTION)); + announcement.updateViewCount(); return InternshipDetailResponseDto.of( announcement, announcement.getCompany(), From e03226bf56b5401dcca77bf80867249fad8ad55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 03:03:56 +0900 Subject: [PATCH 174/205] =?UTF-8?q?[=F0=9F=94=A8fix/#70]:=20=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20=EC=83=81=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EC=88=98=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95,=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20=EC=B6=94=EA=B0=80/?= =?UTF-8?q?=EC=B7=A8=EC=86=8C=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 공고 상세페이지 조회 시마다 조회수 +1 증가하도록 수정 - 스크랩 추가/취소 시 scrapCount 변경되도록 로직 추가 --- .../terningserver/domain/InternshipAnnouncement.java | 4 ++++ .../InternshipRepositoryImpl.java | 1 - .../service/InternshipDetailServiceImpl.java | 2 +- .../terning/terningserver/service/ScrapServiceImpl.java | 9 ++++++++- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java index d853b25..361dd2b 100644 --- a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -72,4 +72,8 @@ public class InternshipAnnouncement extends BaseTimeEntity { public void updateViewCount() { this.viewCount += 1; } + + public void updateScrapCount(int plusOrMinus) { + this.scrapCount = scrapCount + plusOrMinus; + } } diff --git a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java index c486547..bbf9832 100644 --- a/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/internship_announcement/InternshipRepositoryImpl.java @@ -136,7 +136,6 @@ private BooleanExpression getStartDateFilter(int startYear, int startMonth){ // 정렬 옵션 (5가지) private OrderSpecifier getSortOrder(String sortBy) { - System.out.println("sortBy = " + sortBy); return switch (sortBy) { case "shortestDuration" // 짧은 근무 기간 순 -> getWorkingPeriodAsNumber().asc(); diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java b/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java index 84f2549..5a2871b 100644 --- a/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java @@ -13,12 +13,12 @@ @Service @RequiredArgsConstructor -@Transactional(readOnly = true) public class InternshipDetailServiceImpl implements InternshipDetailService { private final InternshipRepository internshipRepository; private final ScrapRepository scrapRepository; @Override + @Transactional public InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId) { InternshipAnnouncement announcement = internshipRepository.findById(internshipAnnouncementId) .orElseThrow(() -> new CustomException(ErrorMessage.NOT_FOUND_INTERN_EXCEPTION)); diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 69118d0..7f0683f 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -116,7 +116,10 @@ public List getDailyScraps(Long userId, LocalDate date) { @Transactional public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request, Long userId) { - getInternshipAnnouncement(internshipAnnouncementId); + InternshipAnnouncement announcement = getInternshipAnnouncement(internshipAnnouncementId); + + //스크랩 수 +1 + announcement.updateScrapCount(1); scrapRepository.save(Scrap.create( findUser(userId), @@ -129,6 +132,10 @@ public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto req @Transactional public void deleteScrap(Long scrapId, Long userId) { Scrap scrap = findScrap(scrapId); + + //스크랩 수 -1 + scrap.getInternshipAnnouncement().updateScrapCount(-1); + verifyScrapOwner(scrap, userId); scrapRepository.deleteById(scrapId); } From a8e2df0cf7460843c4ddb425cb29f0806a16a9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 03:25:54 +0900 Subject: [PATCH 175/205] =?UTF-8?q?[=F0=9F=94=A8=20fix/#70]:=20reissue=20?= =?UTF-8?q?=EC=8B=9C=EC=97=90=20dto=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dto명을 accessToken에서 refreshToken으로 변경 --- Terning | 1 + .../terningserver/dto/auth/response/TokenGetResponseDto.java | 3 ++- .../org/terning/terningserver/service/AuthServiceImpl.java | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) create mode 160000 Terning diff --git a/Terning b/Terning new file mode 160000 index 0000000..e53017f --- /dev/null +++ b/Terning @@ -0,0 +1 @@ +Subproject commit e53017fc3ff5bbab45222818feb966ca912c1917 diff --git a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java index e7148df..1974b3a 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java @@ -6,7 +6,8 @@ import static lombok.AccessLevel.*; @Builder(access = PRIVATE) -public record TokenGetResponseDto(@NonNull String accessToken +public record TokenGetResponseDto( + String accessToken ) { public static TokenGetResponseDto of(String accessToken) { diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index bf38643..ee43c53 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -87,6 +87,7 @@ public TokenGetResponseDto reissueToken(String refreshToken) { .orElseThrow(() -> new CustomException(FAILED_TOKEN_REISSUE)); return TokenGetResponseDto.of(token); } + private User getUser(String refreshToken, AuthType authType) { User user = userRepository.findByAuthTypeAndRefreshToken(authType, refreshToken) .orElseThrow(() -> new CustomException(INVALID_USER)); From 4edf5deadf7a90024f586d75508c58cc4c2c68a3 Mon Sep 17 00:00:00 2001 From: Willy Date: Thu, 18 Jul 2024 03:37:05 +0900 Subject: [PATCH 176/205] =?UTF-8?q?[=E2=9C=A8fix/#66]=20=EC=BA=98=EB=A6=B0?= =?UTF-8?q?=EB=8D=94=20=EA=B4=80=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20&=20?= =?UTF-8?q?=ED=99=88=ED=99=94=EB=A9=B4=20>=20=EB=A7=9E=EC=B6=A4=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20=EC=B6=94=EA=B0=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/auth/request/SignUpFilterRequestDto.java | 8 ++++---- .../dto/auth/request/SignUpRequestDto.java | 2 +- .../dto/user/response/HomeResponseDto.java | 4 +++- .../repository/scrap/ScrapRepositoryCustom.java | 1 + .../repository/scrap/ScrapRepositoryImpl.java | 10 ++++++++++ .../terning/terningserver/service/HomeServiceImpl.java | 6 ++++-- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java index 484869c..983f27a 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpFilterRequestDto.java @@ -7,10 +7,10 @@ @Builder(access = PRIVATE) public record SignUpFilterRequestDto( - @NonNull int grade, - @NonNull int workingPeriod, - @NonNull int startYear, - @NonNull int startMonth + int grade, + int workingPeriod, + int startYear, + int startMonth ) { public static SignUpFilterRequestDto of(int grade, int workingPeriod, int startYear, int startMonth) { diff --git a/src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java index 5e69811..b010b96 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/request/SignUpRequestDto.java @@ -9,7 +9,7 @@ @Builder(access = PRIVATE) public record SignUpRequestDto( @NonNull String name, - @NonNull int profileImage, + int profileImage, @NonNull AuthType authType ) { diff --git a/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java b/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java index a38a182..71c7fff 100644 --- a/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java @@ -6,6 +6,7 @@ @Builder public record HomeResponseDto( + Long scrapId, Long intershipAnnouncementId, String title, String dDay, @@ -13,10 +14,11 @@ public record HomeResponseDto( String companyImage, boolean isScrapped ) { - public static HomeResponseDto of(final InternshipAnnouncement internshipAnnouncement, final boolean isScrapped){ + public static HomeResponseDto of(final Long scrapId, final InternshipAnnouncement internshipAnnouncement, final boolean isScrapped){ String dDay = DateUtil.convert(internshipAnnouncement.getDeadline()); // dDay 계산 로직 추가 return HomeResponseDto.builder() + .scrapId(scrapId) .intershipAnnouncementId(internshipAnnouncement.getId()) .title(internshipAnnouncement.getTitle()) .dDay(dDay) diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryCustom.java index 38a0112..2c1ae93 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryCustom.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryCustom.java @@ -6,6 +6,7 @@ import java.util.List; public interface ScrapRepositoryCustom { + Long findScrapIdByInternshipAnnouncementIdAndUserId(Long internshipAnnouncementId, Long userId); List findAllByInternshipAndUserId(List internshipAnnouncements, Long userId); diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryImpl.java index d53b08c..cacfe74 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryImpl.java @@ -22,4 +22,14 @@ public List findAllByInternshipAndUserId(List int .where(scrap.internshipAnnouncement.in(internshipAnnouncements), scrap.user.id.eq(userId)) .fetch(); } + + @Override + public Long findScrapIdByInternshipAnnouncementIdAndUserId(Long internshipAnnouncementId, Long userId) { + return jpaQueryFactory + .select(scrap.id) + .from(scrap) + .where(scrap.internshipAnnouncement.id.eq(internshipAnnouncementId) + .and(scrap.user.id.eq(userId))) + .fetchOne(); + } } diff --git a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java index 9fab987..8e84aad 100644 --- a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.Scrap; import org.terning.terningserver.domain.User; import org.terning.terningserver.dto.user.response.HomeResponseDto; import org.terning.terningserver.exception.CustomException; @@ -32,8 +33,9 @@ public List getAnnouncements(Long userId, String sortBy, int st return announcements.stream() .map(announcement -> { boolean isScrapped = scrapRepository.existsByInternshipAnnouncementIdAndUserId(announcement.getId(), userId); - return HomeResponseDto.of(announcement, isScrapped); + Long scrapId = isScrapped ? scrapRepository.findScrapIdByInternshipAnnouncementIdAndUserId(announcement.getId(), userId) : null; + return HomeResponseDto.of(scrapId, announcement, isScrapped); }) - .collect(Collectors.toList()); + .toList(); } } From 5a82aa9780e66e46654e466c99e0b80a10b11523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 03:45:53 +0900 Subject: [PATCH 177/205] =?UTF-8?q?[=F0=9F=94=A8fix/#70]:=20=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20=EC=83=81=EC=84=B8=20=EC=A0=95=EB=B3=B4=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20scrapId=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InternshipDetailController.java | 4 +++- .../InternshipDetailResponseDto.java | 7 +++--- .../repository/scrap/ScrapRepository.java | 3 ++- .../service/InternshipDetailService.java | 2 +- .../service/InternshipDetailServiceImpl.java | 22 ++++++++++++++----- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java index 3dd5455..99269d0 100644 --- a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java +++ b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java @@ -10,6 +10,7 @@ import org.terning.terningserver.controller.swagger.InternshipDetailSwagger; import org.terning.terningserver.dto.internship_detail.InternshipDetailResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; +import org.terning.terningserver.jwt.PrincipalHandler; import org.terning.terningserver.service.InternshipDetailService; import static org.terning.terningserver.exception.enums.SuccessMessage.SUCCESS_GET_INTERNSHIP_DETAIL; @@ -20,13 +21,14 @@ public class InternshipDetailController implements InternshipDetailSwagger { private final InternshipDetailService internshipDetailService; + private final PrincipalHandler principalHandler; @GetMapping("/announcements/{internshipAnnouncementId}") public ResponseEntity> getInternshipDetail( @PathVariable Long internshipAnnouncementId) { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_INTERNSHIP_DETAIL, - internshipDetailService.getInternshipDetail(internshipAnnouncementId) + internshipDetailService.getInternshipDetail(internshipAnnouncementId, principalHandler.getUserFromPrincipal()) )); } diff --git a/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java b/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java index 41d065b..3bbd388 100644 --- a/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java @@ -3,6 +3,7 @@ import lombok.Builder; import org.terning.terningserver.domain.Company; import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.Scrap; import org.terning.terningserver.util.DateUtil; @Builder @@ -21,9 +22,9 @@ public record InternshipDetailResponseDto( String jobType, String detail, String url, - boolean isScrapped + Long scrapId ) { - public static InternshipDetailResponseDto of(InternshipAnnouncement announcement, Company company, boolean isScrapped) { + public static InternshipDetailResponseDto of(InternshipAnnouncement announcement, Company company, Long scrapId) { return InternshipDetailResponseDto.builder() .dDay(DateUtil.convert(announcement.getDeadline())) .title(announcement.getTitle()) @@ -39,7 +40,7 @@ public static InternshipDetailResponseDto of(InternshipAnnouncement announcement .jobType(announcement.getJobType()) .detail(announcement.getDetail()) .url(announcement.getUrl()) - .isScrapped(isScrapped) + .scrapId(scrapId) .build(); } } diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java index 945b10d..11a5807 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java @@ -5,9 +5,10 @@ import java.time.LocalDate; import java.util.List; +import java.util.Optional; public interface ScrapRepository extends JpaRepository, ScrapRepositoryCustom { - Boolean existsByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); + Optional findByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); List findByUserIdAndInternshipAnnouncement_Deadline(Long userId, LocalDate deadline); diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java index 6382b79..0dac0fc 100644 --- a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java @@ -14,5 +14,5 @@ public interface InternshipDetailService { - InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId); + InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId, Long userId); } diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java b/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java index 5a2871b..6c05e2c 100644 --- a/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java @@ -4,12 +4,15 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.Scrap; import org.terning.terningserver.dto.internship_detail.InternshipDetailResponseDto; import org.terning.terningserver.exception.CustomException; import org.terning.terningserver.exception.enums.ErrorMessage; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import org.terning.terningserver.repository.scrap.ScrapRepository; +import java.util.Optional; + @Service @RequiredArgsConstructor @@ -19,15 +22,24 @@ public class InternshipDetailServiceImpl implements InternshipDetailService { @Override @Transactional - public InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId) { + public InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId, Long userId) { InternshipAnnouncement announcement = internshipRepository.findById(internshipAnnouncementId) .orElseThrow(() -> new CustomException(ErrorMessage.NOT_FOUND_INTERN_EXCEPTION)); + announcement.updateViewCount(); + Optional scrap = scrapRepository.findByInternshipAnnouncementIdAndUserId(announcement.getId(), userId); - return InternshipDetailResponseDto.of( - announcement, announcement.getCompany(), - scrapRepository.existsByInternshipAnnouncementIdAndUserId(announcement.getId(), 1L) - ); + if (scrap.isPresent()) { + return InternshipDetailResponseDto.of( + announcement, announcement.getCompany(), + scrapRepository.findByInternshipAnnouncementIdAndUserId(announcement.getId(), userId).get().getId() + ); + } else { + return InternshipDetailResponseDto.of( + announcement, announcement.getCompany(), + null + ); + } } } From a5b28cff4eefd087ce3a92e7f275c8d301d6e6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 03:49:55 +0900 Subject: [PATCH 178/205] =?UTF-8?q?[=F0=9F=94=A8fix]:=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terning/terningserver/repository/scrap/ScrapRepository.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java index 11a5807..67ed558 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java @@ -8,6 +8,8 @@ import java.util.Optional; public interface ScrapRepository extends JpaRepository, ScrapRepositoryCustom { + Boolean existsByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); + Optional findByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); List findByUserIdAndInternshipAnnouncement_Deadline(Long userId, LocalDate deadline); From c1fee2e562a8e88369b19823687c18ecdc2d4c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 03:55:06 +0900 Subject: [PATCH 179/205] =?UTF-8?q?[=F0=9F=94=A8fix#70]:=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88=20=EC=9E=AC=EB=B0=9C=EA=B8=89=20dto=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/auth/response/TokenGetResponseDto.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java index 1974b3a..ffb118f 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java @@ -7,12 +7,12 @@ @Builder(access = PRIVATE) public record TokenGetResponseDto( - String accessToken + String refreshToken ) { - public static TokenGetResponseDto of(String accessToken) { + public static TokenGetResponseDto of(String refreshToken) { return TokenGetResponseDto.builder() - .accessToken(accessToken) + .refreshToken(refreshToken) .build(); } } From 029fb58ce1242b635c7c412c1b58d376b296253c Mon Sep 17 00:00:00 2001 From: Willy Date: Thu, 18 Jul 2024 04:16:05 +0900 Subject: [PATCH 180/205] =?UTF-8?q?[=E2=9C=A8fix/#66]=20=EC=BA=98=EB=A6=B0?= =?UTF-8?q?=EB=8D=94=20=EA=B4=80=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20&=20?= =?UTF-8?q?=ED=99=88=ED=99=94=EB=A9=B4=20>=20=EB=A7=9E=EC=B6=A4=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=20=EC=B6=94=EA=B0=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scrap/ScrapRepositoryCustom.java | 5 +++++ .../repository/scrap/ScrapRepositoryImpl.java | 21 +++++++++++++++++++ .../service/ScrapServiceImpl.java | 8 ++++--- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryCustom.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryCustom.java index 2c1ae93..1d4d788 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryCustom.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryCustom.java @@ -3,6 +3,7 @@ import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.domain.Scrap; +import java.time.LocalDate; import java.util.List; public interface ScrapRepositoryCustom { @@ -10,4 +11,8 @@ public interface ScrapRepositoryCustom { List findAllByInternshipAndUserId(List internshipAnnouncements, Long userId); + List findScrapsByUserIdAndDeadlineBetweenOrderByDeadline(Long userId, LocalDate start, LocalDate end); + + List findScrapsByUserIdAndDeadlineOrderByDeadline(Long userId, LocalDate deadline); + } diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryImpl.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryImpl.java index cacfe74..274b656 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryImpl.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepositoryImpl.java @@ -5,6 +5,7 @@ import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.domain.Scrap; +import java.time.LocalDate; import java.util.List; import static org.terning.terningserver.domain.QScrap.scrap; @@ -32,4 +33,24 @@ public Long findScrapIdByInternshipAnnouncementIdAndUserId(Long internshipAnnoun .and(scrap.user.id.eq(userId))) .fetchOne(); } + + @Override + public List findScrapsByUserIdAndDeadlineBetweenOrderByDeadline(Long userId, LocalDate start, LocalDate end){ + return jpaQueryFactory + .selectFrom(scrap) + .where(scrap.user.id.eq(userId) + .and(scrap.internshipAnnouncement.deadline.between(start, end))) + .orderBy(scrap.internshipAnnouncement.deadline.asc()) + .fetch(); + } + + @Override + public List findScrapsByUserIdAndDeadlineOrderByDeadline(Long userId, LocalDate deadline){ + return jpaQueryFactory + .selectFrom(scrap) + .where(scrap.user.id.eq(userId) + .and(scrap.internshipAnnouncement.deadline.eq(deadline))) + .orderBy(scrap.internshipAnnouncement.deadline.asc()) + .fetch(); + } } diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 12255e2..4c07d5d 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -52,13 +52,14 @@ public List getMonthlyScraps(Long userId, int year, i LocalDate start = LocalDate.of(year, month, 1); LocalDate end = start.plusMonths(1).minusDays(1); - List scraps = scrapRepository.findByUserIdAndInternshipAnnouncement_DeadlineBetween(userId, start, end); + List scraps = scrapRepository.findScrapsByUserIdAndDeadlineBetweenOrderByDeadline(userId, start, end); //deadline 별로 그룹화 Map> scrapsByDeadline = scraps.stream() .collect(Collectors.groupingBy(s -> s.getInternshipAnnouncement().getDeadline())); return scrapsByDeadline.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) .map(entry -> MonthlyDefaultResponseDto.of( entry.getKey().toString(), entry.getValue().stream() @@ -79,13 +80,14 @@ public List getMonthlyScrapsAsList(Long userId, int year LocalDate start = LocalDate.of(year, month, 1); LocalDate end = start.plusMonths(1).minusDays(1); - List scraps = scrapRepository.findByUserIdAndInternshipAnnouncement_DeadlineBetween(userId, start, end); + List scraps = scrapRepository.findScrapsByUserIdAndDeadlineBetweenOrderByDeadline(userId, start, end); //deadline 별로 그룹화 Map> scrapsByDeadline = scraps.stream() .collect(Collectors.groupingBy(s -> s.getInternshipAnnouncement().getDeadline())); return scrapsByDeadline.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) .map(entry -> MonthlyListResponseDto.of( entry.getKey().toString(), entry.getValue().stream() @@ -107,7 +109,7 @@ public List getMonthlyScrapsAsList(Long userId, int year @Override public List getDailyScraps(Long userId, LocalDate date) { - return scrapRepository.findByUserIdAndInternshipAnnouncement_Deadline(userId, date).stream() + return scrapRepository.findScrapsByUserIdAndDeadlineOrderByDeadline(userId, date).stream() .map(DailyScrapResponseDto::of) .toList(); } From 0334b7298cfee2690c505bb5a657acfc3d50b4ed Mon Sep 17 00:00:00 2001 From: Willy Date: Thu, 18 Jul 2024 05:00:17 +0900 Subject: [PATCH 181/205] =?UTF-8?q?[=E2=9C=A8fix/#66]=20gitignore=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4f5aa4a..99bdb2d 100644 --- a/.gitignore +++ b/.gitignore @@ -188,8 +188,8 @@ Temporary Items .apdisk # application.yml -src/main/resources/application.yml -src/main/resources/application-dev.yml +#src/main/resources/application.yml +#src/main/resources/application-dev.yml # Q-Class src/main/generated From b462a7152de386d990b8afc5f15bdf47ade1b19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 18 Jul 2024 05:18:53 +0900 Subject: [PATCH 182/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8F=20refactor/#67]:=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=AC=EB=B0=B0=EC=B9=98=20=EB=B0=8F=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=ED=95=A0=EB=8B=B9=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 불필요한 임포트 제거 및 코드 구조 최적화. - JsonParser로 헤더의 kid와 alg 값 할당 순서가 잘못되어 있던 부분을 수정. - 기존 코드의 중복된 섹션을 재배치하여 가독성 향상. - 코드 내 예외 처리 로직 강화 및 에러 메시지 처리를 위한 열거형 상수 활용. --- .../service/AppleServiceImpl.java | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java b/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java index 53ac5fb..59f9c39 100644 --- a/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AppleServiceImpl.java @@ -1,15 +1,5 @@ package org.terning.terningserver.service; -import com.google.gson.*; -import io.jsonwebtoken.Jwts; -import lombok.RequiredArgsConstructor; -import lombok.val; -import org.springframework.http.HttpMethod; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.terning.terningserver.config.ValueConfig; -import org.terning.terningserver.exception.CustomException; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -24,6 +14,22 @@ import java.util.Base64; import java.util.Objects; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import io.jsonwebtoken.Jwts; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.terning.terningserver.config.ValueConfig; +import org.terning.terningserver.exception.CustomException; + import static org.terning.terningserver.exception.enums.ErrorMessage.INVALID_KEY; @Service @@ -94,15 +100,13 @@ private StringBuilder splitResponse(BufferedReader bufferedReader) { private PublicKey makePublicKey(String accessToken, JsonArray publicKeyList) { val decodeArray = accessToken.split(ValueConfig.TOKEN_VALUE_DELIMITER); val header = new String(Base64.getDecoder().decode(getTokenFromBearerString(decodeArray[0]))); + val kid = ((JsonObject) JsonParser.parseString(header)).get(ValueConfig.KID_HEADER_KEY); + val alg = ((JsonObject) JsonParser.parseString(header)).get(ValueConfig.ALG_HEADER_KEY); - val kid = ((JsonObject) JsonParser.parseString(header)).get(ValueConfig.ALG_HEADER_KEY); - val alg = ((JsonObject) JsonParser.parseString(header)).get(ValueConfig.KID_HEADER_KEY); val matchingPublicKey = findMatchingPublicKey(publicKeyList, kid, alg); - if (Objects.isNull(matchingPublicKey)) { throw new CustomException(INVALID_KEY); } - return getPublicKey(matchingPublicKey); } From 3c7855f1c721018af80f660e9ab6f1cf9816ff15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 18 Jul 2024 06:20:19 +0900 Subject: [PATCH 183/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8Frefactor/#76]:=20?= =?UTF-8?q?=ED=86=A0=ED=81=B0=20=EC=9E=AC=EB=B0=9C=EA=B8=89=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - reissueToken 메서드 내에서 토큰 재발급 로직을 개선하였습니다. findUser를 이용해 사용자를 찾고, generateRefreshToken으로부터 새로운 토큰을 생성하여 기존 토큰을 업데이트하는 과정에서 발생할 수 있는 예외를 처리하도록 orElseThrow를 통해 개선했습니다. - TokenGetResponseDto의 of 메서드를 수정하여, 반환되는 DTO가 새로운 액세스 토큰과 리프레시 토큰을 모두 포함하도록 변경하였습니다. - 사용되지 않는 getUser 메서드를 주석 처리했습니다. 이는 코드의 가독성을 향상시키고 유지보수를 용이하게 하기 위함입니다. --- .../dto/auth/response/TokenGetResponseDto.java | 8 ++++++-- .../terningserver/service/AuthServiceImpl.java | 13 ++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java index ffb118f..8691da8 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java @@ -2,17 +2,21 @@ import lombok.Builder; import lombok.NonNull; +import org.terning.terningserver.domain.Token; import static lombok.AccessLevel.*; @Builder(access = PRIVATE) public record TokenGetResponseDto( + String accessToken, String refreshToken + ) { - public static TokenGetResponseDto of(String refreshToken) { + public static TokenGetResponseDto of(Token token) { return TokenGetResponseDto.builder() - .refreshToken(refreshToken) + .accessToken(token.getAccessToken()) + .refreshToken(token.getRefreshToken()) .build(); } } diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index ee43c53..7ab6aae 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -81,10 +81,12 @@ public void withdraw(long userId) { } @Override + @Transactional public TokenGetResponseDto reissueToken(String refreshToken) { val user = findUser(refreshToken); - val token = Optional.ofNullable(generateRefreshToken(user.getId())) - .orElseThrow(() -> new CustomException(FAILED_TOKEN_REISSUE)); + Token token = getToken(user); + user.updateRefreshToken(token.getRefreshToken()); + return TokenGetResponseDto.of(token); } @@ -95,13 +97,6 @@ private User getUser(String refreshToken, AuthType authType) { return signUp(authType, authId, user); } -// private User getUser(String authAccessToken, AuthType authType) { -//// User user = userRepository.findByAuthTypeAndAuthAccessToken(authType, authAccessToken) -//// .orElseThrow(() -> new CustomException(INVALID_USER)); -// String authId = getAuthId(authType, authAccessToken); -// return signUp(authType, authId); -// } - private String getAuthId(AuthType authType, String authAccessToken) { return switch (authType) { case APPLE -> appleService.getAppleData(authAccessToken); From 7b2f9783456faa480951955d068d9ad9539261d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 06:39:37 +0900 Subject: [PATCH 184/205] =?UTF-8?q?[=F0=9F=94=A8fix/#75]:=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=EB=A7=81=20=EA=B4=80=EB=A0=A8=20API=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FilterController.java | 5 +- .../controller/swagger/FilterSwagger.java | 2 - src/main/resources/application-dev.yml | 49 +++++++++++++++++++ src/main/resources/application.yml | 4 ++ 4 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application.yml diff --git a/src/main/java/org/terning/terningserver/controller/FilterController.java b/src/main/java/org/terning/terningserver/controller/FilterController.java index 02ea027..ba0216f 100644 --- a/src/main/java/org/terning/terningserver/controller/FilterController.java +++ b/src/main/java/org/terning/terningserver/controller/FilterController.java @@ -23,7 +23,6 @@ public class FilterController implements FilterSwagger { @GetMapping("/filters") public ResponseEntity> getUserFilter( - @AuthenticationPrincipal Long userId ) { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_USER_FILTER, @@ -32,9 +31,7 @@ public ResponseEntity> getUserFilter( } @PutMapping("/filters") - public ResponseEntity updateUserFilter( - @AuthenticationPrincipal Long userId, - @RequestBody UserFilterRequestDto requestDto) { + public ResponseEntity updateUserFilter(@RequestBody UserFilterRequestDto requestDto) { filterService.updateUserFilter(requestDto, principalHandler.getUserFromPrincipal()); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_SCRAP)); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java index 6e37c43..bd8a653 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java @@ -15,12 +15,10 @@ public interface FilterSwagger { @Operation(summary = "사용자 필터링 정보 조회 API", description = "사용자가 설정한 필터링 정보를 조회하는 API") ResponseEntity> getUserFilter( - Long userId ); @Operation(summary = "사용자 필터링 정보 수정 API", description = "사용자 필터링을 수정하는 API") ResponseEntity updateUserFilter( - Long userId, @RequestBody UserFilterRequestDto requestDto ); } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..04fc1ad --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,49 @@ +spring: + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://localhost:5432/terning + username: ${USER_ID} + password: ${USER_PW} + + hikari: + maximum-pool-size: 10 + minimum-idle: 10 + connection-timeout: 5000 # 5 seconds + validation-timeout: 2000 # 2 seconds + idle-timeout: 600000 # 10 minutes + max-lifetime: 1800000 # 30 minutes + + # 로그 관련 설정 + data-source-properties: + dataSource.logWriter: # 로그 작성 구현체 지정 + dataSource.logUnclosedConnections: false # 사용하지 않은 커넥션의 로깅 여부 지정 + + # 모니터링 관련 설정 + metrics: + enabled: true # HikariCP 메트릭스 활성화 + export: + reporter: + - prometheus # 사용할 메트릭스 리포터 설정 + prometheus: + enabled: true # Prometheus 메트릭스 리포터 활성화 여부 + step: 60s # 측정 간격 + + jpa: + show-sql: true + hibernate: + ddl-auto: update + properties: + hibernate: + format_sql: true + show_sql: true + +jwt: + secret-key: ${SECRET-KEY} + apple-url: ${APPLE-URL} + kakao-url: ${KAKAO-URL} + access-token-expired: ${ACCESS-EXPIRED} + refresh-token-expired: ${REFRESH-EXPIRED} + +logging: + level: + com.zaxxer.hikari: INFO \ 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 0000000..41ba440 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,4 @@ +spring: + profiles: + active: + - dev \ No newline at end of file From 852cacb7a45ea52f00cda48d43bd74239b84def4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 18 Jul 2024 17:01:13 +0900 Subject: [PATCH 185/205] =?UTF-8?q?[=F0=9F=94=A8=C2=A0fix/#67]:=20?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=9E=A9,=20=ED=95=84=ED=84=B0=EB=A7=81,=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B4=EC=8B=AD=20=EA=B3=B5=EA=B3=A0=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20API=20=EC=9C=A0=EC=A0=80=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 스크랩 추가/취소시 scrapCount 변경되도록 로직 수정 - 스트랩/필터링/인턴십 공고 상세에서 유저 가져오는 로직 수정 --- .../InternshipDetailController.java | 4 +++- .../controller/ScrapController.java | 14 +++++++---- .../controller/SearchController.java | 4 +++- .../swagger/InternshipDetailSwagger.java | 2 ++ .../controller/swagger/ScrapSwagger.java | 5 +++- .../controller/swagger/SearchSwagger.java | 2 ++ .../domain/InternshipAnnouncement.java | 8 +++++++ .../repository/scrap/ScrapRepository.java | 3 +++ .../terningserver/service/FilterService.java | 4 ++-- .../service/FilterServiceImpl.java | 8 +++---- .../service/InternshipDetailService.java | 11 +-------- .../service/InternshipDetailServiceImpl.java | 24 +++++++++++++++---- .../terningserver/service/ScrapService.java | 4 ++-- .../service/ScrapServiceImpl.java | 17 +++++++------ .../terningserver/service/SearchService.java | 2 +- .../service/SearchServiceImpl.java | 4 ++-- 16 files changed, 76 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java index 3dd5455..5634641 100644 --- a/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java +++ b/src/main/java/org/terning/terningserver/controller/InternshipDetailController.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -23,10 +24,11 @@ public class InternshipDetailController implements InternshipDetailSwagger { @GetMapping("/announcements/{internshipAnnouncementId}") public ResponseEntity> getInternshipDetail( + @AuthenticationPrincipal Long userId, @PathVariable Long internshipAnnouncementId) { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_INTERNSHIP_DETAIL, - internshipDetailService.getInternshipDetail(internshipAnnouncementId) + internshipDetailService.getInternshipDetail(internshipAnnouncementId, userId) )); } diff --git a/src/main/java/org/terning/terningserver/controller/ScrapController.java b/src/main/java/org/terning/terningserver/controller/ScrapController.java index 9ef27c9..8660801 100644 --- a/src/main/java/org/terning/terningserver/controller/ScrapController.java +++ b/src/main/java/org/terning/terningserver/controller/ScrapController.java @@ -17,6 +17,7 @@ @RequiredArgsConstructor @RequestMapping("/api/v1") public class ScrapController implements ScrapSwagger { + private final ScrapService scrapService; @PostMapping("/scraps/{internshipAnnouncementId}") @@ -29,14 +30,19 @@ public ResponseEntity createScrap( } @DeleteMapping("/scraps/{scrapId}") - public ResponseEntity deleteScrap(@PathVariable Long scrapId) { - scrapService.deleteScrap(scrapId); + public ResponseEntity deleteScrap( + @AuthenticationPrincipal Long userId, + @PathVariable Long scrapId) { + scrapService.deleteScrap(scrapId, userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_DELETE_SCRAP)); } @PatchMapping("/scraps/{scrapId}") - public ResponseEntity updateScrapColor(@PathVariable Long scrapId, @RequestBody UpdateScrapRequestDto request) { - scrapService.updateScrapColor(scrapId, request); + public ResponseEntity updateScrapColor( + @AuthenticationPrincipal Long userId, + @PathVariable Long scrapId, + @RequestBody UpdateScrapRequestDto request) { + scrapService.updateScrapColor(scrapId, request, userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_SCRAP)); } } diff --git a/src/main/java/org/terning/terningserver/controller/SearchController.java b/src/main/java/org/terning/terningserver/controller/SearchController.java index bfbbca7..93d89b6 100644 --- a/src/main/java/org/terning/terningserver/controller/SearchController.java +++ b/src/main/java/org/terning/terningserver/controller/SearchController.java @@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -41,11 +42,12 @@ public ResponseEntity> getMo @GetMapping("/search") public ResponseEntity> searchInternshipAnnouncement( + @AuthenticationPrincipal Long userId, @RequestParam(value = "keyword", required = false) String keyword, @RequestParam(value = "sortBy", required = false) String sortBy, Pageable pageable) { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_SEARCH_ANNOUNCEMENTS, - searchService.searchInternshipAnnouncement(keyword, sortBy, pageable) + searchService.searchInternshipAnnouncement(keyword, sortBy, pageable, userId) )); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java index 7df1e9e..183ef5a 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/InternshipDetailSwagger.java @@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.PathVariable; import org.terning.terningserver.dto.internship_detail.InternshipDetailResponseDto; import org.terning.terningserver.exception.dto.SuccessResponse; @@ -16,6 +17,7 @@ public interface InternshipDetailSwagger { @Operation(summary = "공고 상세 페이지", description = "인턴 공고의 상세 정보를 불러오는 API") ResponseEntity> getInternshipDetail( + @AuthenticationPrincipal Long userId, @PathVariable("internshipAnnouncementId") Long internshipAnnouncementId ); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java index 180f99e..b2d7bab 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java @@ -20,12 +20,15 @@ ResponseEntity createScrap( @Operation(summary = "스크랩 취소", description = "사용자가 스크랩을 취소하는 API") ResponseEntity deleteScrap( + @AuthenticationPrincipal Long userId, @PathVariable Long internshipAnnouncementId ); @Operation(summary = "스크랩 수정", description = "사용자가 스크랩 색상을 수정하는 API") public ResponseEntity updateScrapColor( - @PathVariable Long scrapId, @RequestBody UpdateScrapRequestDto request + @AuthenticationPrincipal Long userId, + @PathVariable Long scrapId, + @RequestBody UpdateScrapRequestDto request ); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java index 537bb65..b502290 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/SearchSwagger.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.terning.terningserver.dto.search.response.PopularAnnouncementListResponseDto; import org.springframework.web.bind.annotation.RequestParam; import org.terning.terningserver.dto.search.response.SearchResultResponseDto; @@ -25,6 +26,7 @@ ResponseEntity> getMostScrap @Operation(summary = "탐색 > 검색 결과 화면", description = "탐색 화면에서 인턴 공고를 검색하는 API") ResponseEntity> searchInternshipAnnouncement( + @AuthenticationPrincipal Long userId, @RequestParam(value = "keyword", required = false) String keyword, @RequestParam("sortBy") String sortBy, Pageable pageable ); diff --git a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java index 204657e..aa21dba 100644 --- a/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java +++ b/src/main/java/org/terning/terningserver/domain/InternshipAnnouncement.java @@ -68,4 +68,12 @@ public class InternshipAnnouncement extends BaseTimeEntity { @OneToMany(mappedBy = "internshipAnnouncement", cascade = CascadeType.ALL) private List scrapList = new ArrayList<>(); //스크랩 리스트 + + public void updateViewCount(){ + this.viewCount += 1; + } + + public void updateScrapCount(int plusOrMinus){ + this.scrapCount = scrapCount + plusOrMinus; + } } diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java index 945b10d..f2d4ce1 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java @@ -5,6 +5,7 @@ import java.time.LocalDate; import java.util.List; +import java.util.Optional; public interface ScrapRepository extends JpaRepository, ScrapRepositoryCustom { Boolean existsByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); @@ -12,5 +13,7 @@ public interface ScrapRepository extends JpaRepository, ScrapReposi List findByUserIdAndInternshipAnnouncement_Deadline(Long userId, LocalDate deadline); List findByUserIdAndInternshipAnnouncement_DeadlineBetween(Long userId, LocalDate start, LocalDate end); + + Optional findByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); } diff --git a/src/main/java/org/terning/terningserver/service/FilterService.java b/src/main/java/org/terning/terningserver/service/FilterService.java index 6b2b929..f05c4b2 100644 --- a/src/main/java/org/terning/terningserver/service/FilterService.java +++ b/src/main/java/org/terning/terningserver/service/FilterService.java @@ -5,7 +5,7 @@ public interface FilterService { - UserFilterResponseDto getUserFilter(); + UserFilterResponseDto getUserFilter(Long userId); - void updateUserFilter(UserFilterRequestDto responseDto); + void updateUserFilter(UserFilterRequestDto responseDto, Long userId); } diff --git a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java index a5bd831..9c1d025 100644 --- a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java @@ -23,14 +23,14 @@ public class FilterServiceImpl implements FilterService { private final UserRepository userRepository; @Override - public UserFilterResponseDto getUserFilter() { - return UserFilterResponseDto.of(findUser(6L).getFilter()); + public UserFilterResponseDto getUserFilter(Long userId) { + return UserFilterResponseDto.of(findUser(userId).getFilter()); } @Override @Transactional - public void updateUserFilter(UserFilterRequestDto responseDto) { - User user = findUser(6L); + public void updateUserFilter(UserFilterRequestDto responseDto, Long userId) { + User user = findUser(userId); Filter filter = user.getFilter(); filter.updateFilter( diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java index 6382b79..f84b738 100644 --- a/src/main/java/org/terning/terningserver/service/InternshipDetailService.java +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailService.java @@ -1,18 +1,9 @@ package org.terning.terningserver.service; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.terning.terningserver.domain.InternshipAnnouncement; import org.terning.terningserver.dto.internship_detail.InternshipDetailResponseDto; -import org.terning.terningserver.exception.CustomException; -import org.terning.terningserver.exception.enums.ErrorMessage; -import org.terning.terningserver.repository.internship_announcement.InternshipRepository; -import org.terning.terningserver.repository.scrap.ScrapRepository; public interface InternshipDetailService { - InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId); + InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId, Long userId); } diff --git a/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java b/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java index cd862a5..ffd51fe 100644 --- a/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/InternshipDetailServiceImpl.java @@ -4,12 +4,15 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.InternshipAnnouncement; +import org.terning.terningserver.domain.Scrap; import org.terning.terningserver.dto.internship_detail.InternshipDetailResponseDto; import org.terning.terningserver.exception.CustomException; import org.terning.terningserver.exception.enums.ErrorMessage; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import org.terning.terningserver.repository.scrap.ScrapRepository; +import java.util.Optional; + @Service @RequiredArgsConstructor @@ -19,14 +22,25 @@ public class InternshipDetailServiceImpl implements InternshipDetailService { private final ScrapRepository scrapRepository; @Override - public InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId) { + @Transactional + public InternshipDetailResponseDto getInternshipDetail(Long internshipAnnouncementId, Long userId) { InternshipAnnouncement announcement = internshipRepository.findById(internshipAnnouncementId) .orElseThrow(() -> new CustomException(ErrorMessage.NOT_FOUND_INTERN_EXCEPTION)); - return InternshipDetailResponseDto.of( - announcement, announcement.getCompany(), - scrapRepository.existsByInternshipAnnouncementIdAndUserId(announcement.getId(), 1L) - ); + announcement.updateViewCount(); + Optional scrap = scrapRepository.findByInternshipAnnouncementIdAndUserId(announcement.getId(), userId); + + if (scrap.isPresent()) { + return InternshipDetailResponseDto.of( + announcement, announcement.getCompany(), + scrapRepository.findByInternshipAnnouncementIdAndUserId(announcement.getId(), userId).get().getId() + ); + } else { + return InternshipDetailResponseDto.of( + announcement, announcement.getCompany(), + null + ); + } } } diff --git a/src/main/java/org/terning/terningserver/service/ScrapService.java b/src/main/java/org/terning/terningserver/service/ScrapService.java index 7102daf..5d94bb5 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapService.java +++ b/src/main/java/org/terning/terningserver/service/ScrapService.java @@ -15,9 +15,9 @@ public interface ScrapService { void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request, Long userId); - void deleteScrap(Long scrapId); + void deleteScrap(Long scrapId, Long userId); - void updateScrapColor(Long scrapId, UpdateScrapRequestDto request); + void updateScrapColor(Long scrapId, UpdateScrapRequestDto request, Long userId); List getMonthlyScraps(Long userId, int year, int month); diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 12255e2..104776b 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -115,7 +115,9 @@ public List getDailyScraps(Long userId, LocalDate date) { @Override @Transactional public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request, Long userId) { - getInternshipAnnouncement(internshipAnnouncementId); + InternshipAnnouncement announcement = getInternshipAnnouncement(internshipAnnouncementId); + + announcement.updateScrapCount(1); scrapRepository.save(Scrap.create( findUser(userId), @@ -126,23 +128,24 @@ public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto req @Override @Transactional - public void deleteScrap(Long scrapId) { + public void deleteScrap(Long scrapId, Long userId) { Scrap scrap = findScrap(scrapId); - verifyScrapOwner(scrap); + scrap.getInternshipAnnouncement().updateScrapCount(-1); + verifyScrapOwner(scrap, userId); scrapRepository.deleteById(scrapId); } @Override @Transactional - public void updateScrapColor(Long scrapId, UpdateScrapRequestDto request) { + public void updateScrapColor(Long scrapId, UpdateScrapRequestDto request, Long userId) { Scrap scrap = findScrap(scrapId); - verifyScrapOwner(scrap); + verifyScrapOwner(scrap, userId); scrap.updateColor(findColor(request.color())); } //토큰으로 찾은(요청한) User와 스크랩한 User가 일치한지 여부 검증하는 메서드 - private void verifyScrapOwner(Scrap scrap) { - if(!scrap.getUser().equals(findUser(1L))) { + private void verifyScrapOwner(Scrap scrap, Long userId) { + if(!scrap.getUser().equals(findUser(userId))) { throw new CustomException(FORBIDDEN_DELETE_SCRAP); } } diff --git a/src/main/java/org/terning/terningserver/service/SearchService.java b/src/main/java/org/terning/terningserver/service/SearchService.java index d54d8af..c3ce894 100644 --- a/src/main/java/org/terning/terningserver/service/SearchService.java +++ b/src/main/java/org/terning/terningserver/service/SearchService.java @@ -10,6 +10,6 @@ public interface SearchService { PopularAnnouncementListResponseDto getMostScrappedAnnouncements(); - SearchResultResponseDto searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable); + SearchResultResponseDto searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable, Long userId); } \ No newline at end of file diff --git a/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java b/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java index 0e25be8..f527d46 100644 --- a/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java @@ -38,14 +38,14 @@ public PopularAnnouncementListResponseDto getMostScrappedAnnouncements() { } @Override - public SearchResultResponseDto searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable) { + public SearchResultResponseDto searchInternshipAnnouncement(String keyword, String sortBy, Pageable pageable, Long userId) { Page pageAnnouncements = internshipRepository.searchInternshipAnnouncement(keyword, sortBy, pageable); List announcements = pageAnnouncements.getContent(); List searchAnnouncementResponses = new ArrayList<>(); - List scraps = scrapRepository.findAllByInternshipAndUserId(announcements, 1L); + List scraps = scrapRepository.findAllByInternshipAndUserId(announcements, userId); //스크랩 정보를 매핑 (인턴 공고 ID -> 스크랩 ID) Map scrapMap = scraps.stream() From f1e95bb996b91575c83bc1ee29b76028abb7d77f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 18 Jul 2024 17:19:26 +0900 Subject: [PATCH 186/205] =?UTF-8?q?[=E2=99=BB=EF=B8=8F=C2=A0refactor]:=20?= =?UTF-8?q?=EC=95=A0=ED=94=8C=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20=ED=86=A0=ED=81=B0=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 로그인/회원가입시 토큰 userId로 생성하도록 수정 - 토큰 재발급시 dto에 필드면 accessToken에서 refreshToken으로 수정 --- .../terningserver/controller/AuthController.java | 4 +--- .../terningserver/controller/FilterController.java | 4 ++-- .../dto/auth/response/SignUpResponseDto.java | 2 ++ .../dto/auth/response/TokenGetResponseDto.java | 6 +++--- .../InternshipDetailResponseDto.java | 6 +++--- .../terningserver/service/AuthServiceImpl.java | 13 ++----------- .../terningserver/service/SignUpService.java | 8 ++++++-- 7 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/AuthController.java b/src/main/java/org/terning/terningserver/controller/AuthController.java index 1d54404..5584fe4 100644 --- a/src/main/java/org/terning/terningserver/controller/AuthController.java +++ b/src/main/java/org/terning/terningserver/controller/AuthController.java @@ -39,8 +39,6 @@ public ResponseEntity> signIn( @RequestHeader("Authorization") String authAccessToken, @RequestBody SignInRequestDto request ) { -// User user = authService.saveUser(authAccessToken, request); - val signInResponse = authService.signIn(authAccessToken, request); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_IN, signInResponse)); @@ -61,8 +59,8 @@ public ResponseEntity> signUp( @RequestHeader("authId") String authId, @RequestBody SignUpRequestDto request ) { - SignUpResponseDto signUpResponseDto = signUpService.signUp(authId, request.name(), request.profileImage(), request.authType()); + SignUpResponseDto signUpResponseDto = signUpService.signUp(authId, request.name(), request.profileImage(), request.authType()); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_SIGN_UP, signUpResponseDto)); } diff --git a/src/main/java/org/terning/terningserver/controller/FilterController.java b/src/main/java/org/terning/terningserver/controller/FilterController.java index 739fe64..780ab0b 100644 --- a/src/main/java/org/terning/terningserver/controller/FilterController.java +++ b/src/main/java/org/terning/terningserver/controller/FilterController.java @@ -25,7 +25,7 @@ public ResponseEntity> getUserFilter( ) { return ResponseEntity.ok(SuccessResponse.of( SUCCESS_GET_USER_FILTER, - filterService.getUserFilter() + filterService.getUserFilter(userId) )); } @@ -33,7 +33,7 @@ public ResponseEntity> getUserFilter( public ResponseEntity updateUserFilter( @AuthenticationPrincipal Long userId, @RequestBody UserFilterRequestDto requestDto) { - filterService.updateUserFilter(requestDto); + filterService.updateUserFilter(requestDto, userId); return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_SCRAP)); } diff --git a/src/main/java/org/terning/terningserver/dto/auth/response/SignUpResponseDto.java b/src/main/java/org/terning/terningserver/dto/auth/response/SignUpResponseDto.java index 202b0b4..a924318 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/response/SignUpResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/response/SignUpResponseDto.java @@ -12,3 +12,5 @@ public static SignUpResponseDto of(String accessToken, String refreshToken, Long return new SignUpResponseDto(accessToken, refreshToken, userId, authType); } } + + diff --git a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java index e7148df..97a7d08 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java @@ -6,12 +6,12 @@ import static lombok.AccessLevel.*; @Builder(access = PRIVATE) -public record TokenGetResponseDto(@NonNull String accessToken +public record TokenGetResponseDto(@NonNull String refreshToken ) { - public static TokenGetResponseDto of(String accessToken) { + public static TokenGetResponseDto of(String refreshToken) { return TokenGetResponseDto.builder() - .accessToken(accessToken) + .refreshToken(refreshToken) .build(); } } diff --git a/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java b/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java index 41d065b..9a2c017 100644 --- a/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/internship_detail/InternshipDetailResponseDto.java @@ -21,9 +21,9 @@ public record InternshipDetailResponseDto( String jobType, String detail, String url, - boolean isScrapped + Long scrapId ) { - public static InternshipDetailResponseDto of(InternshipAnnouncement announcement, Company company, boolean isScrapped) { + public static InternshipDetailResponseDto of(InternshipAnnouncement announcement, Company company, Long scrapId) { return InternshipDetailResponseDto.builder() .dDay(DateUtil.convert(announcement.getDeadline())) .title(announcement.getTitle()) @@ -39,7 +39,7 @@ public static InternshipDetailResponseDto of(InternshipAnnouncement announcement .jobType(announcement.getJobType()) .detail(announcement.getDetail()) .url(announcement.getUrl()) - .isScrapped(isScrapped) + .scrapId(scrapId) .build(); } } diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index bf38643..4f073ae 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -1,6 +1,5 @@ package org.terning.terningserver.service; -import lombok.Builder; import lombok.extern.slf4j.Slf4j; import lombok.val; import org.springframework.security.core.Authentication; @@ -57,7 +56,6 @@ public SignInResponseDto signIn(String authAccessToken, SignInRequestDto request } } - @Transactional public User saveUser(SignInRequestDto request) { User user = User.builder() @@ -94,13 +92,6 @@ private User getUser(String refreshToken, AuthType authType) { return signUp(authType, authId, user); } -// private User getUser(String authAccessToken, AuthType authType) { -//// User user = userRepository.findByAuthTypeAndAuthAccessToken(authType, authAccessToken) -//// .orElseThrow(() -> new CustomException(INVALID_USER)); -// String authId = getAuthId(authType, authAccessToken); -// return signUp(authType, authId); -// } - private String getAuthId(AuthType authType, String authAccessToken) { return switch (authType) { case APPLE -> appleService.getAppleData(authAccessToken); @@ -113,14 +104,14 @@ private User signUp(AuthType authType, String authId, User user) { return userRepository.save(user); } - private Token getToken(User user) { + public Token getToken(User user) { val token = generateToken(new UserAuthentication(user.getId(), null, null)); user.updateRefreshToken(token.getRefreshToken()); return token; } public Token getTokenByAuthId(String AuthId) { - long id = Long.parseLong(AuthId); + Long id = Long.parseLong(AuthId); val token = generateToken(new UserAuthentication(id, null, null)); return token; } diff --git a/src/main/java/org/terning/terningserver/service/SignUpService.java b/src/main/java/org/terning/terningserver/service/SignUpService.java index ecb77bb..4a832a8 100644 --- a/src/main/java/org/terning/terningserver/service/SignUpService.java +++ b/src/main/java/org/terning/terningserver/service/SignUpService.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.terning.terningserver.domain.Token; import org.terning.terningserver.domain.User; import org.terning.terningserver.domain.enums.AuthType; @@ -19,16 +20,19 @@ public class SignUpService { private final UserRepository userRepository; private final AuthServiceImpl authService; + @Transactional public SignUpResponseDto signUp(String authId, String name, Integer profileImage, AuthType authType) { - Token token = authService.getTokenByAuthId(authId); + User user = userRepository.save(User.builder() .authId(authId) .name(name) .authType(authType) - .refreshToken(token.getRefreshToken()) .profileImage(profileImage) .build()); + Token token = authService.getToken(user); + userRepository.save(user); + return SignUpResponseDto.of(token.getAccessToken(), token.getRefreshToken(), user.getId(), authType); } } From 29c6ee8b0b85493eddf076f1853a8b124b3eeddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 18 Jul 2024 17:36:07 +0900 Subject: [PATCH 187/205] =?UTF-8?q?[=F0=9F=94=A8=C2=A0fix/#67]:=20?= =?UTF-8?q?=ED=86=A0=ED=81=B0=20=EC=9E=AC=EB=B0=9C=EA=B8=89=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 토큰 재발급시 atk, rtk 같이 반환하도록 수정 --- .../dto/auth/response/TokenGetResponseDto.java | 10 +++++++--- .../terning/terningserver/service/AuthServiceImpl.java | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java index 97a7d08..7d07a02 100644 --- a/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/auth/response/TokenGetResponseDto.java @@ -2,16 +2,20 @@ import lombok.Builder; import lombok.NonNull; +import org.terning.terningserver.domain.Token; import static lombok.AccessLevel.*; @Builder(access = PRIVATE) -public record TokenGetResponseDto(@NonNull String refreshToken +public record TokenGetResponseDto( + @NonNull String accessToken, + @NonNull String refreshToken ) { - public static TokenGetResponseDto of(String refreshToken) { + public static TokenGetResponseDto of(Token token) { return TokenGetResponseDto.builder() - .refreshToken(refreshToken) + .accessToken(token.getAccessToken()) + .refreshToken(token.getRefreshToken()) .build(); } } diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index 4f073ae..ecaebe3 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -81,8 +81,8 @@ public void withdraw(long userId) { @Override public TokenGetResponseDto reissueToken(String refreshToken) { val user = findUser(refreshToken); - val token = Optional.ofNullable(generateRefreshToken(user.getId())) - .orElseThrow(() -> new CustomException(FAILED_TOKEN_REISSUE)); + Token token = getToken(user); + user.updateRefreshToken(token.getRefreshToken()); return TokenGetResponseDto.of(token); } private User getUser(String refreshToken, AuthType authType) { From 2e5b9fb7687c62fa9249f9a439f31158d3970366 Mon Sep 17 00:00:00 2001 From: Jayson Date: Thu, 18 Jul 2024 17:40:45 +0900 Subject: [PATCH 188/205] Delete src/main/resources directory --- src/main/resources/application-dev.yml | 49 -------------------------- src/main/resources/application.yml | 4 --- 2 files changed, 53 deletions(-) delete mode 100644 src/main/resources/application-dev.yml delete mode 100644 src/main/resources/application.yml diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml deleted file mode 100644 index 04fc1ad..0000000 --- a/src/main/resources/application-dev.yml +++ /dev/null @@ -1,49 +0,0 @@ -spring: - datasource: - driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://localhost:5432/terning - username: ${USER_ID} - password: ${USER_PW} - - hikari: - maximum-pool-size: 10 - minimum-idle: 10 - connection-timeout: 5000 # 5 seconds - validation-timeout: 2000 # 2 seconds - idle-timeout: 600000 # 10 minutes - max-lifetime: 1800000 # 30 minutes - - # 로그 관련 설정 - data-source-properties: - dataSource.logWriter: # 로그 작성 구현체 지정 - dataSource.logUnclosedConnections: false # 사용하지 않은 커넥션의 로깅 여부 지정 - - # 모니터링 관련 설정 - metrics: - enabled: true # HikariCP 메트릭스 활성화 - export: - reporter: - - prometheus # 사용할 메트릭스 리포터 설정 - prometheus: - enabled: true # Prometheus 메트릭스 리포터 활성화 여부 - step: 60s # 측정 간격 - - jpa: - show-sql: true - hibernate: - ddl-auto: update - properties: - hibernate: - format_sql: true - show_sql: true - -jwt: - secret-key: ${SECRET-KEY} - apple-url: ${APPLE-URL} - kakao-url: ${KAKAO-URL} - access-token-expired: ${ACCESS-EXPIRED} - refresh-token-expired: ${REFRESH-EXPIRED} - -logging: - level: - com.zaxxer.hikari: INFO \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml deleted file mode 100644 index 41ba440..0000000 --- a/src/main/resources/application.yml +++ /dev/null @@ -1,4 +0,0 @@ -spring: - profiles: - active: - - dev \ No newline at end of file From f253090d6e0ce27df61054b521e7c953bc3896bb Mon Sep 17 00:00:00 2001 From: Jayson Date: Thu, 18 Jul 2024 17:41:19 +0900 Subject: [PATCH 189/205] Update .gitignore --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 99bdb2d..4f5aa4a 100644 --- a/.gitignore +++ b/.gitignore @@ -188,8 +188,8 @@ Temporary Items .apdisk # application.yml -#src/main/resources/application.yml -#src/main/resources/application-dev.yml +src/main/resources/application.yml +src/main/resources/application-dev.yml # Q-Class src/main/generated From 273ce60559541658b4cf5ad82528c61849faeb4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 18 Jul 2024 18:16:41 +0900 Subject: [PATCH 190/205] =?UTF-8?q?[=F0=9F=94=A8=C2=A0fix/#67]:=20?= =?UTF-8?q?=ED=86=A0=ED=81=B0=20=EC=9E=AC=EB=B0=9C=EA=B8=89=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 토큰 재발급 시 atk, rtk 모두 반환하도록 수정 --- .../service/AuthServiceImpl.java | 28 ++----------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java index ecaebe3..3d5469e 100644 --- a/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/AuthServiceImpl.java @@ -20,7 +20,6 @@ import java.util.Optional; import static org.terning.terningserver.exception.enums.ErrorMessage.INVALID_USER; -import static org.terning.terningserver.exception.enums.ErrorMessage.FAILED_TOKEN_REISSUE; @Slf4j @Service @@ -39,13 +38,14 @@ public class AuthServiceImpl implements AuthService { @Transactional public SignInResponseDto signIn(String authAccessToken, SignInRequestDto request) { String authId = getAuthId(request.authType(), authAccessToken); - Optional userOptional = userRepository.findByAuthIdAndAuthType(authId, request.authType()); if (userOptional.isPresent()) { User user = userOptional.get(); + Token token = getToken(user); + user.updateRefreshToken(token.getRefreshToken()); return SignInResponseDto.of( - getToken(user), + token, authId, request.authType(), user.getId() @@ -85,12 +85,6 @@ public TokenGetResponseDto reissueToken(String refreshToken) { user.updateRefreshToken(token.getRefreshToken()); return TokenGetResponseDto.of(token); } - private User getUser(String refreshToken, AuthType authType) { - User user = userRepository.findByAuthTypeAndRefreshToken(authType, refreshToken) - .orElseThrow(() -> new CustomException(INVALID_USER)); - String authId = getAuthId(user.getAuthType(), refreshToken); - return signUp(authType, authId, user); - } private String getAuthId(AuthType authType, String authAccessToken) { return switch (authType) { @@ -99,23 +93,12 @@ private String getAuthId(AuthType authType, String authAccessToken) { }; } - private User signUp(AuthType authType, String authId, User user) { - user.updateUser(authType, authId, user); - return userRepository.save(user); - } - public Token getToken(User user) { val token = generateToken(new UserAuthentication(user.getId(), null, null)); user.updateRefreshToken(token.getRefreshToken()); return token; } - public Token getTokenByAuthId(String AuthId) { - Long id = Long.parseLong(AuthId); - val token = generateToken(new UserAuthentication(id, null, null)); - return token; - } - private Token generateToken(Authentication authentication) { return Token.builder() .accessToken(jwtTokenProvider.generateToken(authentication, valueConfig.getAccessTokenExpired())) @@ -136,11 +119,6 @@ private String getTokenFromBearerString(String token) { return token.replaceFirst(ValueConfig.BEARER_HEADER, ValueConfig.BLANK); } - private String generateRefreshToken(long userId) { - val authentication = new UserAuthentication(userId, null, null); - return jwtTokenProvider.generateToken(authentication, valueConfig.getRefreshTokenExpired()); - } - private void deleteUser(User user) { userService.deleteUser(user); } From 954a4940bd826f99bc0787509240adcf8848304a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 18 Jul 2024 18:20:36 +0900 Subject: [PATCH 191/205] =?UTF-8?q?[=E2=9C=85chore/#67]:=20gitignore=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 99bdb2d..4f5aa4a 100644 --- a/.gitignore +++ b/.gitignore @@ -188,8 +188,8 @@ Temporary Items .apdisk # application.yml -#src/main/resources/application.yml -#src/main/resources/application-dev.yml +src/main/resources/application.yml +src/main/resources/application-dev.yml # Q-Class src/main/generated From 6ee7ef0a63fcc6ab13ad6be7bfd155a66de558ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 18 Jul 2024 18:22:00 +0900 Subject: [PATCH 192/205] =?UTF-8?q?[=E2=9C=85chore/#67]:=20gitignore=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4f5aa4a..b4a50a4 100644 --- a/.gitignore +++ b/.gitignore @@ -187,6 +187,7 @@ Network Trash Folder Temporary Items .apdisk + # application.yml src/main/resources/application.yml src/main/resources/application-dev.yml From 2c183be1bd83e65454c44dceacf258c8eaa448dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 18 Jul 2024 18:22:36 +0900 Subject: [PATCH 193/205] =?UTF-8?q?[=E2=9C=85chore/#67]:=20gitignore=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index b4a50a4..4f5aa4a 100644 --- a/.gitignore +++ b/.gitignore @@ -187,7 +187,6 @@ Network Trash Folder Temporary Items .apdisk - # application.yml src/main/resources/application.yml src/main/resources/application-dev.yml From cdec6ac3338a7e491d6701cb7f83500db957914b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 18 Jul 2024 18:24:09 +0900 Subject: [PATCH 194/205] =?UTF-8?q?[=E2=9C=85chore/#67]:=20yml=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/swagger/FilterSwagger.java | 3 ++ .../controller/swagger/ScrapSwagger.java | 1 + .../repository/scrap/ScrapRepository.java | 1 - src/main/resources/application-dev.yml | 49 ------------------- src/main/resources/application.yml | 4 -- 5 files changed, 4 insertions(+), 54 deletions(-) delete mode 100644 src/main/resources/application-dev.yml delete mode 100644 src/main/resources/application.yml diff --git a/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java index bd8a653..746bedc 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/FilterSwagger.java @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.terning.terningserver.dto.filter.request.UserFilterRequestDto; @@ -15,10 +16,12 @@ public interface FilterSwagger { @Operation(summary = "사용자 필터링 정보 조회 API", description = "사용자가 설정한 필터링 정보를 조회하는 API") ResponseEntity> getUserFilter( + @AuthenticationPrincipal Long userId ); @Operation(summary = "사용자 필터링 정보 수정 API", description = "사용자 필터링을 수정하는 API") ResponseEntity updateUserFilter( + @AuthenticationPrincipal Long userId, @RequestBody UserFilterRequestDto requestDto ); } diff --git a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java index f3ed9c5..9159bae 100644 --- a/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java +++ b/src/main/java/org/terning/terningserver/controller/swagger/ScrapSwagger.java @@ -15,6 +15,7 @@ public interface ScrapSwagger { @Operation(summary = "스크랩 추가", description = "사용자가 스크랩을 추가하는 API") ResponseEntity createScrap( + @AuthenticationPrincipal Long userId, @PathVariable Long internshipAnnouncementId, @RequestBody CreateScrapRequestDto request ); diff --git a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java index 3dbe800..8373692 100644 --- a/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java +++ b/src/main/java/org/terning/terningserver/repository/scrap/ScrapRepository.java @@ -16,6 +16,5 @@ public interface ScrapRepository extends JpaRepository, ScrapReposi List findByUserIdAndInternshipAnnouncement_DeadlineBetween(Long userId, LocalDate start, LocalDate end); - Optional findByInternshipAnnouncementIdAndUserId(Long internshipId, Long userId); } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml deleted file mode 100644 index 04fc1ad..0000000 --- a/src/main/resources/application-dev.yml +++ /dev/null @@ -1,49 +0,0 @@ -spring: - datasource: - driver-class-name: org.postgresql.Driver - url: jdbc:postgresql://localhost:5432/terning - username: ${USER_ID} - password: ${USER_PW} - - hikari: - maximum-pool-size: 10 - minimum-idle: 10 - connection-timeout: 5000 # 5 seconds - validation-timeout: 2000 # 2 seconds - idle-timeout: 600000 # 10 minutes - max-lifetime: 1800000 # 30 minutes - - # 로그 관련 설정 - data-source-properties: - dataSource.logWriter: # 로그 작성 구현체 지정 - dataSource.logUnclosedConnections: false # 사용하지 않은 커넥션의 로깅 여부 지정 - - # 모니터링 관련 설정 - metrics: - enabled: true # HikariCP 메트릭스 활성화 - export: - reporter: - - prometheus # 사용할 메트릭스 리포터 설정 - prometheus: - enabled: true # Prometheus 메트릭스 리포터 활성화 여부 - step: 60s # 측정 간격 - - jpa: - show-sql: true - hibernate: - ddl-auto: update - properties: - hibernate: - format_sql: true - show_sql: true - -jwt: - secret-key: ${SECRET-KEY} - apple-url: ${APPLE-URL} - kakao-url: ${KAKAO-URL} - access-token-expired: ${ACCESS-EXPIRED} - refresh-token-expired: ${REFRESH-EXPIRED} - -logging: - level: - com.zaxxer.hikari: INFO \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml deleted file mode 100644 index 41ba440..0000000 --- a/src/main/resources/application.yml +++ /dev/null @@ -1,4 +0,0 @@ -spring: - profiles: - active: - - dev \ No newline at end of file From 5a55e3bb2056aed5b8bb7750143185d847cf5f17 Mon Sep 17 00:00:00 2001 From: Willy Date: Thu, 18 Jul 2024 19:01:46 +0900 Subject: [PATCH 195/205] =?UTF-8?q?[=E2=9C=A8fix/#66]=20=EC=BA=98=EB=A6=B0?= =?UTF-8?q?=EB=8D=94=20=EA=B4=80=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terning/terningserver/service/ScrapServiceImpl.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 104776b..1b17a50 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -52,13 +52,14 @@ public List getMonthlyScraps(Long userId, int year, i LocalDate start = LocalDate.of(year, month, 1); LocalDate end = start.plusMonths(1).minusDays(1); - List scraps = scrapRepository.findByUserIdAndInternshipAnnouncement_DeadlineBetween(userId, start, end); + List scraps = scrapRepository.findScrapsByUserIdAndDeadlineBetweenOrderByDeadline(userId, start, end); //deadline 별로 그룹화 Map> scrapsByDeadline = scraps.stream() .collect(Collectors.groupingBy(s -> s.getInternshipAnnouncement().getDeadline())); return scrapsByDeadline.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) .map(entry -> MonthlyDefaultResponseDto.of( entry.getKey().toString(), entry.getValue().stream() @@ -79,13 +80,14 @@ public List getMonthlyScrapsAsList(Long userId, int year LocalDate start = LocalDate.of(year, month, 1); LocalDate end = start.plusMonths(1).minusDays(1); - List scraps = scrapRepository.findByUserIdAndInternshipAnnouncement_DeadlineBetween(userId, start, end); + List scraps = scrapRepository.findScrapsByUserIdAndDeadlineBetweenOrderByDeadline(userId, start, end); //deadline 별로 그룹화 Map> scrapsByDeadline = scraps.stream() .collect(Collectors.groupingBy(s -> s.getInternshipAnnouncement().getDeadline())); return scrapsByDeadline.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) .map(entry -> MonthlyListResponseDto.of( entry.getKey().toString(), entry.getValue().stream() @@ -107,7 +109,7 @@ public List getMonthlyScrapsAsList(Long userId, int year @Override public List getDailyScraps(Long userId, LocalDate date) { - return scrapRepository.findByUserIdAndInternshipAnnouncement_Deadline(userId, date).stream() + return scrapRepository.findScrapsByUserIdAndDeadlineOrderByDeadline(userId, date).stream() .map(DailyScrapResponseDto::of) .toList(); } From 90fecbb72d2834f53bb0ee52550b0b56051ba5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 22:51:55 +0900 Subject: [PATCH 196/205] =?UTF-8?q?[=F0=9F=94=A8fix/#82]:=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=EB=A7=81=20=EC=9E=AC=EC=84=A4=EC=A0=95=20dto=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UserFilterRequestDto에서 userId 필드 삭제 --- .../terningserver/dto/filter/request/UserFilterRequestDto.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java b/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java index e5bb972..510766e 100644 --- a/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java +++ b/src/main/java/org/terning/terningserver/dto/filter/request/UserFilterRequestDto.java @@ -1,8 +1,6 @@ package org.terning.terningserver.dto.filter.request; public record UserFilterRequestDto( - - Long userId, int grade, int workingPeriod, int startYear, From 998ce42d76159c3b8da84eea252cc3be457b8514 Mon Sep 17 00:00:00 2001 From: Willy Date: Thu, 18 Jul 2024 22:56:54 +0900 Subject: [PATCH 197/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/terning/terningserver/config/WebMvcConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/config/WebMvcConfig.java b/src/main/java/org/terning/terningserver/config/WebMvcConfig.java index 0ed35f2..c3029c1 100644 --- a/src/main/java/org/terning/terningserver/config/WebMvcConfig.java +++ b/src/main/java/org/terning/terningserver/config/WebMvcConfig.java @@ -11,7 +11,7 @@ public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") - .allowedOrigins("http://localhost:8080", "http://localhost:3000", "http://terning-official.p-e.kr","http://localhost:5173") // 허용할 출처 : 특정 도메인만 받을 수 있음 + .allowedOrigins("http://localhost:8080", "http://localhost:3000", "http://terning-official.p-e.kr","https://terning-official.p-e.kr", "http://localhost:5173") // 허용할 출처 : 특정 도메인만 받을 수 있음 .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH") // 허용할 HTTP method .allowCredentials(true); // 쿠키 인증 요청 허용 } From df7dbe9e948b28f8fffc4cc28dd55646086863f4 Mon Sep 17 00:00:00 2001 From: Willy Date: Thu, 18 Jul 2024 23:02:19 +0900 Subject: [PATCH 198/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#63]=20CORS=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/terning/terningserver/config/WebMvcConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/config/WebMvcConfig.java b/src/main/java/org/terning/terningserver/config/WebMvcConfig.java index c3029c1..a1a2df2 100644 --- a/src/main/java/org/terning/terningserver/config/WebMvcConfig.java +++ b/src/main/java/org/terning/terningserver/config/WebMvcConfig.java @@ -11,7 +11,7 @@ public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") - .allowedOrigins("http://localhost:8080", "http://localhost:3000", "http://terning-official.p-e.kr","https://terning-official.p-e.kr", "http://localhost:5173") // 허용할 출처 : 특정 도메인만 받을 수 있음 + .allowedOrigins("http://localhost:8080", "http://localhost:3000", "https://www.terning-official.p-e.kr/") // 허용할 출처 : 특정 도메인만 받을 수 있음 .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH") // 허용할 HTTP method .allowCredentials(true); // 쿠키 인증 요청 허용 } From 5c8246dafb9674646d49f53742d0ee5563ed694b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 19 Jul 2024 00:18:17 +0900 Subject: [PATCH 199/205] =?UTF-8?q?[=F0=9F=94=A8fiX/#82]:=20COLOR=20enum?= =?UTF-8?q?=20=ED=97=A5=EC=82=AC=EA=B0=92=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/terning/terningserver/domain/enums/Color.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/domain/enums/Color.java b/src/main/java/org/terning/terningserver/domain/enums/Color.java index bd70d1b..2545ac4 100644 --- a/src/main/java/org/terning/terningserver/domain/enums/Color.java +++ b/src/main/java/org/terning/terningserver/domain/enums/Color.java @@ -10,7 +10,7 @@ public enum Color { RED(0, "ED4E54"), ORANGE1(1, "EE7647"), - ORANGE2(2, "5397F3"), + ORANGE2(2, "F3A649"), YELLOW(3, "F5E660"), GREEN1(4, "C4E953"), GREEN2(5, "84D558"), From 763b850bac542b48d416ccbd5be27d568f50e2df Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 19 Jul 2024 01:07:57 +0900 Subject: [PATCH 200/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#84]=20=ED=99=88?= =?UTF-8?q?=20>=20=EB=82=98=EC=97=90=EA=B2=8C=20=EB=94=B1=EB=A7=9E?= =?UTF-8?q?=EB=8A=94=20=EC=9D=B8=ED=84=B4=20=EA=B3=B5=EA=B3=A0=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=9D=91=EB=8B=B5=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/dto/user/response/HomeResponseDto.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java b/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java index 71c7fff..e5825b3 100644 --- a/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/user/response/HomeResponseDto.java @@ -10,19 +10,25 @@ public record HomeResponseDto( Long intershipAnnouncementId, String title, String dDay, + String deadline, String workingPeriod, + String startYearMonth, String companyImage, boolean isScrapped ) { public static HomeResponseDto of(final Long scrapId, final InternshipAnnouncement internshipAnnouncement, final boolean isScrapped){ String dDay = DateUtil.convert(internshipAnnouncement.getDeadline()); // dDay 계산 로직 추가 + String startYearMonth = internshipAnnouncement.getStartYear() + "년 " + internshipAnnouncement.getStartMonth() + "월"; + String deadline = DateUtil.convertDeadline(internshipAnnouncement.getDeadline()); return HomeResponseDto.builder() .scrapId(scrapId) .intershipAnnouncementId(internshipAnnouncement.getId()) .title(internshipAnnouncement.getTitle()) .dDay(dDay) + .deadline(deadline) .workingPeriod(internshipAnnouncement.getWorkingPeriod()) + .startYearMonth(startYearMonth) .companyImage(internshipAnnouncement.getCompany().getCompanyImage()) .isScrapped(isScrapped) .build(); From 27bbd6a765c3d53fa4b252c561a3e6c03501fef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 19 Jul 2024 03:46:33 +0900 Subject: [PATCH 201/205] =?UTF-8?q?[=F0=9F=94=A8=20fix/#82]:=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=EB=A7=81=20=EC=9E=AC=EC=84=A4=EC=A0=95=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 필터링 설정 안 한 유저가 재설정시 오류나는 문제 해결 --- .../controller/FilterController.java | 2 +- .../terningserver/service/FilterServiceImpl.java | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/terning/terningserver/controller/FilterController.java b/src/main/java/org/terning/terningserver/controller/FilterController.java index 780ab0b..39ad4c8 100644 --- a/src/main/java/org/terning/terningserver/controller/FilterController.java +++ b/src/main/java/org/terning/terningserver/controller/FilterController.java @@ -34,7 +34,7 @@ public ResponseEntity updateUserFilter( @AuthenticationPrincipal Long userId, @RequestBody UserFilterRequestDto requestDto) { filterService.updateUserFilter(requestDto, userId); - return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_SCRAP)); + return ResponseEntity.ok(SuccessResponse.of(SUCCESS_UPDATE_USER_FILTER)); } } diff --git a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java index 9c1d025..f6a2d96 100644 --- a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java @@ -32,13 +32,15 @@ public UserFilterResponseDto getUserFilter(Long userId) { public void updateUserFilter(UserFilterRequestDto responseDto, Long userId) { User user = findUser(userId); Filter filter = user.getFilter(); - - filter.updateFilter( - Grade.fromKey(responseDto.grade()), - WorkingPeriod.fromKey(responseDto.workingPeriod()), - responseDto.startYear(), - responseDto.startMonth() - ); + System.out.println("filter = " + filter); + if(filter != null){ + filter.updateFilter( + Grade.fromKey(responseDto.grade()), + WorkingPeriod.fromKey(responseDto.workingPeriod()), + responseDto.startYear(), + responseDto.startMonth() + ); + } } private User findUser(Long userId) { From 6679fc366a3fc954dd6909db63daa2b50f123e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 19 Jul 2024 04:09:04 +0900 Subject: [PATCH 202/205] =?UTF-8?q?[=F0=9F=94=A8fix/#82]:=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=EB=A6=B4=20=EC=9E=AC=EC=84=A4=EC=A0=95=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용자 필터링 재설정 로직 수정 --- .../org/terning/terningserver/domain/Filter.java | 2 ++ .../java/org/terning/terningserver/domain/User.java | 1 + .../terningserver/service/FilterServiceImpl.java | 13 ++++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/domain/Filter.java b/src/main/java/org/terning/terningserver/domain/Filter.java index cf123c8..d4e6cbf 100644 --- a/src/main/java/org/terning/terningserver/domain/Filter.java +++ b/src/main/java/org/terning/terningserver/domain/Filter.java @@ -33,10 +33,12 @@ public class Filter { private int startMonth; // 근무 시작 월 + public void updateFilter(Grade grade, WorkingPeriod workingPeriod, int startYear, int startMonth) { this.grade = grade; this.workingPeriod = workingPeriod; this.startYear = startYear; this.startMonth = startMonth; } + } diff --git a/src/main/java/org/terning/terningserver/domain/User.java b/src/main/java/org/terning/terningserver/domain/User.java index 773bc73..6abd6ed 100644 --- a/src/main/java/org/terning/terningserver/domain/User.java +++ b/src/main/java/org/terning/terningserver/domain/User.java @@ -83,4 +83,5 @@ public void updateUser(AuthType authType, String authId, User user) { this.authId = authId; this.refreshToken = user.getRefreshToken(); } + } diff --git a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java index f6a2d96..c1cc974 100644 --- a/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/FilterServiceImpl.java @@ -11,6 +11,7 @@ import org.terning.terningserver.dto.filter.request.UserFilterRequestDto; import org.terning.terningserver.dto.filter.response.UserFilterResponseDto; import org.terning.terningserver.exception.CustomException; +import org.terning.terningserver.repository.filter.FilterRepository; import org.terning.terningserver.repository.user.UserRepository; import static org.terning.terningserver.exception.enums.ErrorMessage.NOT_FOUND_USER_EXCEPTION; @@ -21,6 +22,7 @@ public class FilterServiceImpl implements FilterService { private final UserRepository userRepository; + private final FilterRepository filterRepository; @Override public UserFilterResponseDto getUserFilter(Long userId) { @@ -32,7 +34,6 @@ public UserFilterResponseDto getUserFilter(Long userId) { public void updateUserFilter(UserFilterRequestDto responseDto, Long userId) { User user = findUser(userId); Filter filter = user.getFilter(); - System.out.println("filter = " + filter); if(filter != null){ filter.updateFilter( Grade.fromKey(responseDto.grade()), @@ -40,6 +41,16 @@ public void updateUserFilter(UserFilterRequestDto responseDto, Long userId) { responseDto.startYear(), responseDto.startMonth() ); + } else { + Filter savedFilter = filterRepository.save( + Filter.builder() + .grade(Grade.fromKey(responseDto.grade())) + .workingPeriod(WorkingPeriod.fromKey(responseDto.workingPeriod())) + .startYear(responseDto.startYear()) + .startMonth(responseDto.startMonth()) + .build() + ); + user.assignFilter(savedFilter); } } From 891bf77f9399a1329ae6ea0eab090b3b7a8a0d4d Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 19 Jul 2024 04:38:19 +0900 Subject: [PATCH 203/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#84]=20=ED=99=88?= =?UTF-8?q?=20>=20=EB=82=98=EC=97=90=EA=B2=8C=20=EB=94=B1=EB=A7=9E?= =?UTF-8?q?=EB=8A=94=20=EC=9D=B8=ED=84=B4=20=EA=B3=B5=EA=B3=A0=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=9D=91=EB=8B=B5=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/terning/terningserver/service/HomeServiceImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java index 8e84aad..ee9b1e2 100644 --- a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java @@ -28,6 +28,12 @@ public List getAnnouncements(Long userId, String sortBy, int st User user = userRepository.findById(userId).orElseThrow( () -> new CustomException(ErrorMessage.NOT_FOUND_USER_EXCEPTION) ); + + // 필터링 상태가 없을 경우 NULL 리턴 + if(user.getFilter() == null){ + return null; + } + List announcements = internshipRepository.findFilteredInternships(user, sortBy, startYear, startMonth); return announcements.stream() From 7b53243fcab1b7b4eac12408908994b248eec235 Mon Sep 17 00:00:00 2001 From: Willy Date: Fri, 19 Jul 2024 16:47:20 +0900 Subject: [PATCH 204/205] =?UTF-8?q?[=F0=9F=94=A5!hotfix/#88]=20=ED=83=90?= =?UTF-8?q?=EC=83=89=20>=20=EA=B2=80=EC=83=89=20=EA=B2=B0=EA=B3=BC=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=9D=91=EB=8B=B5=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/SearchResultResponseDto.java | 14 +++++++++++-- .../service/HomeServiceImpl.java | 2 +- .../service/SearchServiceImpl.java | 20 +++++++++++++------ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponseDto.java b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponseDto.java index 34d082d..c291b82 100644 --- a/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponseDto.java +++ b/src/main/java/org/terning/terningserver/dto/search/response/SearchResultResponseDto.java @@ -16,18 +16,28 @@ public record SearchAnnouncementResponse( Long internshipAnnouncementId, Long scrapId, String dDay, + String deadline, String companyImage, String title, - String workingPeriod + String workingPeriod, + String startYearMonth, + String color + ) { - public static SearchAnnouncementResponse from(InternshipAnnouncement announcement, Long scrapId) { + public static SearchAnnouncementResponse from(final InternshipAnnouncement announcement, final Long scrapId, final String color) { + String startYearMonth = announcement.getStartYear() + "년 " + announcement.getStartMonth() + "월"; + String deadline = DateUtil.convertDeadline(announcement.getDeadline()); + return SearchAnnouncementResponse.builder() .internshipAnnouncementId(announcement.getId()) .scrapId(scrapId) .dDay(DateUtil.convert(announcement.getDeadline())) + .deadline(deadline) .companyImage(announcement.getCompany().getCompanyImage()) .title(announcement.getTitle()) .workingPeriod(announcement.getWorkingPeriod()) + .startYearMonth(startYearMonth) + .color(color) // .isScrapped(isScrapped) .build(); } diff --git a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java index ee9b1e2..6fa986c 100644 --- a/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/HomeServiceImpl.java @@ -31,7 +31,7 @@ public List getAnnouncements(Long userId, String sortBy, int st // 필터링 상태가 없을 경우 NULL 리턴 if(user.getFilter() == null){ - return null; + return List.of(); } List announcements = internshipRepository.findFilteredInternships(user, sortBy, startYear, startMonth); diff --git a/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java b/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java index f527d46..5bed3da 100644 --- a/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/SearchServiceImpl.java @@ -47,16 +47,24 @@ public SearchResultResponseDto searchInternshipAnnouncement(String keyword, Stri List scraps = scrapRepository.findAllByInternshipAndUserId(announcements, userId); - //스크랩 정보를 매핑 (인턴 공고 ID -> 스크랩 ID) - Map scrapMap = scraps.stream() + // 스크랩 정보를 매핑 (인턴 공고 ID -> 스크랩) + Map scrapMap = scraps.stream() .collect(Collectors.toMap( scrap -> scrap.getInternshipAnnouncement().getId(), - Scrap::getId + scrap -> scrap )); + searchAnnouncementResponses = announcements.stream() + .map(a -> { + Scrap scrap = scrapMap.get(a.getId()); + return SearchResultResponseDto.SearchAnnouncementResponse.from(a, scrap != null ? scrap.getId() : null, scrap != null ? scrap.getColor().getColorValue() : null); + }) + .toList(); + return new SearchResultResponseDto( - pageAnnouncements.getTotalPages(), pageAnnouncements.hasNext(), announcements.stream() - .map(a -> SearchResultResponseDto.SearchAnnouncementResponse.from(a, scrapMap.get(a.getId()))) - .toList()); + pageAnnouncements.getTotalPages(), + pageAnnouncements.hasNext(), + searchAnnouncementResponses + ); } } \ No newline at end of file From c26a95d681836906ae8105a02cfee26ebf6c0dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=9C=A4?= <63058347+JungYoonShin@users.noreply.github.com> Date: Fri, 19 Jul 2024 23:33:40 +0900 Subject: [PATCH 205/205] =?UTF-8?q?[=E2=9C=A8=20feat/#91]:=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=EA=B0=80=20=ED=95=B4=EB=8B=B9=20=EA=B3=B5?= =?UTF-8?q?=EA=B3=A0=EB=A5=BC=20=EC=9D=B4=EB=AF=B8=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=9E=A9=ED=96=88=EC=9D=84=20=EA=B2=BD=EC=9A=B0=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../terningserver/exception/enums/ErrorMessage.java | 3 +++ .../terning/terningserver/service/ScrapServiceImpl.java | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java index d659e7b..f52b514 100644 --- a/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java +++ b/src/main/java/org/terning/terningserver/exception/enums/ErrorMessage.java @@ -22,6 +22,9 @@ public enum ErrorMessage { // 사용자 필터링 정보 생성 FAILED_SIGN_UP_FILTER(404, "회원가입 필터링 정보 생성에 실패하였습니다"), + //스크랩 + EXISTS_SCRAP_ALREADY(400, "이미 스크랩했습니다."), + // 로그 아웃 FAILED_SIGN_OUT(404, "로그아웃에 실패하였습니다"), FAILED_REFRESH_TOKEN_RESET(400, "리프레쉬 토큰 초기화에 실패하였습니다"), diff --git a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java index 1b17a50..cf86ba5 100644 --- a/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java +++ b/src/main/java/org/terning/terningserver/service/ScrapServiceImpl.java @@ -14,7 +14,6 @@ import org.terning.terningserver.dto.calendar.response.MonthlyListResponseDto; import org.terning.terningserver.dto.user.response.TodayScrapResponseDto; import org.terning.terningserver.exception.CustomException; -import org.terning.terningserver.jwt.PrincipalHandler; import org.terning.terningserver.repository.internship_announcement.InternshipRepository; import org.terning.terningserver.repository.scrap.ScrapRepository; import org.terning.terningserver.repository.user.UserRepository; @@ -117,6 +116,12 @@ public List getDailyScraps(Long userId, LocalDate date) { @Override @Transactional public void createScrap(Long internshipAnnouncementId, CreateScrapRequestDto request, Long userId) { + + //이미 스크랩 했을 경우 예외처리 + if(scrapRepository.existsByInternshipAnnouncementIdAndUserId(internshipAnnouncementId, userId)) { + throw new CustomException(EXISTS_SCRAP_ALREADY); + } + InternshipAnnouncement announcement = getInternshipAnnouncement(internshipAnnouncementId); announcement.updateScrapCount(1);